Merge "Add recommendation setting and remove app settings" into sc-dev
diff --git a/Android.bp b/Android.bp
index 4a22369..6c5acd2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -273,6 +273,14 @@
installable: false,
}
+// NOTE: This filegroup is exposed for vendor libraries to depend on and is referenced in
+// documentation. Do not remove without consulting the treble/hidl teams.
+filegroup {
+ name: "framework-jarjar-rules",
+ srcs: ["framework-jarjar-rules.txt"],
+ visibility: ["//visibility:public"],
+}
+
java_defaults {
name: "framework-minus-apex-defaults",
defaults: ["framework-aidl-export-defaults"],
@@ -284,16 +292,17 @@
generate_get_transaction_name: true,
local_include_dirs: [
"media/aidl",
- // TODO: move to include_dirs when migrated to packages/modules
- "packages/Connectivity/framework/aidl-export",
],
- include_dirs: ["frameworks/av/aidl"],
+ include_dirs: [
+ "frameworks/av/aidl",
+ "packages/modules/Connectivity/framework/aidl-export",
+ ],
},
dxflags: [
"--core-library",
"--multi-dex",
],
- jarjar_rules: "framework-jarjar-rules.txt",
+ jarjar_rules: ":framework-jarjar-rules",
javac_shard_size: 150,
plugins: [
"view-inspector-annotation-processor",
@@ -524,12 +533,12 @@
local_include_dirs: [
"apex/media/aidl/stable",
"media/aidl",
- // TODO: move to include-dirs for packages/modules/Connectivity when this moves out of
- // frameworks/base
- "packages/Connectivity/framework/aidl-export",
"telephony/java",
],
- include_dirs: ["frameworks/av/aidl"],
+ include_dirs: [
+ "frameworks/av/aidl",
+ "packages/modules/Connectivity/framework/aidl-export",
+ ],
},
// These are libs from framework-internal-utils that are required (i.e. being referenced)
// from framework-non-updatable-sources. Add more here when there's a need.
diff --git a/StubLibraries.bp b/StubLibraries.bp
index ed24d43..b6c45ed 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -255,7 +255,7 @@
modules_system_stubs = [
"android.net.ipsec.ike.stubs.system",
- "art.module.public.api.stubs", // Only has public stubs
+ "art.module.public.api.stubs.system",
"conscrypt.module.public.api.stubs", // Only has public stubs
"framework-appsearch.stubs.system",
"framework-connectivity.stubs.system",
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index b3c33b6..144536e 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -1229,7 +1229,11 @@
* </ul>
* Note that the system may choose to delay jobs with large network
* usage estimates when the device has a poor network connection, in
- * order to save battery.
+ * order to save battery and possible network costs.
+ * Starting from Android version {@link Build.VERSION_CODES#S}, JobScheduler may attempt
+ * to run large jobs when the device is charging and on an unmetered network, even if the
+ * network is slow. This gives large jobs an opportunity to make forward progress, even if
+ * they risk timing out.
* <p>
* The values provided here only reflect the traffic that will be
* performed by the base job; if you're using {@link JobWorkItem} then
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 60f5769..cef065d 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -547,7 +547,7 @@
private int[] mPowerSaveWhitelistUserAppIdArray = new int[0];
/**
- * List of end times for UIDs that are temporarily marked as being allowed to access
+ * List of end times for app-IDs that are temporarily marked as being allowed to access
* the network and acquire wakelocks. Times are in milliseconds.
*/
private final SparseArray<Pair<MutableLong, String>> mTempWhitelistAppIdEndTimes
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 5365218..1169391 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -121,7 +121,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
-import com.android.internal.os.BinderDeathDispatcher;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.LocalLog;
@@ -184,8 +183,7 @@
static final boolean DEBUG_BG_LIMIT = localLOGV || false;
static final boolean DEBUG_STANDBY = localLOGV || false;
static final boolean RECORD_ALARMS_IN_HISTORY = true;
- // TODO(b/178484639) : Turn off once alarms and reminders work is complete.
- static final boolean RECORD_DEVICE_IDLE_ALARMS = true;
+ static final boolean RECORD_DEVICE_IDLE_ALARMS = false;
static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
static final int TICK_HISTORY_DEPTH = 10;
@@ -206,8 +204,6 @@
.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
- private static final BinderDeathDispatcher<IAlarmListener> sListenerDeathDispatcher =
- new BinderDeathDispatcher<>();
final LocalLog mLog = new LocalLog(TAG);
AppOpsManager mAppOps;
@@ -1837,8 +1833,9 @@
}
if (directReceiver != null) {
- if (sListenerDeathDispatcher.linkToDeath(directReceiver, mListenerDeathRecipient)
- <= 0) {
+ try {
+ directReceiver.asBinder().linkToDeath(mListenerDeathRecipient, 0);
+ } catch (RemoteException e) {
Slog.w(TAG, "Dropping unreachable alarm listener " + listenerTag);
return;
}
@@ -2851,12 +2848,6 @@
pw.println();
}
- pw.println("Listener death dispatcher state:");
- pw.increaseIndent();
- sListenerDeathDispatcher.dump(pw);
- pw.println();
- pw.decreaseIndent();
-
if (mLog.dump(pw, "Recent problems:")) {
pw.println();
}
@@ -3448,6 +3439,9 @@
for (final Alarm removed : removedAlarms) {
decrementAlarmCount(removed.uid, 1);
+ if (removed.listener != null) {
+ removed.listener.asBinder().unlinkToDeath(mListenerDeathRecipient, 0);
+ }
if (!RemovedAlarm.isLoggable(reason)) {
continue;
}
@@ -4701,6 +4695,8 @@
// Direct listener callback alarm
mListenerCount++;
+ alarm.listener.asBinder().unlinkToDeath(mListenerDeathRecipient, 0);
+
if (RECORD_ALARMS_IN_HISTORY) {
if (alarm.listener == mTimeTickTrigger) {
mTickHistory[mNextTickHistory++] = nowELAPSED;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index 7b947fd..e8065aa 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -25,12 +25,18 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.job.JobInfo;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkPolicyManager;
import android.net.NetworkRequest;
+import android.os.BatteryManager;
+import android.os.BatteryManagerInternal;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -101,6 +107,8 @@
private final ConnectivityManager mConnManager;
private final NetworkPolicyManagerInternal mNetPolicyManagerInternal;
+ private final ChargingTracker mChargingTracker;
+
/** List of tracked jobs keyed by source UID. */
@GuardedBy("mLock")
private final SparseArray<ArraySet<JobStatus>> mTrackedJobs = new SparseArray<>();
@@ -229,6 +237,9 @@
// network changes against the active network for each UID with jobs.
final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
mConnManager.registerNetworkCallback(request, mNetworkCallback);
+
+ mChargingTracker = new ChargingTracker();
+ mChargingTracker.startTracking();
}
@GuardedBy("mLock")
@@ -538,6 +549,14 @@
*/
private boolean isInsane(JobStatus jobStatus, Network network,
NetworkCapabilities capabilities, Constants constants) {
+ if (capabilities.hasCapability(NET_CAPABILITY_NOT_METERED)
+ && mChargingTracker.isCharging()) {
+ // We're charging and on an unmetered network. We don't have to be as conservative about
+ // making sure the job will run within its max execution time. Let's just hope the app
+ // supports interruptible work.
+ return false;
+ }
+
// Use the maximum possible time since it gives us an upper bound, even though the job
// could end up stopping earlier.
final long maxJobExecutionTimeMs = mService.getMaxJobExecutionTimeMs(jobStatus);
@@ -922,7 +941,7 @@
* {@link Network}, or {@code null} to update all tracked jobs.
*/
@GuardedBy("mLock")
- private void updateTrackedJobsLocked(int filterUid, Network filterNetwork) {
+ private void updateTrackedJobsLocked(int filterUid, @Nullable Network filterNetwork) {
boolean changed = false;
if (filterUid == -1) {
for (int i = mTrackedJobs.size() - 1; i >= 0; i--) {
@@ -937,7 +956,8 @@
}
@GuardedBy("mLock")
- private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs, Network filterNetwork) {
+ private boolean updateTrackedJobsLocked(ArraySet<JobStatus> jobs,
+ @Nullable Network filterNetwork) {
if (jobs == null || jobs.size() == 0) {
return false;
}
@@ -993,6 +1013,51 @@
}
}
+ private final class ChargingTracker extends BroadcastReceiver {
+ /**
+ * Track whether we're "charging", where charging means that we're ready to commit to
+ * doing work.
+ */
+ private boolean mCharging;
+
+ ChargingTracker() {}
+
+ public void startTracking() {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BatteryManager.ACTION_CHARGING);
+ filter.addAction(BatteryManager.ACTION_DISCHARGING);
+ mContext.registerReceiver(this, filter);
+
+ // Initialise tracker state.
+ final BatteryManagerInternal batteryManagerInternal =
+ LocalServices.getService(BatteryManagerInternal.class);
+ mCharging = batteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
+ }
+
+ public boolean isCharging() {
+ return mCharging;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (mLock) {
+ final String action = intent.getAction();
+ if (BatteryManager.ACTION_CHARGING.equals(action)) {
+ if (mCharging) {
+ return;
+ }
+ mCharging = true;
+ } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) {
+ if (!mCharging) {
+ return;
+ }
+ mCharging = false;
+ }
+ updateTrackedJobsLocked(-1, null);
+ }
+ }
+ }
+
private final NetworkCallback mNetworkCallback = new NetworkCallback() {
@Override
public void onAvailable(Network network) {
diff --git a/apex/media/service/Android.bp b/apex/media/service/Android.bp
index 9b3399e..271fc53 100644
--- a/apex/media/service/Android.bp
+++ b/apex/media/service/Android.bp
@@ -23,10 +23,10 @@
filegroup {
name: "service-media-s-sources",
srcs: [
- "java/**/*.java",
+ "java/**/*.java",
],
path: "java",
- visibility: ["//frameworks/base/services"], // TODO(b/177640454): Should be private.
+ visibility: ["//visibility:private"],
}
java_sdk_library {
diff --git a/api/Android.bp b/api/Android.bp
index b85dc46..db1f64c 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -161,6 +161,7 @@
genrule {
name: "frameworks-base-api-system-current.txt",
srcs: [
+ ":art.module.public.api{.system.api.txt}",
":android.net.ipsec.ike{.system.api.txt}",
":framework-appsearch{.system.api.txt}",
":framework-connectivity{.system.api.txt}",
@@ -215,6 +216,7 @@
genrule {
name: "frameworks-base-api-system-removed.txt",
srcs: [
+ ":art.module.public.api{.system.removed-api.txt}",
":android.net.ipsec.ike{.system.removed-api.txt}",
":framework-appsearch{.system.removed-api.txt}",
":framework-connectivity{.system.removed-api.txt}",
@@ -251,6 +253,7 @@
genrule {
name: "frameworks-base-api-module-lib-current.txt",
srcs: [
+ ":art.module.public.api{.module-lib.api.txt}",
":android.net.ipsec.ike{.module-lib.api.txt}",
":framework-appsearch{.module-lib.api.txt}",
":framework-connectivity{.module-lib.api.txt}",
@@ -307,6 +310,7 @@
genrule {
name: "frameworks-base-api-module-lib-removed.txt",
srcs: [
+ ":art.module.public.api{.module-lib.removed-api.txt}",
":android.net.ipsec.ike{.module-lib.removed-api.txt}",
":framework-appsearch{.module-lib.removed-api.txt}",
":framework-connectivity{.module-lib.removed-api.txt}",
diff --git a/boot/hiddenapi/hiddenapi-max-target-o.txt b/boot/hiddenapi/hiddenapi-max-target-o.txt
index 45ebbb1..3cc28d9 100644
--- a/boot/hiddenapi/hiddenapi-max-target-o.txt
+++ b/boot/hiddenapi/hiddenapi-max-target-o.txt
@@ -93863,283 +93863,6 @@
Lcom/android/internal/widget/VerifyCredentialResponse;->setTimeout(I)V
Lcom/android/internal/widget/VerifyCredentialResponse;->stripPayload()Lcom/android/internal/widget/VerifyCredentialResponse;
Lcom/android/internal/widget/VerifyCredentialResponse;->TAG:Ljava/lang/String;
-Lcom/android/org/conscrypt/AbstractConscryptSocket;-><init>()V
-Lcom/android/org/conscrypt/AbstractConscryptSocket;-><init>(Ljava/lang/String;I)V
-Lcom/android/org/conscrypt/AbstractConscryptSocket;-><init>(Ljava/lang/String;ILjava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/AbstractConscryptSocket;-><init>(Ljava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/AbstractConscryptSocket;-><init>(Ljava/net/InetAddress;ILjava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/AbstractConscryptSocket;->getFileDescriptor$()Ljava/io/FileDescriptor;
-Lcom/android/org/conscrypt/AbstractConscryptSocket;->getTlsUnique()[B
-Lcom/android/org/conscrypt/AbstractConscryptSocket;->peerInfoProvider()Lcom/android/org/conscrypt/PeerInfoProvider;
-Lcom/android/org/conscrypt/AbstractConscryptSocket;->setApplicationProtocolSelector(Lcom/android/org/conscrypt/ApplicationProtocolSelector;)V
-Lcom/android/org/conscrypt/ApplicationProtocolSelector;-><init>()V
-Lcom/android/org/conscrypt/ApplicationProtocolSelector;->selectApplicationProtocol(Ljavax/net/ssl/SSLEngine;Ljava/util/List;)Ljava/lang/String;
-Lcom/android/org/conscrypt/ApplicationProtocolSelector;->selectApplicationProtocol(Ljavax/net/ssl/SSLSocket;Ljava/util/List;)Ljava/lang/String;
-Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;-><init>(Ljavax/net/ssl/SSLEngine;Lcom/android/org/conscrypt/ApplicationProtocolSelector;)V
-Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;-><init>(Ljavax/net/ssl/SSLSocket;Lcom/android/org/conscrypt/ApplicationProtocolSelector;)V
-Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;->engine:Ljavax/net/ssl/SSLEngine;
-Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;->NO_PROTOCOL_SELECTED:I
-Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;->selectApplicationProtocol([B)I
-Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;->selector:Lcom/android/org/conscrypt/ApplicationProtocolSelector;
-Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;->socket:Ljavax/net/ssl/SSLSocket;
-Lcom/android/org/conscrypt/CertBlacklist;-><init>(Ljava/util/Set;Ljava/util/Set;)V
-Lcom/android/org/conscrypt/CertBlacklist;->closeQuietly(Ljava/io/Closeable;)V
-Lcom/android/org/conscrypt/CertBlacklist;->getDefault()Lcom/android/org/conscrypt/CertBlacklist;
-Lcom/android/org/conscrypt/CertBlacklist;->HEX_TABLE:[B
-Lcom/android/org/conscrypt/CertBlacklist;->isHex(Ljava/lang/String;)Z
-Lcom/android/org/conscrypt/CertBlacklist;->isPubkeyHash(Ljava/lang/String;)Z
-Lcom/android/org/conscrypt/CertBlacklist;->isPublicKeyBlackListed(Ljava/security/PublicKey;)Z
-Lcom/android/org/conscrypt/CertBlacklist;->isSerialNumberBlackListed(Ljava/math/BigInteger;)Z
-Lcom/android/org/conscrypt/CertBlacklist;->logger:Ljava/util/logging/Logger;
-Lcom/android/org/conscrypt/CertBlacklist;->pubkeyBlacklist:Ljava/util/Set;
-Lcom/android/org/conscrypt/CertBlacklist;->readBlacklist(Ljava/lang/String;)Ljava/lang/String;
-Lcom/android/org/conscrypt/CertBlacklist;->readFileAsBytes(Ljava/lang/String;)Ljava/io/ByteArrayOutputStream;
-Lcom/android/org/conscrypt/CertBlacklist;->readFileAsString(Ljava/lang/String;)Ljava/lang/String;
-Lcom/android/org/conscrypt/CertBlacklist;->readPublicKeyBlackList(Ljava/lang/String;)Ljava/util/Set;
-Lcom/android/org/conscrypt/CertBlacklist;->readSerialBlackList(Ljava/lang/String;)Ljava/util/Set;
-Lcom/android/org/conscrypt/CertBlacklist;->serialBlacklist:Ljava/util/Set;
-Lcom/android/org/conscrypt/CertBlacklist;->toHex([B)[B
-Lcom/android/org/conscrypt/CertificatePriorityComparator;-><init>()V
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->ALGORITHM_OID_PRIORITY_MAP:Ljava/util/Map;
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->compare(Ljava/lang/Object;Ljava/lang/Object;)I
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->compare(Ljava/security/cert/X509Certificate;Ljava/security/cert/X509Certificate;)I
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->compareKeyAlgorithm(Ljava/security/PublicKey;Ljava/security/PublicKey;)I
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->compareKeySize(Ljava/security/PublicKey;Ljava/security/PublicKey;)I
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->compareSignatureAlgorithm(Ljava/security/cert/X509Certificate;Ljava/security/cert/X509Certificate;)I
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->compareStrength(Ljava/security/cert/X509Certificate;Ljava/security/cert/X509Certificate;)I
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->getKeySize(Ljava/security/PublicKey;)I
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_MD5:Ljava/lang/Integer;
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_SHA1:Ljava/lang/Integer;
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_SHA224:Ljava/lang/Integer;
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_SHA256:Ljava/lang/Integer;
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_SHA384:Ljava/lang/Integer;
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_SHA512:Ljava/lang/Integer;
-Lcom/android/org/conscrypt/CertificatePriorityComparator;->PRIORITY_UNKNOWN:Ljava/lang/Integer;
-Lcom/android/org/conscrypt/CertPinManager;->checkChainPinning(Ljava/lang/String;Ljava/util/List;)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>()V
-Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>(Ljava/lang/String;I)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>(Ljava/lang/String;ILjava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>(Ljava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>(Ljava/net/InetAddress;ILjava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;-><init>(Ljava/net/Socket;Ljava/lang/String;IZ)V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->autoClose:Z
-Lcom/android/org/conscrypt/ConscryptSocketBase;->checkOpen()V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->getActiveSession()Ljavax/net/ssl/SSLSession;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->getFileDescriptor$()Ljava/io/FileDescriptor;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->isDelegating()Z
-Lcom/android/org/conscrypt/ConscryptSocketBase;->listeners:Ljava/util/List;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->notifyHandshakeCompletedListeners()V
-Lcom/android/org/conscrypt/ConscryptSocketBase;->peerHostname:Ljava/lang/String;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->peerInfoProvider()Lcom/android/org/conscrypt/PeerInfoProvider;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->peerInfoProvider:Lcom/android/org/conscrypt/PeerInfoProvider;
-Lcom/android/org/conscrypt/ConscryptSocketBase;->peerPort:I
-Lcom/android/org/conscrypt/ConscryptSocketBase;->readTimeoutMilliseconds:I
-Lcom/android/org/conscrypt/ConscryptSocketBase;->setApplicationProtocolSelector(Lcom/android/org/conscrypt/ApplicationProtocolSelectorAdapter;)V
-Lcom/android/org/conscrypt/NativeRef$EC_GROUP;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef$EC_GROUP;->doFree(J)V
-Lcom/android/org/conscrypt/NativeRef$EC_POINT;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef$EC_POINT;->doFree(J)V
-Lcom/android/org/conscrypt/NativeRef$EVP_CIPHER_CTX;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef$EVP_CIPHER_CTX;->doFree(J)V
-Lcom/android/org/conscrypt/NativeRef$EVP_MD_CTX;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef$EVP_MD_CTX;->doFree(J)V
-Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;->doFree(J)V
-Lcom/android/org/conscrypt/NativeRef$EVP_PKEY_CTX;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef$EVP_PKEY_CTX;->doFree(J)V
-Lcom/android/org/conscrypt/NativeRef$HMAC_CTX;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef$HMAC_CTX;->doFree(J)V
-Lcom/android/org/conscrypt/NativeRef$SSL_SESSION;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef$SSL_SESSION;->doFree(J)V
-Lcom/android/org/conscrypt/NativeRef;-><init>(J)V
-Lcom/android/org/conscrypt/NativeRef;->context:J
-Lcom/android/org/conscrypt/NativeRef;->doFree(J)V
-Lcom/android/org/conscrypt/OpenSSLKey;-><init>(JZ)V
-Lcom/android/org/conscrypt/OpenSSLKey;->ctx:Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;
-Lcom/android/org/conscrypt/OpenSSLKey;->fromECPrivateKeyForTLSStackOnly(Ljava/security/PrivateKey;Ljava/security/spec/ECParameterSpec;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->fromKeyMaterial(Ljava/security/PrivateKey;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->fromPrivateKeyForTLSStackOnly(Ljava/security/PrivateKey;Ljava/security/PublicKey;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->fromPrivateKeyPemInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->fromPublicKey(Ljava/security/PublicKey;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->fromPublicKeyPemInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->getOpenSSLKey(Ljava/security/PrivateKey;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->getPrivateKey()Ljava/security/PrivateKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->getPrivateKey(Ljava/security/spec/PKCS8EncodedKeySpec;I)Ljava/security/PrivateKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->getPublicKey(Ljava/security/spec/X509EncodedKeySpec;I)Ljava/security/PublicKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->isWrapped()Z
-Lcom/android/org/conscrypt/OpenSSLKey;->wrapJCAPrivateKeyForTLSStackOnly(Ljava/security/PrivateKey;Ljava/security/PublicKey;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLKey;->wrapped:Z
-Lcom/android/org/conscrypt/OpenSSLKey;->wrapPrivateKey(Ljava/security/PrivateKey;)Lcom/android/org/conscrypt/OpenSSLKey;
-Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>()V
-Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>(Ljava/lang/String;I)V
-Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>(Ljava/lang/String;ILjava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>(Ljava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>(Ljava/net/InetAddress;ILjava/net/InetAddress;I)V
-Lcom/android/org/conscrypt/OpenSSLSocketImpl;-><init>(Ljava/net/Socket;Ljava/lang/String;IZ)V
-Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getFileDescriptor$()Ljava/io/FileDescriptor;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;-><init>(J)V
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;-><init>(JLjava/util/Date;Ljava/util/Date;)V
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->alternativeNameArrayToList([[Ljava/lang/Object;)Ljava/util/Collection;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromCertificate(Ljava/security/cert/Certificate;)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromPkcs7DerInputStream(Ljava/io/InputStream;)Ljava/util/List;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromPkcs7PemInputStream(Ljava/io/InputStream;)Ljava/util/List;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromX509Der([B)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->fromX509DerInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->getContext()J
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->mHashCode:Ljava/lang/Integer;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->notAfter:Ljava/util/Date;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->notBefore:Ljava/util/Date;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->toDate(J)Ljava/util/Date;
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->verifyInternal(Ljava/security/PublicKey;Ljava/lang/String;)V
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->verifyOpenSSL(Lcom/android/org/conscrypt/OpenSSLKey;)V
-Lcom/android/org/conscrypt/OpenSSLX509Certificate;->withDeletedExtension(Ljava/lang/String;)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;-><init>()V
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->fromPkcs7DerInputStream(Ljava/io/InputStream;)Ljava/util/List;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->fromPkcs7PemInputStream(Ljava/io/InputStream;)Ljava/util/List;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->fromX509DerInputStream(Ljava/io/InputStream;)Ljava/lang/Object;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->fromX509PemInputStream(Ljava/io/InputStream;)Ljava/lang/Object;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->generateItem(Ljava/io/InputStream;)Ljava/lang/Object;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;->generateItems(Ljava/io/InputStream;)Ljava/util/Collection;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$ParsingException;-><init>(Ljava/lang/Exception;)V
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$ParsingException;-><init>(Ljava/lang/String;)V
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$ParsingException;-><init>(Ljava/lang/String;Ljava/lang/Exception;)V
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;-><init>()V
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;->certificateParser:Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;->crlParser:Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory$Parser;
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;->PKCS7_MARKER:[B
-Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;->PUSHBACK_SIZE:I
-Lcom/android/org/conscrypt/OpenSSLX509CRL;-><init>(J)V
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->fromPkcs7DerInputStream(Ljava/io/InputStream;)Ljava/util/List;
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->fromPkcs7PemInputStream(Ljava/io/InputStream;)Ljava/util/List;
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->fromX509DerInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLX509CRL;
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->fromX509PemInputStream(Ljava/io/InputStream;)Lcom/android/org/conscrypt/OpenSSLX509CRL;
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->mContext:J
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->nextUpdate:Ljava/util/Date;
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->thisUpdate:Ljava/util/Date;
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->toDate(J)Ljava/util/Date;
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->verifyInternal(Ljava/security/PublicKey;Ljava/lang/String;)V
-Lcom/android/org/conscrypt/OpenSSLX509CRL;->verifyOpenSSL(Lcom/android/org/conscrypt/OpenSSLKey;)V
-Lcom/android/org/conscrypt/PeerInfoProvider;-><init>()V
-Lcom/android/org/conscrypt/PeerInfoProvider;->forHostAndPort(Ljava/lang/String;I)Lcom/android/org/conscrypt/PeerInfoProvider;
-Lcom/android/org/conscrypt/PeerInfoProvider;->getHostname()Ljava/lang/String;
-Lcom/android/org/conscrypt/PeerInfoProvider;->getHostnameOrIP()Ljava/lang/String;
-Lcom/android/org/conscrypt/PeerInfoProvider;->getPort()I
-Lcom/android/org/conscrypt/PeerInfoProvider;->nullProvider()Lcom/android/org/conscrypt/PeerInfoProvider;
-Lcom/android/org/conscrypt/PeerInfoProvider;->NULL_PEER_INFO_PROVIDER:Lcom/android/org/conscrypt/PeerInfoProvider;
-Lcom/android/org/conscrypt/SSLClientSessionCache;->getSessionData(Ljava/lang/String;I)[B
-Lcom/android/org/conscrypt/SSLClientSessionCache;->putSessionData(Ljavax/net/ssl/SSLSession;[B)V
-Lcom/android/org/conscrypt/TrustedCertificateIndex;-><init>()V
-Lcom/android/org/conscrypt/TrustedCertificateIndex;-><init>(Ljava/util/Set;)V
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->findAllByIssuerAndSignature(Ljava/security/cert/X509Certificate;)Ljava/util/Set;
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->findByIssuerAndSignature(Ljava/security/cert/X509Certificate;)Ljava/security/cert/TrustAnchor;
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->findBySubjectAndPublicKey(Ljava/security/cert/X509Certificate;)Ljava/security/cert/TrustAnchor;
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->findBySubjectAndPublicKey(Ljava/security/cert/X509Certificate;Ljava/util/Collection;)Ljava/security/cert/TrustAnchor;
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->index(Ljava/security/cert/TrustAnchor;)V
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->index(Ljava/security/cert/X509Certificate;)Ljava/security/cert/TrustAnchor;
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->index(Ljava/util/Set;)V
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->reset()V
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->reset(Ljava/util/Set;)V
-Lcom/android/org/conscrypt/TrustedCertificateIndex;->subjectToTrustAnchors:Ljava/util/Map;
-Lcom/android/org/conscrypt/TrustedCertificateStore$CertSelector;->match(Ljava/security/cert/X509Certificate;)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore$PreloadHolder;-><init>()V
-Lcom/android/org/conscrypt/TrustedCertificateStore$PreloadHolder;->defaultCaCertsAddedDir:Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore$PreloadHolder;->defaultCaCertsDeletedDir:Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore$PreloadHolder;->defaultCaCertsSystemDir:Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore;-><init>(Ljava/io/File;Ljava/io/File;Ljava/io/File;)V
-Lcom/android/org/conscrypt/TrustedCertificateStore;->addAliases(Ljava/util/Set;Ljava/lang/String;Ljava/io/File;)V
-Lcom/android/org/conscrypt/TrustedCertificateStore;->addedDir:Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->aliases()Ljava/util/Set;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->allSystemAliases()Ljava/util/Set;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->CERT_FACTORY:Ljava/security/cert/CertificateFactory;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->containsAlias(Ljava/lang/String;)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore;->containsAlias(Ljava/lang/String;Z)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore;->convertToOpenSSLIfNeeded(Ljava/security/cert/X509Certificate;)Lcom/android/org/conscrypt/OpenSSLX509Certificate;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->deleteCertificateEntry(Ljava/lang/String;)V
-Lcom/android/org/conscrypt/TrustedCertificateStore;->deletedDir:Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->file(Ljava/io/File;Ljava/lang/String;I)Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->fileForAlias(Ljava/lang/String;)Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->findAllIssuers(Ljava/security/cert/X509Certificate;)Ljava/util/Set;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->findCert(Ljava/io/File;Ljavax/security/auth/x500/X500Principal;Lcom/android/org/conscrypt/TrustedCertificateStore$CertSelector;Ljava/lang/Class;)Ljava/lang/Object;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->findIssuer(Ljava/security/cert/X509Certificate;)Ljava/security/cert/X509Certificate;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificate(Ljava/lang/String;)Ljava/security/cert/Certificate;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificate(Ljava/lang/String;Z)Ljava/security/cert/Certificate;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificateAlias(Ljava/security/cert/Certificate;)Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificateAlias(Ljava/security/cert/Certificate;Z)Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->getCertificateFile(Ljava/io/File;Ljava/security/cert/X509Certificate;)Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->getCreationDate(Ljava/lang/String;)Ljava/util/Date;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->getTrustAnchor(Ljava/security/cert/X509Certificate;)Ljava/security/cert/X509Certificate;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->hash(Ljavax/security/auth/x500/X500Principal;)Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->installCertificate(Ljava/security/cert/X509Certificate;)V
-Lcom/android/org/conscrypt/TrustedCertificateStore;->isDeletedSystemCertificate(Ljava/security/cert/X509Certificate;)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore;->isSelfIssuedCertificate(Lcom/android/org/conscrypt/OpenSSLX509Certificate;)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore;->isSystem(Ljava/lang/String;)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore;->isTombstone(Ljava/io/File;)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore;->isUser(Ljava/lang/String;)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore;->isUserAddedCertificate(Ljava/security/cert/X509Certificate;)Z
-Lcom/android/org/conscrypt/TrustedCertificateStore;->PREFIX_SYSTEM:Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->PREFIX_USER:Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->readCertificate(Ljava/io/File;)Ljava/security/cert/X509Certificate;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->removeUnnecessaryTombstones(Ljava/lang/String;)V
-Lcom/android/org/conscrypt/TrustedCertificateStore;->setDefaultUserDirectory(Ljava/io/File;)V
-Lcom/android/org/conscrypt/TrustedCertificateStore;->systemDir:Ljava/io/File;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->userAliases()Ljava/util/Set;
-Lcom/android/org/conscrypt/TrustedCertificateStore;->writeCertificate(Ljava/io/File;Ljava/security/cert/X509Certificate;)V
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;-><init>(ZLjava/security/cert/X509Certificate;)V
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->clientAuth:Z
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_anyExtendedKeyUsage:Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_clientAuth:Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_msSGC:Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_nsSGC:Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_OID:Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->EKU_serverAuth:Ljava/lang/String;
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->leaf:Ljava/security/cert/X509Certificate;
-Lcom/android/org/conscrypt/TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker;->SUPPORTED_EXTENSIONS:Ljava/util/Set;
-Lcom/android/org/conscrypt/TrustManagerImpl$TrustAnchorComparator;-><init>()V
-Lcom/android/org/conscrypt/TrustManagerImpl$TrustAnchorComparator;->CERT_COMPARATOR:Lcom/android/org/conscrypt/CertificatePriorityComparator;
-Lcom/android/org/conscrypt/TrustManagerImpl$TrustAnchorComparator;->compare(Ljava/lang/Object;Ljava/lang/Object;)I
-Lcom/android/org/conscrypt/TrustManagerImpl$TrustAnchorComparator;->compare(Ljava/security/cert/TrustAnchor;Ljava/security/cert/TrustAnchor;)I
-Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;Lcom/android/org/conscrypt/CertPinManager;)V
-Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;Lcom/android/org/conscrypt/CertPinManager;Lcom/android/org/conscrypt/TrustedCertificateStore;)V
-Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;Lcom/android/org/conscrypt/CertPinManager;Lcom/android/org/conscrypt/TrustedCertificateStore;Lcom/android/org/conscrypt/CertBlacklist;)V
-Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;Lcom/android/org/conscrypt/CertPinManager;Lcom/android/org/conscrypt/TrustedCertificateStore;Lcom/android/org/conscrypt/CertBlacklist;Lcom/android/org/conscrypt/ct/CTLogStore;Lcom/android/org/conscrypt/ct/CTVerifier;Lcom/android/org/conscrypt/ct/CTPolicy;)V
-Lcom/android/org/conscrypt/TrustManagerImpl;->acceptedIssuers(Ljava/security/KeyStore;)[Ljava/security/cert/X509Certificate;
-Lcom/android/org/conscrypt/TrustManagerImpl;->acceptedIssuers:[Ljava/security/cert/X509Certificate;
-Lcom/android/org/conscrypt/TrustManagerImpl;->blacklist:Lcom/android/org/conscrypt/CertBlacklist;
-Lcom/android/org/conscrypt/TrustManagerImpl;->checkBlacklist(Ljava/security/cert/X509Certificate;)V
-Lcom/android/org/conscrypt/TrustManagerImpl;->checkClientTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
-Lcom/android/org/conscrypt/TrustManagerImpl;->checkCT(Ljava/lang/String;Ljava/util/List;[B[B)V
-Lcom/android/org/conscrypt/TrustManagerImpl;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljavax/net/ssl/SSLSession;)Ljava/util/List;
-Lcom/android/org/conscrypt/TrustManagerImpl;->checkTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljavax/net/ssl/SSLSession;Ljavax/net/ssl/SSLParameters;Z)Ljava/util/List;
-Lcom/android/org/conscrypt/TrustManagerImpl;->checkTrusted([Ljava/security/cert/X509Certificate;[B[BLjava/lang/String;Ljava/lang/String;Z)Ljava/util/List;
-Lcom/android/org/conscrypt/TrustManagerImpl;->checkTrustedRecursive([Ljava/security/cert/X509Certificate;[B[BLjava/lang/String;ZLjava/util/ArrayList;Ljava/util/ArrayList;Ljava/util/Set;)Ljava/util/List;
-Lcom/android/org/conscrypt/TrustManagerImpl;->ctEnabledOverride:Z
-Lcom/android/org/conscrypt/TrustManagerImpl;->ctPolicy:Lcom/android/org/conscrypt/ct/CTPolicy;
-Lcom/android/org/conscrypt/TrustManagerImpl;->ctVerifier:Lcom/android/org/conscrypt/ct/CTVerifier;
-Lcom/android/org/conscrypt/TrustManagerImpl;->err:Ljava/lang/Exception;
-Lcom/android/org/conscrypt/TrustManagerImpl;->factory:Ljava/security/cert/CertificateFactory;
-Lcom/android/org/conscrypt/TrustManagerImpl;->findAllTrustAnchorsByIssuerAndSignature(Ljava/security/cert/X509Certificate;)Ljava/util/Set;
-Lcom/android/org/conscrypt/TrustManagerImpl;->findTrustAnchorBySubjectAndPublicKey(Ljava/security/cert/X509Certificate;)Ljava/security/cert/TrustAnchor;
-Lcom/android/org/conscrypt/TrustManagerImpl;->getHandshakeSessionOrThrow(Ljavax/net/ssl/SSLSocket;)Ljavax/net/ssl/SSLSession;
-Lcom/android/org/conscrypt/TrustManagerImpl;->getOcspDataFromSession(Ljavax/net/ssl/SSLSession;)[B
-Lcom/android/org/conscrypt/TrustManagerImpl;->getTlsSctDataFromSession(Ljavax/net/ssl/SSLSession;)[B
-Lcom/android/org/conscrypt/TrustManagerImpl;->getTrustedChainForServer([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/net/Socket;)Ljava/util/List;
-Lcom/android/org/conscrypt/TrustManagerImpl;->getTrustedChainForServer([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljavax/net/ssl/SSLEngine;)Ljava/util/List;
-Lcom/android/org/conscrypt/TrustManagerImpl;->handleTrustStorageUpdate()V
-Lcom/android/org/conscrypt/TrustManagerImpl;->intermediateIndex:Lcom/android/org/conscrypt/TrustedCertificateIndex;
-Lcom/android/org/conscrypt/TrustManagerImpl;->isUserAddedCertificate(Ljava/security/cert/X509Certificate;)Z
-Lcom/android/org/conscrypt/TrustManagerImpl;->pinManager:Lcom/android/org/conscrypt/CertPinManager;
-Lcom/android/org/conscrypt/TrustManagerImpl;->rootKeyStore:Ljava/security/KeyStore;
-Lcom/android/org/conscrypt/TrustManagerImpl;->setCTEnabledOverride(Z)V
-Lcom/android/org/conscrypt/TrustManagerImpl;->setCTPolicy(Lcom/android/org/conscrypt/ct/CTPolicy;)V
-Lcom/android/org/conscrypt/TrustManagerImpl;->setCTVerifier(Lcom/android/org/conscrypt/ct/CTVerifier;)V
-Lcom/android/org/conscrypt/TrustManagerImpl;->setOcspResponses(Ljava/security/cert/PKIXParameters;Ljava/security/cert/X509Certificate;[B)V
-Lcom/android/org/conscrypt/TrustManagerImpl;->sortPotentialAnchors(Ljava/util/Set;)Ljava/util/Collection;
-Lcom/android/org/conscrypt/TrustManagerImpl;->trustAnchors([Ljava/security/cert/X509Certificate;)Ljava/util/Set;
-Lcom/android/org/conscrypt/TrustManagerImpl;->trustedCertificateIndex:Lcom/android/org/conscrypt/TrustedCertificateIndex;
-Lcom/android/org/conscrypt/TrustManagerImpl;->trustedCertificateStore:Lcom/android/org/conscrypt/TrustedCertificateStore;
-Lcom/android/org/conscrypt/TrustManagerImpl;->TRUST_ANCHOR_COMPARATOR:Lcom/android/org/conscrypt/TrustManagerImpl$TrustAnchorComparator;
-Lcom/android/org/conscrypt/TrustManagerImpl;->validator:Ljava/security/cert/CertPathValidator;
-Lcom/android/org/conscrypt/TrustManagerImpl;->verifyChain(Ljava/util/List;Ljava/util/List;Ljava/lang/String;Z[B[B)Ljava/util/List;
Lorg/apache/http/conn/ssl/AbstractVerifier;->IPV4_PATTERN:Ljava/util/regex/Pattern;
Lorg/apache/http/conn/ssl/AbstractVerifier;->isIPv4Address(Ljava/lang/String;)Z
Lorg/apache/http/conn/ssl/SSLSocketFactory$NoPreloadHolder;-><init>()V
diff --git a/cmds/idmap2/OWNERS b/cmds/idmap2/OWNERS
index f1903a5..69dfcc9 100644
--- a/cmds/idmap2/OWNERS
+++ b/cmds/idmap2/OWNERS
@@ -1,3 +1,4 @@
set noparent
toddke@google.com
-rtmitchell@google.com
\ No newline at end of file
+rtmitchell@google.com
+patb@google.com
\ No newline at end of file
diff --git a/core/api/current.txt b/core/api/current.txt
index 521e519..4c61afe 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5958,7 +5958,6 @@
method @NonNull public android.app.Notification.Builder setRemoteInputHistory(CharSequence[]);
method @NonNull public android.app.Notification.Builder setSettingsText(CharSequence);
method @NonNull public android.app.Notification.Builder setShortcutId(String);
- method @Deprecated @NonNull public android.app.Notification.Builder setShowForegroundImmediately(boolean);
method @NonNull public android.app.Notification.Builder setShowWhen(boolean);
method @NonNull public android.app.Notification.Builder setSmallIcon(@DrawableRes int);
method @NonNull public android.app.Notification.Builder setSmallIcon(@DrawableRes int, int);
@@ -18989,12 +18988,15 @@
method @NonNull public String getName();
method public int getOrdinal();
method public int getType();
+ method public boolean hasBrightnessControl();
+ method public boolean hasRgbControl();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.lights.Light> CREATOR;
- field public static final int LIGHT_TYPE_INPUT_PLAYER_ID = 10002; // 0x2712
- field public static final int LIGHT_TYPE_INPUT_RGB = 10003; // 0x2713
- field public static final int LIGHT_TYPE_INPUT_SINGLE = 10001; // 0x2711
+ field public static final int LIGHT_CAPABILITY_BRIGHTNESS = 1; // 0x1
+ field public static final int LIGHT_CAPABILITY_RGB = 0; // 0x0
+ field public static final int LIGHT_TYPE_INPUT = 10001; // 0x2711
field public static final int LIGHT_TYPE_MICROPHONE = 8; // 0x8
+ field public static final int LIGHT_TYPE_PLAYER_ID = 10002; // 0x2712
}
public final class LightState implements android.os.Parcelable {
@@ -19026,7 +19028,7 @@
public final class LightsRequest {
method @NonNull public java.util.List<android.hardware.lights.LightState> getLightStates();
method @NonNull public java.util.List<java.lang.Integer> getLights();
- method @NonNull public java.util.Map<java.lang.Integer,android.hardware.lights.LightState> getLightsAndStates();
+ method @NonNull public java.util.Map<android.hardware.lights.Light,android.hardware.lights.LightState> getLightsAndStates();
}
public static final class LightsRequest.Builder {
@@ -31962,7 +31964,6 @@
method public long getUserCreationTime(android.os.UserHandle);
method public android.os.UserHandle getUserForSerialNumber(long);
method @NonNull @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED, "android.permission.CREATE_USERS"}, conditional=true) public String getUserName();
- method public int getUserPrivacySensitivity();
method public java.util.List<android.os.UserHandle> getUserProfiles();
method public android.os.Bundle getUserRestrictions();
method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public android.os.Bundle getUserRestrictions(android.os.UserHandle);
@@ -32043,8 +32044,6 @@
field public static final String DISALLOW_USER_SWITCH = "no_user_switch";
field public static final String ENSURE_VERIFY_APPS = "ensure_verify_apps";
field public static final String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
- field public static final int PRIVACY_SENSITIVITY_DEFAULT = 0; // 0x0
- field public static final int PRIVACY_SENSITIVITY_LOCATION = 1; // 0x1
field public static final int QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED = 1; // 0x1
field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1
field public static final int USER_CREATION_FAILED_NO_MORE_USERS = 2; // 0x2
@@ -50267,6 +50266,7 @@
method @NonNull public android.graphics.Insets getInsets(int);
method @NonNull public android.graphics.Insets getInsetsIgnoringVisibility(int);
method @Deprecated @NonNull public android.graphics.Insets getMandatorySystemGestureInsets();
+ method @Nullable public android.graphics.Rect getPrivacyIndicatorBounds();
method @Nullable public android.view.RoundedCorner getRoundedCorner(int);
method @Deprecated public int getStableInsetBottom();
method @Deprecated public int getStableInsetLeft();
@@ -50301,6 +50301,7 @@
method @NonNull public android.view.WindowInsets.Builder setInsets(int, @NonNull android.graphics.Insets);
method @NonNull public android.view.WindowInsets.Builder setInsetsIgnoringVisibility(int, @NonNull android.graphics.Insets) throws java.lang.IllegalArgumentException;
method @Deprecated @NonNull public android.view.WindowInsets.Builder setMandatorySystemGestureInsets(@NonNull android.graphics.Insets);
+ method @NonNull public android.view.WindowInsets.Builder setPrivacyIndicatorBounds(@Nullable android.graphics.Rect);
method @NonNull public android.view.WindowInsets.Builder setRoundedCorner(int, @Nullable android.view.RoundedCorner);
method @Deprecated @NonNull public android.view.WindowInsets.Builder setStableInsets(@NonNull android.graphics.Insets);
method @Deprecated @NonNull public android.view.WindowInsets.Builder setSystemGestureInsets(@NonNull android.graphics.Insets);
@@ -52892,8 +52893,6 @@
public static final class TranslationRequest.Builder {
ctor public TranslationRequest.Builder();
- method @Deprecated @NonNull public android.view.translation.TranslationRequest.Builder addTranslationRequestValue(@NonNull android.view.translation.TranslationRequestValue);
- method @Deprecated @NonNull public android.view.translation.TranslationRequest.Builder addViewTranslationRequest(@NonNull android.view.translation.ViewTranslationRequest);
method @NonNull public android.view.translation.TranslationRequest build();
method @NonNull public android.view.translation.TranslationRequest.Builder setFlags(int);
method @NonNull public android.view.translation.TranslationRequest.Builder setTranslationRequestValues(@NonNull java.util.List<android.view.translation.TranslationRequestValue>);
@@ -52927,7 +52926,6 @@
method @NonNull public android.view.translation.TranslationResponse.Builder setFinalResponse(boolean);
method @NonNull public android.view.translation.TranslationResponse.Builder setTranslationResponseValue(int, @NonNull android.view.translation.TranslationResponseValue);
method @NonNull public android.view.translation.TranslationResponse.Builder setTranslationResponseValues(@NonNull android.util.SparseArray<android.view.translation.TranslationResponseValue>);
- method @Deprecated @NonNull public android.view.translation.TranslationResponse.Builder setTranslationStatus(int);
method @NonNull public android.view.translation.TranslationResponse.Builder setViewTranslationResponse(int, @NonNull android.view.translation.ViewTranslationResponse);
method @NonNull public android.view.translation.TranslationResponse.Builder setViewTranslationResponses(@NonNull android.util.SparseArray<android.view.translation.ViewTranslationResponse>);
}
diff --git a/core/api/removed.txt b/core/api/removed.txt
index cdb6a58..57e1598 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -560,6 +560,15 @@
method @Deprecated public void removeTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent);
}
+ public static final class TranslationRequest.Builder {
+ method @Deprecated @NonNull public android.view.translation.TranslationRequest.Builder addTranslationRequestValue(@NonNull android.view.translation.TranslationRequestValue);
+ method @Deprecated @NonNull public android.view.translation.TranslationRequest.Builder addViewTranslationRequest(@NonNull android.view.translation.ViewTranslationRequest);
+ }
+
+ public static final class TranslationResponse.Builder {
+ method @Deprecated @NonNull public android.view.translation.TranslationResponse.Builder setTranslationStatus(int);
+ }
+
public final class TranslationSpec implements android.os.Parcelable {
ctor @Deprecated public TranslationSpec(@NonNull String, int);
method @Deprecated @NonNull public String getLanguage();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index e28ac6e..7072bbe 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1458,6 +1458,7 @@
method public long getTimestampMillis();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.search.Query> CREATOR;
+ field public static final String EXTRA_IME_HEIGHT = "android.app.search.extra.IME_HEIGHT";
}
public final class SearchAction implements android.os.Parcelable {
@@ -1526,7 +1527,7 @@
method @Nullable public android.content.pm.ShortcutInfo getShortcutInfo();
method @Nullable public android.net.Uri getSliceUri();
method @NonNull public android.os.UserHandle getUserHandle();
- method public boolean shouldHide();
+ method public boolean isHidden();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.search.SearchTarget> CREATOR;
field public static final String LAYOUT_TYPE_ICON = "icon";
@@ -1543,12 +1544,12 @@
method @NonNull public android.app.search.SearchTarget build();
method @NonNull public android.app.search.SearchTarget.Builder setAppWidgetProviderInfo(@NonNull android.appwidget.AppWidgetProviderInfo);
method @NonNull public android.app.search.SearchTarget.Builder setExtras(@NonNull android.os.Bundle);
+ method @NonNull public android.app.search.SearchTarget.Builder setHidden(boolean);
method @NonNull public android.app.search.SearchTarget.Builder setPackageName(@NonNull String);
method @NonNull public android.app.search.SearchTarget.Builder setParentId(@NonNull String);
method @NonNull public android.app.search.SearchTarget.Builder setScore(@FloatRange(from=0.0f, to=1.0f) float);
method @NonNull public android.app.search.SearchTarget.Builder setSearchAction(@Nullable android.app.search.SearchAction);
method @NonNull public android.app.search.SearchTarget.Builder setShortcutInfo(@NonNull android.content.pm.ShortcutInfo);
- method @NonNull public android.app.search.SearchTarget.Builder setShouldHide(boolean);
method @NonNull public android.app.search.SearchTarget.Builder setSliceUri(@NonNull android.net.Uri);
method @NonNull public android.app.search.SearchTarget.Builder setUserHandle(@NonNull android.os.UserHandle);
}
@@ -2246,7 +2247,7 @@
package android.companion {
public final class CompanionDeviceManager {
- method @RequiresPermission(android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES) public void associate(@NonNull String, @NonNull android.net.MacAddress);
+ method @RequiresPermission(android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES) public void associate(@NonNull String, @NonNull android.net.MacAddress, @NonNull byte[]);
method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean canPairWithoutPrompt(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean isDeviceAssociatedForWifiConnection(@NonNull String, @NonNull android.net.MacAddress, @NonNull android.os.UserHandle);
}
@@ -3118,7 +3119,7 @@
method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(int, @NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void addSensorPrivacyListener(int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public boolean isSensorPrivacyEnabled(int);
- method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void removeSensorPrivacyListener(@NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
+ method @RequiresPermission(android.Manifest.permission.OBSERVE_SENSOR_PRIVACY) public void removeSensorPrivacyListener(int, @NonNull android.hardware.SensorPrivacyManager.OnSensorPrivacyChangedListener);
}
public static interface SensorPrivacyManager.OnSensorPrivacyChangedListener {
@@ -4941,7 +4942,6 @@
method public boolean isLocationEnabledForUser(@NonNull android.os.UserHandle);
method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle);
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String);
- method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String, @Nullable String);
method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.UPDATE_APP_OPS_STATS}) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
@@ -5003,7 +5003,6 @@
public final class SatellitePvt implements android.os.Parcelable {
method public int describeContents();
method @Nullable public android.location.SatellitePvt.ClockInfo getClockInfo();
- method public int getFlags();
method @FloatRange public double getIonoDelayMeters();
method @Nullable public android.location.SatellitePvt.PositionEcef getPositionEcef();
method @FloatRange public double getTropoDelayMeters();
@@ -5019,10 +5018,9 @@
ctor public SatellitePvt.Builder();
method @NonNull public android.location.SatellitePvt build();
method @NonNull public android.location.SatellitePvt.Builder setClockInfo(@NonNull android.location.SatellitePvt.ClockInfo);
- method @NonNull public android.location.SatellitePvt.Builder setFlags(int);
- method @NonNull public android.location.SatellitePvt.Builder setIonoDelayMeters(@FloatRange double);
+ method @NonNull public android.location.SatellitePvt.Builder setIonoDelayMeters(@FloatRange(from=0.0f, to=100.0f) double);
method @NonNull public android.location.SatellitePvt.Builder setPositionEcef(@NonNull android.location.SatellitePvt.PositionEcef);
- method @NonNull public android.location.SatellitePvt.Builder setTropoDelayMeters(@FloatRange double);
+ method @NonNull public android.location.SatellitePvt.Builder setTropoDelayMeters(@FloatRange(from=0.0f, to=100.0f) double);
method @NonNull public android.location.SatellitePvt.Builder setVelocityEcef(@NonNull android.location.SatellitePvt.VelocityEcef);
}
@@ -9085,6 +9083,7 @@
field public static final String NAMESPACE_GAME_DRIVER = "game_driver";
field public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
field public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
+ field public static final String NAMESPACE_LOCATION = "location";
field public static final String NAMESPACE_MEDIA = "media";
field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
@@ -10413,11 +10412,11 @@
ctor public TranslationService();
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
method public void onConnected();
- method public void onCreateTranslationSession(@NonNull android.view.translation.TranslationContext, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method public abstract void onCreateTranslationSession(@NonNull android.view.translation.TranslationContext, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method public void onDisconnected();
method public abstract void onFinishTranslationSession(int);
method public abstract void onTranslationCapabilitiesRequest(int, int, @NonNull java.util.function.Consumer<java.util.Set<android.view.translation.TranslationCapability>>);
- method public void onTranslationRequest(@NonNull android.view.translation.TranslationRequest, int, @Nullable android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.view.translation.TranslationResponse>);
+ method public abstract void onTranslationRequest(@NonNull android.view.translation.TranslationRequest, int, @Nullable android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.view.translation.TranslationResponse>);
method public final void updateTranslationCapability(@NonNull android.view.translation.TranslationCapability);
field public static final String SERVICE_INTERFACE = "android.service.translation.TranslationService";
field public static final String SERVICE_META_DATA = "android.translation_service";
@@ -10513,9 +10512,11 @@
public final class HotwordDetectedResult implements android.os.Parcelable {
method public int describeContents();
- method public int getByteOffset();
+ method public int getAudioChannel();
method public int getConfidenceLevel();
method @NonNull public android.os.PersistableBundle getExtras();
+ method public int getHotwordDurationMillis();
+ method public int getHotwordOffsetMillis();
method public int getHotwordPhraseId();
method public static int getMaxBundleSize();
method public static int getMaxHotwordPhraseId();
@@ -10523,17 +10524,29 @@
method @Nullable public android.media.MediaSyncEvent getMediaSyncEvent();
method public int getPersonalizedScore();
method public int getScore();
+ method public boolean isHotwordDetectionPersonalized();
method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final int BYTE_OFFSET_UNSET = -1; // 0xffffffff
+ field public static final int AUDIO_CHANNEL_UNSET = -1; // 0xffffffff
+ field public static final int CONFIDENCE_LEVEL_HIGH = 5; // 0x5
+ field public static final int CONFIDENCE_LEVEL_LOW = 1; // 0x1
+ field public static final int CONFIDENCE_LEVEL_LOW_MEDIUM = 2; // 0x2
+ field public static final int CONFIDENCE_LEVEL_MEDIUM = 3; // 0x3
+ field public static final int CONFIDENCE_LEVEL_MEDIUM_HIGH = 4; // 0x4
+ field public static final int CONFIDENCE_LEVEL_NONE = 0; // 0x0
+ field public static final int CONFIDENCE_LEVEL_VERY_HIGH = 6; // 0x6
field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.HotwordDetectedResult> CREATOR;
+ field public static final int HOTWORD_OFFSET_UNSET = -1; // 0xffffffff
}
public static final class HotwordDetectedResult.Builder {
ctor public HotwordDetectedResult.Builder();
method @NonNull public android.service.voice.HotwordDetectedResult build();
- method @NonNull public android.service.voice.HotwordDetectedResult.Builder setByteOffset(int);
+ method @NonNull public android.service.voice.HotwordDetectedResult.Builder setAudioChannel(int);
method @NonNull public android.service.voice.HotwordDetectedResult.Builder setConfidenceLevel(int);
method @NonNull public android.service.voice.HotwordDetectedResult.Builder setExtras(@NonNull android.os.PersistableBundle);
+ method @NonNull public android.service.voice.HotwordDetectedResult.Builder setHotwordDetectionPersonalized(boolean);
+ method @NonNull public android.service.voice.HotwordDetectedResult.Builder setHotwordDurationMillis(int);
+ method @NonNull public android.service.voice.HotwordDetectedResult.Builder setHotwordOffsetMillis(int);
method @NonNull public android.service.voice.HotwordDetectedResult.Builder setHotwordPhraseId(int);
method @NonNull public android.service.voice.HotwordDetectedResult.Builder setMediaSyncEvent(@NonNull android.media.MediaSyncEvent);
method @NonNull public android.service.voice.HotwordDetectedResult.Builder setPersonalizedScore(int);
@@ -10544,11 +10557,10 @@
ctor public HotwordDetectionService();
method public static int getMaxCustomInitializationStatus();
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
- method @Deprecated public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, long, @NonNull android.service.voice.HotwordDetectionService.Callback);
method public void onDetect(@NonNull android.service.voice.AlwaysOnHotwordDetector.EventPayload, long, @NonNull android.service.voice.HotwordDetectionService.Callback);
- method @Deprecated public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @NonNull android.service.voice.HotwordDetectionService.Callback);
method public void onDetect(@NonNull android.service.voice.HotwordDetectionService.Callback);
method public void onDetect(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle, @NonNull android.service.voice.HotwordDetectionService.Callback);
+ method public void onStopDetection();
method public void onUpdateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, long, @Nullable java.util.function.IntConsumer);
field public static final int INITIALIZATION_STATUS_SUCCESS = 0; // 0x0
field public static final int INITIALIZATION_STATUS_UNKNOWN = 100; // 0x64
@@ -10565,10 +10577,6 @@
method public boolean startRecognition(@NonNull android.os.ParcelFileDescriptor, @NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle);
method public boolean stopRecognition();
method public void updateState(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory);
- field public static final int CONFIDENCE_LEVEL_HIGH = 3; // 0x3
- field public static final int CONFIDENCE_LEVEL_LOW = 1; // 0x1
- field public static final int CONFIDENCE_LEVEL_MEDIUM = 2; // 0x2
- field public static final int CONFIDENCE_LEVEL_NONE = 0; // 0x0
}
public static interface HotwordDetector.Callback {
@@ -10585,13 +10593,22 @@
method public int describeContents();
method public int getConfidenceLevel();
method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CONFIDENCE_LEVEL_HIGH = 3; // 0x3
+ field public static final int CONFIDENCE_LEVEL_LOW = 1; // 0x1
+ field public static final int CONFIDENCE_LEVEL_MEDIUM = 2; // 0x2
+ field public static final int CONFIDENCE_LEVEL_NONE = 0; // 0x0
field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.HotwordRejectedResult> CREATOR;
}
+ public static final class HotwordRejectedResult.Builder {
+ ctor public HotwordRejectedResult.Builder();
+ method @NonNull public android.service.voice.HotwordRejectedResult build();
+ method @NonNull public android.service.voice.HotwordRejectedResult.Builder setConfidenceLevel(int);
+ }
+
public class VoiceInteractionService extends android.app.Service {
method @NonNull public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, @Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, android.service.voice.AlwaysOnHotwordDetector.Callback);
- method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.HotwordDetector createHotwordDetector(@NonNull android.media.AudioFormat, @Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull android.service.voice.HotwordDetector.Callback);
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.HotwordDetector createHotwordDetector(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull android.service.voice.HotwordDetector.Callback);
method @NonNull @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public final android.media.voice.KeyphraseModelManager createKeyphraseModelManager();
}
@@ -12821,7 +12838,6 @@
method public void onCreated(@NonNull android.telephony.ims.stub.SipDelegate, @Nullable java.util.Set<android.telephony.ims.FeatureTagState>);
method public void onDestroyed(int);
method public void onFeatureTagRegistrationChanged(@NonNull android.telephony.ims.DelegateRegistrationState);
- method @Deprecated public void onImsConfigurationChanged(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
}
public final class FeatureTagState implements android.os.Parcelable {
@@ -13636,74 +13652,12 @@
}
public interface SipDelegateConnection {
- method public default void cleanupSession(@NonNull String);
- method @Deprecated public default void closeDialog(@NonNull String);
+ method public void cleanupSession(@NonNull String);
method public void notifyMessageReceiveError(@NonNull String, int);
method public void notifyMessageReceived(@NonNull String);
method public void sendMessage(@NonNull android.telephony.ims.SipMessage, long);
}
- @Deprecated public final class SipDelegateImsConfiguration implements android.os.Parcelable {
- method @Deprecated public boolean containsKey(@NonNull String);
- method @Deprecated @NonNull public android.os.PersistableBundle copyBundle();
- method @Deprecated public int describeContents();
- method @Deprecated public boolean getBoolean(@NonNull String, boolean);
- method @Deprecated public int getInt(@NonNull String, int);
- method @Deprecated @Nullable public String getString(@NonNull String);
- method @Deprecated public long getVersion();
- method @Deprecated public void writeToParcel(@NonNull android.os.Parcel, int);
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipDelegateImsConfiguration> CREATOR;
- field @Deprecated public static final String IPTYPE_IPV4 = "IPV4";
- field @Deprecated public static final String IPTYPE_IPV6 = "IPV6";
- field @Deprecated public static final String KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING = "sip_config_auhentication_header_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING = "sip_config_authentication_nonce_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_CELLULAR_NETWORK_INFO_HEADER_STRING = "sip_config_cellular_network_info_header_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_HOME_DOMAIN_STRING = "sip_config_home_domain_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_IMEI_STRING = "sip_config_imei_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_IPTYPE_STRING = "sip_config_iptype_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL = "sip_config_is_compact_form_enabled_bool";
- field @Deprecated public static final String KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL = "sip_config_is_gruu_enabled_bool";
- field @Deprecated public static final String KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL = "sip_config_is_ipsec_enabled_bool";
- field @Deprecated public static final String KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL = "sip_config_is_keepalive_enabled_bool";
- field @Deprecated public static final String KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL = "sip_config_is_nat_enabled_bool";
- field @Deprecated public static final String KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT = "sip_config_udp_max_payload_size_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_PATH_HEADER_STRING = "sip_config_path_header_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING = "sip_config_p_access_network_info_header_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING = "sip_config_p_associated_uri_header_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING = "sip_config_p_last_access_network_info_header_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING = "sip_config_security_verify_header_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING = "sip_config_server_default_ipaddress_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT = "sip_config_server_default_port_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT = "sip_config_server_ipsec_client_port_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT = "sip_config_server_ipsec_old_client_port_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT = "sip_config_server_ipsec_server_port_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING = "sip_config_service_route_header_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING = "sip_config_protocol_type_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING = "sip_config_ue_default_ipaddress_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT = "sip_config_ue_default_port_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT = "sip_config_ue_ipsec_client_port_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT = "sip_config_ue_ipsec_old_client_port_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT = "sip_config_ue_ipsec_server_port_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING = "sip_config_ue_private_user_id_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING = "sip_config_ue_public_gruu_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING = "sip_config_ue_public_ipaddress_with_nat_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT = "sip_config_ue_public_port_with_nat_int";
- field @Deprecated public static final String KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING = "sip_config_ue_public_user_id_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_URI_USER_PART_STRING = "sip_config_uri_user_part_string";
- field @Deprecated public static final String KEY_SIP_CONFIG_USER_AGENT_HEADER_STRING = "sip_config_sip_user_agent_header_string";
- field @Deprecated public static final String SIP_TRANSPORT_TCP = "TCP";
- field @Deprecated public static final String SIP_TRANSPORT_UDP = "UDP";
- }
-
- @Deprecated public static final class SipDelegateImsConfiguration.Builder {
- ctor @Deprecated public SipDelegateImsConfiguration.Builder(int);
- ctor @Deprecated public SipDelegateImsConfiguration.Builder(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
- method @Deprecated @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addBoolean(@NonNull String, boolean);
- method @Deprecated @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addInt(@NonNull String, int);
- method @Deprecated @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addString(@NonNull String, @NonNull String);
- method @Deprecated @NonNull public android.telephony.ims.SipDelegateImsConfiguration build();
- }
-
public class SipDelegateManager {
method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void createSipDelegate(@NonNull android.telephony.ims.DelegateRequest, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.stub.DelegateConnectionStateCallback, @NonNull android.telephony.ims.stub.DelegateConnectionMessageCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void destroySipDelegate(@NonNull android.telephony.ims.SipDelegateConnection, int);
@@ -13871,11 +13825,10 @@
}
public interface DelegateConnectionStateCallback {
- method public default void onConfigurationChanged(@NonNull android.telephony.ims.SipDelegateConfiguration);
+ method public void onConfigurationChanged(@NonNull android.telephony.ims.SipDelegateConfiguration);
method public void onCreated(@NonNull android.telephony.ims.SipDelegateConnection);
method public void onDestroyed(int);
method public void onFeatureTagStatusChanged(@NonNull android.telephony.ims.DelegateRegistrationState, @NonNull java.util.Set<android.telephony.ims.FeatureTagState>);
- method @Deprecated public default void onImsConfigurationChanged(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
}
public class ImsCallSessionImplBase implements java.lang.AutoCloseable {
@@ -14089,8 +14042,7 @@
}
public interface SipDelegate {
- method public default void cleanupSession(@NonNull String);
- method @Deprecated public default void closeDialog(@NonNull String);
+ method public void cleanupSession(@NonNull String);
method public void notifyMessageReceiveError(@NonNull String, int);
method public void notifyMessageReceived(@NonNull String);
method public void sendMessage(@NonNull android.telephony.ims.SipMessage, long);
diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt
index 304f4fe..9a8a493 100644
--- a/core/api/system-removed.txt
+++ b/core/api/system-removed.txt
@@ -58,6 +58,14 @@
method @Deprecated public void destroy();
}
+ public final class SearchTarget implements android.os.Parcelable {
+ method @Deprecated public boolean shouldHide();
+ }
+
+ public static final class SearchTarget.Builder {
+ method @Deprecated @NonNull public android.app.search.SearchTarget.Builder setShouldHide(boolean);
+ }
+
}
package android.bluetooth {
@@ -127,6 +135,7 @@
public class LocationManager {
method @Deprecated public boolean addGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
method @Deprecated public boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
method @Deprecated public void removeGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
method @Deprecated public void removeGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackage(String);
@@ -223,6 +232,83 @@
}
+package android.telephony.ims {
+
+ public interface DelegateStateCallback {
+ method @Deprecated public void onImsConfigurationChanged(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
+ }
+
+ @Deprecated public final class SipDelegateImsConfiguration implements android.os.Parcelable {
+ method public boolean containsKey(@NonNull String);
+ method @NonNull public android.os.PersistableBundle copyBundle();
+ method public int describeContents();
+ method public boolean getBoolean(@NonNull String, boolean);
+ method public int getInt(@NonNull String, int);
+ method @Nullable public String getString(@NonNull String);
+ method public long getVersion();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipDelegateImsConfiguration> CREATOR;
+ field public static final String IPTYPE_IPV4 = "IPV4";
+ field public static final String IPTYPE_IPV6 = "IPV6";
+ field public static final String KEY_SIP_CONFIG_AUTHENTICATION_HEADER_STRING = "sip_config_auhentication_header_string";
+ field public static final String KEY_SIP_CONFIG_AUTHENTICATION_NONCE_STRING = "sip_config_authentication_nonce_string";
+ field public static final String KEY_SIP_CONFIG_CELLULAR_NETWORK_INFO_HEADER_STRING = "sip_config_cellular_network_info_header_string";
+ field public static final String KEY_SIP_CONFIG_HOME_DOMAIN_STRING = "sip_config_home_domain_string";
+ field public static final String KEY_SIP_CONFIG_IMEI_STRING = "sip_config_imei_string";
+ field public static final String KEY_SIP_CONFIG_IPTYPE_STRING = "sip_config_iptype_string";
+ field public static final String KEY_SIP_CONFIG_IS_COMPACT_FORM_ENABLED_BOOL = "sip_config_is_compact_form_enabled_bool";
+ field public static final String KEY_SIP_CONFIG_IS_GRUU_ENABLED_BOOL = "sip_config_is_gruu_enabled_bool";
+ field public static final String KEY_SIP_CONFIG_IS_IPSEC_ENABLED_BOOL = "sip_config_is_ipsec_enabled_bool";
+ field public static final String KEY_SIP_CONFIG_IS_KEEPALIVE_ENABLED_BOOL = "sip_config_is_keepalive_enabled_bool";
+ field public static final String KEY_SIP_CONFIG_IS_NAT_ENABLED_BOOL = "sip_config_is_nat_enabled_bool";
+ field public static final String KEY_SIP_CONFIG_MAX_PAYLOAD_SIZE_ON_UDP_INT = "sip_config_udp_max_payload_size_int";
+ field public static final String KEY_SIP_CONFIG_PATH_HEADER_STRING = "sip_config_path_header_string";
+ field public static final String KEY_SIP_CONFIG_P_ACCESS_NETWORK_INFO_HEADER_STRING = "sip_config_p_access_network_info_header_string";
+ field public static final String KEY_SIP_CONFIG_P_ASSOCIATED_URI_HEADER_STRING = "sip_config_p_associated_uri_header_string";
+ field public static final String KEY_SIP_CONFIG_P_LAST_ACCESS_NETWORK_INFO_HEADER_STRING = "sip_config_p_last_access_network_info_header_string";
+ field public static final String KEY_SIP_CONFIG_SECURITY_VERIFY_HEADER_STRING = "sip_config_security_verify_header_string";
+ field public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_IPADDRESS_STRING = "sip_config_server_default_ipaddress_string";
+ field public static final String KEY_SIP_CONFIG_SERVER_DEFAULT_PORT_INT = "sip_config_server_default_port_int";
+ field public static final String KEY_SIP_CONFIG_SERVER_IPSEC_CLIENT_PORT_INT = "sip_config_server_ipsec_client_port_int";
+ field public static final String KEY_SIP_CONFIG_SERVER_IPSEC_OLD_CLIENT_PORT_INT = "sip_config_server_ipsec_old_client_port_int";
+ field public static final String KEY_SIP_CONFIG_SERVER_IPSEC_SERVER_PORT_INT = "sip_config_server_ipsec_server_port_int";
+ field public static final String KEY_SIP_CONFIG_SERVICE_ROUTE_HEADER_STRING = "sip_config_service_route_header_string";
+ field public static final String KEY_SIP_CONFIG_TRANSPORT_TYPE_STRING = "sip_config_protocol_type_string";
+ field public static final String KEY_SIP_CONFIG_UE_DEFAULT_IPADDRESS_STRING = "sip_config_ue_default_ipaddress_string";
+ field public static final String KEY_SIP_CONFIG_UE_DEFAULT_PORT_INT = "sip_config_ue_default_port_int";
+ field public static final String KEY_SIP_CONFIG_UE_IPSEC_CLIENT_PORT_INT = "sip_config_ue_ipsec_client_port_int";
+ field public static final String KEY_SIP_CONFIG_UE_IPSEC_OLD_CLIENT_PORT_INT = "sip_config_ue_ipsec_old_client_port_int";
+ field public static final String KEY_SIP_CONFIG_UE_IPSEC_SERVER_PORT_INT = "sip_config_ue_ipsec_server_port_int";
+ field public static final String KEY_SIP_CONFIG_UE_PRIVATE_USER_ID_STRING = "sip_config_ue_private_user_id_string";
+ field public static final String KEY_SIP_CONFIG_UE_PUBLIC_GRUU_STRING = "sip_config_ue_public_gruu_string";
+ field public static final String KEY_SIP_CONFIG_UE_PUBLIC_IPADDRESS_WITH_NAT_STRING = "sip_config_ue_public_ipaddress_with_nat_string";
+ field public static final String KEY_SIP_CONFIG_UE_PUBLIC_PORT_WITH_NAT_INT = "sip_config_ue_public_port_with_nat_int";
+ field public static final String KEY_SIP_CONFIG_UE_PUBLIC_USER_ID_STRING = "sip_config_ue_public_user_id_string";
+ field public static final String KEY_SIP_CONFIG_URI_USER_PART_STRING = "sip_config_uri_user_part_string";
+ field public static final String KEY_SIP_CONFIG_USER_AGENT_HEADER_STRING = "sip_config_sip_user_agent_header_string";
+ field public static final String SIP_TRANSPORT_TCP = "TCP";
+ field public static final String SIP_TRANSPORT_UDP = "UDP";
+ }
+
+ public static final class SipDelegateImsConfiguration.Builder {
+ ctor public SipDelegateImsConfiguration.Builder(int);
+ ctor public SipDelegateImsConfiguration.Builder(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
+ method @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addBoolean(@NonNull String, boolean);
+ method @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addInt(@NonNull String, int);
+ method @NonNull public android.telephony.ims.SipDelegateImsConfiguration.Builder addString(@NonNull String, @NonNull String);
+ method @NonNull public android.telephony.ims.SipDelegateImsConfiguration build();
+ }
+
+}
+
+package android.telephony.ims.stub {
+
+ public interface DelegateConnectionStateCallback {
+ method @Deprecated public default void onImsConfigurationChanged(@NonNull android.telephony.ims.SipDelegateImsConfiguration);
+ }
+
+}
+
package android.view.translation {
public final class UiTranslationManager {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 5a9dc82..2f795f0 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1204,6 +1204,10 @@
package android.hardware.lights {
+ public final class Light implements android.os.Parcelable {
+ method public int getCapabilities();
+ }
+
public abstract class LightsManager {
method @NonNull public abstract android.hardware.lights.LightsManager.LightsSession openSession(int);
}
@@ -1358,7 +1362,8 @@
public class LocationManager {
method @NonNull public String[] getBackgroundThrottlingWhitelist();
- method @NonNull public String[] getIgnoreSettingsWhitelist();
+ method @NonNull public android.os.PackageTagsList getIgnoreSettingsAllowlist();
+ method @Deprecated @NonNull public String[] getIgnoreSettingsWhitelist();
method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public java.util.List<java.lang.String> getProviderPackages(@NonNull String);
}
@@ -1653,6 +1658,28 @@
method public void removeSyncBarrier(int);
}
+ public final class PackageTagsList implements android.os.Parcelable {
+ method public boolean contains(@NonNull String, @Nullable String);
+ method public boolean contains(@NonNull android.os.PackageTagsList);
+ method public boolean containsAll(@NonNull String);
+ method public int describeContents();
+ method public boolean includes(@NonNull String);
+ method public boolean isEmpty();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.os.PackageTagsList> CREATOR;
+ }
+
+ public static final class PackageTagsList.Builder {
+ ctor public PackageTagsList.Builder();
+ ctor public PackageTagsList.Builder(int);
+ method @NonNull public android.os.PackageTagsList.Builder add(@NonNull String);
+ method @NonNull public android.os.PackageTagsList.Builder add(@NonNull String, @Nullable String);
+ method @NonNull public android.os.PackageTagsList.Builder add(@NonNull android.os.PackageTagsList);
+ method @NonNull public android.os.PackageTagsList.Builder add(@NonNull java.util.Map<java.lang.String,? extends java.util.Set<java.lang.String>>);
+ method @NonNull public android.os.PackageTagsList build();
+ method @NonNull public android.os.PackageTagsList.Builder clear();
+ }
+
public final class Parcel {
method public boolean allowSquashing();
method public int readExceptionCode();
@@ -2087,7 +2114,7 @@
field public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
field public static final String HIDDEN_API_POLICY = "hidden_api_policy";
field public static final String HIDE_ERROR_DIALOGS = "hide_error_dialogs";
- field public static final String LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST = "location_ignore_settings_package_whitelist";
+ field @Deprecated public static final String LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST = "location_ignore_settings_package_whitelist";
field public static final String LOW_POWER_MODE = "low_power";
field public static final String LOW_POWER_MODE_STICKY = "low_power_sticky";
field @Deprecated public static final String NOTIFICATION_BUBBLES = "notification_bubbles";
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 92bdda3..7149096 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -73,8 +73,8 @@
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
@@ -237,7 +237,6 @@
import java.util.TimeZone;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
/**
@@ -338,6 +337,11 @@
*/
@UnsupportedAppUsage
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
+ /**
+ * Maps from activity token to local record of the activities that are preparing to be launched.
+ */
+ final Map<IBinder, ActivityClientRecord> mLaunchingActivities =
+ Collections.synchronizedMap(new ArrayMap<IBinder, ActivityClientRecord>());
/** The activities to be truly destroyed (not include relaunch). */
final Map<IBinder, ClientTransactionItem> mActivitiesToBeDestroyed =
Collections.synchronizedMap(new ArrayMap<IBinder, ClientTransactionItem>());
@@ -347,7 +351,6 @@
// Number of activities that are currently visible on-screen.
@UnsupportedAppUsage
int mNumVisibleActivities = 0;
- private final AtomicInteger mNumLaunchingActivities = new AtomicInteger();
@GuardedBy("mAppThread")
private int mLastProcessState = PROCESS_STATE_UNKNOWN;
@GuardedBy("mAppThread")
@@ -1182,7 +1185,7 @@
InetAddress.clearDnsCache();
// Allow libcore to perform the necessary actions as it sees fit upon a network
// configuration change.
- NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged();
+ NetworkEventDispatcher.getInstance().dispatchNetworkConfigurationChange();
}
public void updateHttpProxy() {
@@ -3256,6 +3259,21 @@
}
@Override
+ public void addLaunchingActivity(IBinder token, ActivityClientRecord activity) {
+ mLaunchingActivities.put(token, activity);
+ }
+
+ @Override
+ public ActivityClientRecord getLaunchingActivity(IBinder token) {
+ return mLaunchingActivities.get(token);
+ }
+
+ @Override
+ public void removeLaunchingActivity(IBinder token) {
+ mLaunchingActivities.remove(token);
+ }
+
+ @Override
public ActivityClientRecord getActivityClient(IBinder token) {
return mActivities.get(token);
}
@@ -3299,7 +3317,7 @@
// Defer the top state for VM to avoid aggressive JIT compilation affecting activity
// launch time.
if (processState == ActivityManager.PROCESS_STATE_TOP
- && mNumLaunchingActivities.get() > 0) {
+ && !mLaunchingActivities.isEmpty()) {
mPendingProcessState = processState;
mH.postDelayed(this::applyPendingProcessState, PENDING_TOP_PROCESS_STATE_TIMEOUT);
} else {
@@ -3315,7 +3333,7 @@
// Handle the pending configuration if the process state is changed from cached to
// non-cached. Except the case where there is a launching activity because the
// LaunchActivityItem will handle it.
- if (wasCached && !isCachedProcessState() && mNumLaunchingActivities.get() == 0) {
+ if (wasCached && !isCachedProcessState() && mLaunchingActivities.isEmpty()) {
final Configuration pendingConfig =
mConfigurationController.getPendingConfiguration(false /* clearPending */);
if (pendingConfig == null) {
@@ -3353,11 +3371,6 @@
}
}
- @Override
- public void countLaunchingActivities(int num) {
- mNumLaunchingActivities.getAndAdd(num);
- }
-
@UnsupportedAppUsage
public final void sendActivityResult(
IBinder token, String id, int requestCode,
@@ -4108,7 +4121,7 @@
}
synchronized (this) {
if (mSplashScreenGlobal != null) {
- mSplashScreenGlobal.dispatchOnExitAnimation(r.token, v);
+ mSplashScreenGlobal.handOverSplashScreenView(r.token, v);
}
}
}
@@ -6413,7 +6426,7 @@
VMDebug.setAllocTrackerStackDepth(Integer.parseInt(property));
}
if (data.trackAllocation) {
- DdmVmInternal.enableRecentAllocations(true);
+ DdmVmInternal.setRecentAllocationsTrackingEnabled(true);
}
// Note when this process has started.
Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 53502d4..02520af 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -49,6 +49,7 @@
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
+import android.os.PackageTagsList;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
@@ -7407,7 +7408,7 @@
/** @hide */
public void setUserRestriction(int code, boolean restricted, IBinder token) {
- setUserRestriction(code, restricted, token, (Map<String, String[]>) null);
+ setUserRestriction(code, restricted, token, null);
}
/**
@@ -7415,7 +7416,7 @@
* @hide
*/
public void setUserRestriction(int code, boolean restricted, IBinder token,
- @Nullable Map<String, String[]> excludedPackageTags) {
+ @Nullable PackageTagsList excludedPackageTags) {
setUserRestrictionForUser(code, restricted, token, excludedPackageTags,
mContext.getUserId());
}
@@ -7425,7 +7426,7 @@
* @hide
*/
public void setUserRestrictionForUser(int code, boolean restricted, IBinder token,
- @Nullable Map<String, String[]> excludedPackageTags, int userId) {
+ @Nullable PackageTagsList excludedPackageTags, int userId) {
try {
mService.setUserRestriction(code, restricted, token, userId, excludedPackageTags);
} catch (RemoteException e) {
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index 4f94c9b..d54452f 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -334,6 +334,26 @@
*/
public static final int SUBREASON_CACHED_IDLE_FORCED_APP_STANDBY = 18;
+ /**
+ * The process was killed because it fails to freeze/unfreeze binder
+ * or query binder frozen info while being frozen.
+ * this would be set only when the reason is {@link #REASON_FREEZER}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_FREEZER_BINDER_IOCTL = 19;
+
+ /**
+ * The process was killed because it receives sync binder transactions
+ * while being frozen.
+ * this would be set only when the reason is {@link #REASON_FREEZER}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_FREEZER_BINDER_TRANSACTION = 20;
+
// If there is any OEM code which involves additional app kill reasons, it should
// be categorized in {@link #REASON_OTHER}, with subreason code starting from 1000.
@@ -491,6 +511,8 @@
SUBREASON_IMPERCEPTIBLE,
SUBREASON_REMOVE_LRU,
SUBREASON_ISOLATED_NOT_NEEDED,
+ SUBREASON_FREEZER_BINDER_IOCTL,
+ SUBREASON_FREEZER_BINDER_TRANSACTION,
})
@Retention(RetentionPolicy.SOURCE)
public @interface SubReason {}
@@ -1032,6 +1054,8 @@
pw.println(prefix + " user=" + UserHandle.getUserId(mPackageUid));
pw.println(prefix + " process=" + mProcessName);
pw.println(prefix + " reason=" + mReason + " (" + reasonCodeToString(mReason) + ")");
+ pw.println(prefix + " subreason=" + mSubReason + " (" + subreasonToString(mSubReason)
+ + ")");
pw.println(prefix + " status=" + mStatus);
pw.println(prefix + " importance=" + mImportance);
pw.print(prefix + " pss="); DebugUtils.printSizeValue(pw, mPss << 10); pw.println();
@@ -1055,6 +1079,8 @@
sb.append(" process=").append(mProcessName);
sb.append(" reason=").append(mReason).append(" (")
.append(reasonCodeToString(mReason)).append(")");
+ sb.append(" subreason=").append(mSubReason).append(" (")
+ .append(subreasonToString(mSubReason)).append(")");
sb.append(" status=").append(mStatus);
sb.append(" importance=").append(mImportance);
sb.append(" pss="); DebugUtils.sizeValueToString(mPss << 10, sb);
@@ -1137,6 +1163,10 @@
return "REMOVE LRU";
case SUBREASON_ISOLATED_NOT_NEEDED:
return "ISOLATED NOT NEEDED";
+ case SUBREASON_FREEZER_BINDER_IOCTL:
+ return "FREEZER BINDER IOCTL";
+ case SUBREASON_FREEZER_BINDER_TRANSACTION:
+ return "FREEZER BINDER TRANSACTION";
default:
return "UNKNOWN";
}
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index c752f34..115101c 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -82,9 +82,6 @@
/** Set current process state. */
public abstract void updateProcessState(int processState, boolean fromIpc);
- /** Count how many activities are launching. */
- public abstract void countLaunchingActivities(int num);
-
// Execute phase related logic and handlers. Methods here execute actual lifecycle transactions
// and deliver callbacks.
@@ -193,6 +190,26 @@
FixedRotationAdjustments fixedRotationAdjustments);
/**
+ * Add {@link ActivityClientRecord} that is preparing to be launched.
+ * @param token Activity token.
+ * @param activity An initialized instance of {@link ActivityClientRecord} to use during launch.
+ */
+ public abstract void addLaunchingActivity(IBinder token, ActivityClientRecord activity);
+
+ /**
+ * Get {@link ActivityClientRecord} that is preparing to be launched.
+ * @param token Activity token.
+ * @return An initialized instance of {@link ActivityClientRecord} to use during launch.
+ */
+ public abstract ActivityClientRecord getLaunchingActivity(IBinder token);
+
+ /**
+ * Remove {@link ActivityClientRecord} from the launching activity list.
+ * @param token Activity token.
+ */
+ public abstract void removeLaunchingActivity(IBinder token);
+
+ /**
* Get {@link android.app.ActivityThread.ActivityClientRecord} instance that corresponds to the
* provided token.
*/
diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl
index 9f21bcc..440dd62 100644
--- a/core/java/android/app/IUiModeManager.aidl
+++ b/core/java/android/app/IUiModeManager.aidl
@@ -67,7 +67,6 @@
* 1 - notnight mode
* 2 - night mode
* 3 - automatic mode switching
- * @throws RemoteException
*/
void setApplicationNightMode(in int mode);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 1865141..432d99d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -22,7 +22,6 @@
import static java.util.Objects.requireNonNull;
-import android.annotation.AttrRes;
import android.annotation.ColorInt;
import android.annotation.ColorRes;
import android.annotation.DimenRes;
@@ -36,6 +35,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.StringRes;
+import android.annotation.StyleableRes;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -3314,6 +3314,19 @@
}
/**
+ * Sets the token used for background operations for the pending intents associated with this
+ * notification.
+ *
+ * This token is automatically set during deserialization for you, you usually won't need to
+ * call this unless you want to change the existing token, if any.
+ *
+ * @hide
+ */
+ public void setAllowlistToken(@Nullable IBinder token) {
+ mAllowlistToken = token;
+ }
+
+ /**
* @hide
*/
public static void addFieldsFromContext(Context context, Notification notification) {
@@ -3750,19 +3763,11 @@
private boolean mIsLegacyInitialized;
/**
- * Caches a contrast-enhanced version of {@link #mCachedContrastColorIsFor}.
- */
- private int mCachedContrastColor = COLOR_INVALID;
- private int mCachedContrastColorIsFor = COLOR_INVALID;
-
- /**
* Caches an instance of StandardTemplateParams. Note that this may have been used before,
* so make sure to call {@link StandardTemplateParams#reset()} before using it.
*/
StandardTemplateParams mParams = new StandardTemplateParams();
- private int mTextColorsAreForBackground = COLOR_INVALID;
- private int mPrimaryTextColor = COLOR_INVALID;
- private int mSecondaryTextColor = COLOR_INVALID;
+ Colors mColors = new Colors();
private boolean mTintActionButtons;
private boolean mInNightMode;
@@ -4595,22 +4600,6 @@
}
/**
- * Set to {@code true} to require that the Notification associated with a
- * foreground service is shown as soon as the service's {@code startForeground()}
- * method is called, even if the system's UI policy might otherwise defer
- * its visibility to a later time.
- * @deprecated Use setForegroundServiceBehavior(int) instead
- */
- @Deprecated
- @NonNull
- public Builder setShowForegroundImmediately(boolean showImmediately) {
- setForegroundServiceBehavior(showImmediately
- ? FOREGROUND_SERVICE_IMMEDIATE
- : FOREGROUND_SERVICE_DEFAULT);
- return this;
- }
-
- /**
* Specify a desired visibility policy for a Notification associated with a
* foreground service. By default, the system can choose to defer
* visibility of the notification for a short time after the service is
@@ -5035,7 +5024,7 @@
contentView.setDrawableTint(
R.id.phishing_alert,
false /* targetBackground */,
- getErrorColor(p),
+ getColors(p).getErrorColor(),
PorterDuff.Mode.SRC_ATOP);
}
@@ -5082,8 +5071,8 @@
contentView.setDrawableTint(
R.id.alerted_icon,
false /* targetBackground */,
- getHeaderIconColor(p),
- PorterDuff.Mode.SRC_ATOP);
+ getColors(p).getSecondaryTextColor(),
+ PorterDuff.Mode.SRC_IN);
}
/**
@@ -5211,8 +5200,7 @@
*/
@VisibleForTesting
public @ColorInt int getPrimaryTextColor(StandardTemplateParams p) {
- ensureColors(p);
- return mPrimaryTextColor;
+ return getColors(p).getPrimaryTextColor();
}
/**
@@ -5222,8 +5210,7 @@
*/
@VisibleForTesting
public @ColorInt int getSecondaryTextColor(StandardTemplateParams p) {
- ensureColors(p);
- return mSecondaryTextColor;
+ return getColors(p).getSecondaryTextColor();
}
private void setTextViewColorSecondary(RemoteViews contentView, @IdRes int id,
@@ -5231,29 +5218,9 @@
contentView.setTextColor(id, getSecondaryTextColor(p));
}
- private void ensureColors(StandardTemplateParams p) {
- int backgroundColor = getUnresolvedBackgroundColor(p);
- if (mPrimaryTextColor == COLOR_INVALID
- || mSecondaryTextColor == COLOR_INVALID
- || mTextColorsAreForBackground != backgroundColor) {
- mTextColorsAreForBackground = backgroundColor;
- int defaultPrimaryTextColor = ContrastColorUtil.resolvePrimaryColor(mContext,
- backgroundColor, mInNightMode);
- int defaultSecondaryTextColor = ContrastColorUtil.resolveSecondaryColor(mContext,
- backgroundColor, mInNightMode);
- boolean colorized = backgroundColor != COLOR_DEFAULT;
- if (colorized) {
- mPrimaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
- defaultPrimaryTextColor, backgroundColor, 4.5);
- mSecondaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
- defaultSecondaryTextColor, backgroundColor, 4.5);
- } else {
- mPrimaryTextColor = obtainThemeColor(R.attr.textColorPrimary,
- defaultPrimaryTextColor);
- mSecondaryTextColor = obtainThemeColor(R.attr.textColorSecondary,
- defaultSecondaryTextColor);
- }
- }
+ private Colors getColors(StandardTemplateParams p) {
+ mColors.resolvePalette(mContext, mN.color, isBackgroundColorized(p), mInNightMode);
+ return mColors;
}
private void updateBackgroundColor(RemoteViews contentView,
@@ -5278,7 +5245,7 @@
contentView.setProgressBar(R.id.progress, max, progress, ind);
contentView.setProgressBackgroundTintList(R.id.progress,
mContext.getColorStateList(R.color.notification_progress_background_color));
- ColorStateList progressTint = ColorStateList.valueOf(getAccentColor(p));
+ ColorStateList progressTint = ColorStateList.valueOf(getPrimaryAccentColor(p));
contentView.setProgressTintList(R.id.progress, progressTint);
contentView.setProgressIndeterminateTintList(R.id.progress, progressTint);
return true;
@@ -5412,13 +5379,13 @@
private void bindExpandButton(RemoteViews contentView, StandardTemplateParams p) {
// set default colors
int textColor = getPrimaryTextColor(p);
- int pillColor = getProtectionColor(p);
+ int pillColor = getColors(p).getProtectionColor();
contentView.setInt(R.id.expand_button, "setDefaultTextColor", textColor);
contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor);
// Use different highlighted colors for conversations' unread count
if (p.mHighlightExpander) {
textColor = getBackgroundColor(p);
- pillColor = getAccentColor(p);
+ pillColor = getPrimaryAccentColor(p);
}
contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor);
contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor);
@@ -5731,7 +5698,7 @@
showSpinner ? View.VISIBLE : View.GONE);
big.setProgressIndeterminateTintList(
R.id.notification_material_reply_progress,
- ColorStateList.valueOf(getAccentColor(p)));
+ ColorStateList.valueOf(getPrimaryAccentColor(p)));
if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1].getText())
&& p.maxRemoteInputHistory > 1) {
@@ -6126,7 +6093,7 @@
// change the background bgColor
CharSequence title = action.title;
ColorStateList[] outResultColor = new ColorStateList[1];
- int background = getSecondaryAccentColor(p);
+ int background = getColors(p).getSecondaryAccentColor();
if (isLegacy()) {
title = ContrastColorUtil.clearColorSpans(title);
} else {
@@ -6286,7 +6253,7 @@
if (largeIcon != null && isLegacy()
&& getColorUtil().isGrayscaleIcon(mContext, largeIcon)) {
// resolve color will fall back to the default when legacy
- int color = getContrastColor(p);
+ int color = getSmallIconColor(p);
contentView.setInt(R.id.icon, "setOriginalIconColor", color);
}
}
@@ -6302,14 +6269,7 @@
*/
private @ColorInt int getStandardActionColor(Notification.StandardTemplateParams p) {
return mTintActionButtons || isBackgroundColorized(p)
- ? getAccentColor(p) : getNeutralColor(p);
- }
-
- /**
- * Gets a neutral color that can be used for icons or similar that should not stand out.
- */
- private @ColorInt int getHeaderIconColor(StandardTemplateParams p) {
- return isBackgroundColorized(p) ? getSecondaryTextColor(p) : getNeutralColor(p);
+ ? getPrimaryAccentColor(p) : getSecondaryTextColor(p);
}
/**
@@ -6317,134 +6277,12 @@
* is the primary text color, otherwise it's the contrast-adjusted app-provided color.
*/
private @ColorInt int getSmallIconColor(StandardTemplateParams p) {
- return getContrastColor(p);
+ return getColors(p).getContrastColor();
}
- /**
- * Gets the accent color for colored UI elements. If we're tinting with the theme
- * accent, this is the theme accent color, otherwise this would be identical to
- * {@link #getSmallIconColor(StandardTemplateParams)}.
- */
- private @ColorInt int getAccentColor(StandardTemplateParams p) {
- if (isBackgroundColorized(p)) {
- return getPrimaryTextColor(p);
- }
- int color = obtainThemeColor(R.attr.colorAccent, COLOR_INVALID);
- if (color != COLOR_INVALID) {
- return color;
- }
- return getContrastColor(p);
- }
-
- /**
- * Gets the secondary accent color for colored UI elements. If we're tinting with the theme
- * accent, this is the theme accent color, otherwise this would be identical to
- * {@link #getSmallIconColor(StandardTemplateParams)}.
- */
- private @ColorInt int getSecondaryAccentColor(StandardTemplateParams p) {
- if (isBackgroundColorized(p)) {
- return getSecondaryTextColor(p);
- }
- int color = obtainThemeColor(R.attr.colorAccentSecondary, COLOR_INVALID);
- if (color != COLOR_INVALID) {
- return color;
- }
- return getContrastColor(p);
- }
-
- /**
- * Gets the "surface protection" color from the theme, or a variant of the normal background
- * color when colorized, or when not using theme color tints.
- */
- private @ColorInt int getProtectionColor(StandardTemplateParams p) {
- if (!isBackgroundColorized(p)) {
- int color = obtainThemeColor(R.attr.colorBackgroundFloating, COLOR_INVALID);
- if (color != COLOR_INVALID) {
- return color;
- }
- }
- // TODO(b/181048615): What color should we use for the expander pill when colorized
- return ColorUtils.blendARGB(getPrimaryTextColor(p), getBackgroundColor(p), 0.8f);
- }
-
- /**
- * Gets the theme's error color, or the primary text color for colorized notifications.
- */
- private @ColorInt int getErrorColor(StandardTemplateParams p) {
- if (!isBackgroundColorized(p)) {
- int color = obtainThemeColor(R.attr.colorError, COLOR_INVALID);
- if (color != COLOR_INVALID) {
- return color;
- }
- }
- return getPrimaryTextColor(p);
- }
-
- /**
- * Gets the theme's background color
- */
- private @ColorInt int getDefaultBackgroundColor() {
- return obtainThemeColor(R.attr.colorSurface,
- mInNightMode ? Color.BLACK : Color.WHITE);
- }
-
- /**
- * Gets the contrast-adjusted version of the color provided by the app.
- */
- private @ColorInt int getContrastColor(StandardTemplateParams p) {
- if (isBackgroundColorized(p)) {
- return getPrimaryTextColor(p);
- }
- int rawColor = getRawColor(p);
- if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
- return mCachedContrastColor;
- }
-
- int color;
- // TODO: Maybe use getBackgroundColor(p) instead -- but doing so could break the cache
- int background = getDefaultBackgroundColor();
- if (rawColor == COLOR_DEFAULT) {
- ensureColors(p);
- color = obtainThemeColor(R.attr.colorAccent, COLOR_INVALID);
- if (color == COLOR_INVALID) {
- color = ContrastColorUtil.resolveDefaultColor(mContext, background,
- mInNightMode);
- }
- } else {
- color = ContrastColorUtil.resolveContrastColor(mContext, rawColor,
- background, mInNightMode);
- }
- if (Color.alpha(color) < 255) {
- // alpha doesn't go well for color filters, so let's blend it manually
- color = ContrastColorUtil.compositeColors(color, background);
- }
- mCachedContrastColorIsFor = rawColor;
- return mCachedContrastColor = color;
- }
-
- /**
- * Return the raw color of this Notification, which doesn't necessarily satisfy contrast.
- *
- * @see #getContrastColor(StandardTemplateParams) for the contrasted color
- * @param p the template params to inflate this with
- */
- private @ColorInt int getRawColor(StandardTemplateParams p) {
- return mN.color;
- }
-
- /**
- * Gets a neutral palette color; this is a contrast-satisfied version of the default color.
- * @param p the template params to inflate this with
- */
- private @ColorInt int getNeutralColor(StandardTemplateParams p) {
- int background = getBackgroundColor(p);
- int neutralColor = ContrastColorUtil.resolveDefaultColor(mContext, background,
- mInNightMode);
- if (Color.alpha(neutralColor) < 255) {
- // alpha doesn't go well for color filters, so let's blend it manually
- neutralColor = ContrastColorUtil.compositeColors(neutralColor, background);
- }
- return neutralColor;
+ /** @return the theme's accent color for colored UI elements. */
+ private @ColorInt int getPrimaryAccentColor(StandardTemplateParams p) {
+ return getColors(p).getPrimaryAccentColor();
}
/**
@@ -6590,23 +6428,6 @@
}
/**
- * Returns the color for the given Theme.DeviceDefault.DayNight attribute, or
- * defValue if that could not be completed
- */
- private @ColorInt int obtainThemeColor(@AttrRes int attrRes, @ColorInt int defaultColor) {
- Resources.Theme theme = mContext.getTheme();
- if (theme == null) {
- // Running unit tests with mocked context
- return defaultColor;
- }
- theme = new ContextThemeWrapper(mContext, R.style.Theme_DeviceDefault_DayNight)
- .getTheme();
- try (TypedArray ta = theme.obtainStyledAttributes(new int[]{attrRes})) {
- return ta == null ? defaultColor : ta.getColor(0, defaultColor);
- }
- }
-
- /**
* Apply this Builder to an existing {@link Notification} object.
*
* @hide
@@ -6716,24 +6537,8 @@
return R.layout.notification_material_action_tombstone;
}
- /**
- * Gets the background color, with {@link #COLOR_DEFAULT} being a valid return value,
- * which must be resolved by the caller before being used.
- */
- private @ColorInt int getUnresolvedBackgroundColor(StandardTemplateParams p) {
- return isBackgroundColorized(p) ? getRawColor(p) : COLOR_DEFAULT;
- }
-
- /**
- * Same as {@link #getUnresolvedBackgroundColor(StandardTemplateParams)} except that it
- * also resolves the default color to the background.
- */
private @ColorInt int getBackgroundColor(StandardTemplateParams p) {
- int backgroundColor = getUnresolvedBackgroundColor(p);
- if (backgroundColor == COLOR_DEFAULT) {
- backgroundColor = getDefaultBackgroundColor();
- }
- return backgroundColor;
+ return getColors(p).getBackgroundColor();
}
private boolean textColorsNeedInversion() {
@@ -9115,8 +8920,7 @@
container.setDrawableTint(buttonId, false, tintColor,
PorterDuff.Mode.SRC_ATOP);
- int rippleAlpha = Color.alpha(mBuilder.obtainThemeColor(
- android.R.attr.colorControlHighlight, COLOR_DEFAULT));
+ int rippleAlpha = mBuilder.getColors(p).getRippleAlpha();
int rippleColor = Color.argb(rippleAlpha, Color.red(tintColor), Color.green(tintColor),
Color.blue(tintColor));
container.setRippleDrawableColor(buttonId, ColorStateList.valueOf(rippleColor));
@@ -12447,4 +12251,219 @@
return this;
}
}
+
+ /**
+ * A utility which stores and calculates the palette of colors used to color notifications.
+ * @hide
+ */
+ @VisibleForTesting
+ public static class Colors {
+ private int mPaletteIsForRawColor = COLOR_INVALID;
+ private boolean mPaletteIsForColorized = false;
+ private boolean mPaletteIsForNightMode = false;
+ // The following colors are the palette
+ private int mBackgroundColor = COLOR_INVALID;
+ private int mProtectionColor = COLOR_INVALID;
+ private int mPrimaryTextColor = COLOR_INVALID;
+ private int mSecondaryTextColor = COLOR_INVALID;
+ private int mPrimaryAccentColor = COLOR_INVALID;
+ private int mSecondaryAccentColor = COLOR_INVALID;
+ private int mErrorColor = COLOR_INVALID;
+ private int mContrastColor = COLOR_INVALID;
+ private int mRippleAlpha = 0x33;
+
+ /**
+ * A utility for obtaining a TypedArray of the given DayNight-styled attributes, which
+ * returns null when the context is a mock with no theme.
+ *
+ * NOTE: Calling this method is expensive, as creating a new ContextThemeWrapper
+ * instances can allocate as much as 5MB of memory, so its important to call this method
+ * only when necessary, getting as many attributes as possible from each call.
+ *
+ * @see Resources.Theme#obtainStyledAttributes(int[])
+ */
+ @Nullable
+ private static TypedArray obtainDayNightAttributes(@NonNull Context ctx,
+ @NonNull @StyleableRes int[] attrs) {
+ // when testing, the mock context may have no theme
+ if (ctx.getTheme() == null) {
+ return null;
+ }
+ Resources.Theme theme = new ContextThemeWrapper(ctx,
+ R.style.Theme_DeviceDefault_DayNight).getTheme();
+ return theme.obtainStyledAttributes(attrs);
+ }
+
+ /** A null-safe wrapper of TypedArray.getColor because mocks return null */
+ private static @ColorInt int getColor(@Nullable TypedArray ta, int index,
+ @ColorInt int defValue) {
+ return ta == null ? defValue : ta.getColor(index, defValue);
+ }
+
+ /**
+ * Resolve the palette. If the inputs have not changed, this will be a no-op.
+ * This does not handle invalidating the resolved colors when the context itself changes,
+ * because that case does not happen in the current notification inflation pipeline; we will
+ * recreate a new builder (and thus a new palette) when reinflating notifications for a new
+ * theme (admittedly, we do the same for night mode, but that's easy to check).
+ *
+ * @param ctx the builder context.
+ * @param rawColor the notification's color; may be COLOR_DEFAULT, but may never have alpha.
+ * @param isColorized whether the notification is colorized.
+ * @param nightMode whether the UI is in night mode.
+ */
+ public void resolvePalette(Context ctx, int rawColor,
+ boolean isColorized, boolean nightMode) {
+ if (mPaletteIsForRawColor == rawColor
+ && mPaletteIsForColorized == isColorized
+ && mPaletteIsForNightMode == nightMode) {
+ return;
+ }
+ mPaletteIsForRawColor = rawColor;
+ mPaletteIsForColorized = isColorized;
+ mPaletteIsForNightMode = nightMode;
+
+ if (isColorized) {
+ if (rawColor == COLOR_DEFAULT) {
+ int[] attrs = {R.attr.colorAccentTertiary};
+ try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) {
+ mBackgroundColor = getColor(ta, 0, Color.WHITE);
+ }
+ } else {
+ mBackgroundColor = rawColor;
+ }
+ mProtectionColor = COLOR_INVALID; // filled in at the end
+ mPrimaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
+ ContrastColorUtil.resolvePrimaryColor(ctx, mBackgroundColor, nightMode),
+ mBackgroundColor, 4.5);
+ mSecondaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
+ ContrastColorUtil.resolveSecondaryColor(ctx, mBackgroundColor, nightMode),
+ mBackgroundColor, 4.5);
+ mContrastColor = mPrimaryTextColor;
+ mPrimaryAccentColor = mPrimaryTextColor;
+ mSecondaryAccentColor = mSecondaryTextColor;
+ mErrorColor = mPrimaryTextColor;
+ mRippleAlpha = 0x33;
+ } else {
+ int[] attrs = {
+ R.attr.colorBackground,
+ R.attr.colorBackgroundFloating,
+ R.attr.textColorPrimary,
+ R.attr.textColorSecondary,
+ R.attr.colorAccent,
+ R.attr.colorAccentSecondary,
+ R.attr.colorError,
+ R.attr.colorControlHighlight
+ };
+ try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) {
+ mBackgroundColor = getColor(ta, 0, nightMode ? Color.BLACK : Color.WHITE);
+ mProtectionColor = getColor(ta, 1, COLOR_INVALID);
+ mPrimaryTextColor = getColor(ta, 2, COLOR_INVALID);
+ mSecondaryTextColor = getColor(ta, 3, COLOR_INVALID);
+ mPrimaryAccentColor = getColor(ta, 4, COLOR_INVALID);
+ mSecondaryAccentColor = getColor(ta, 5, COLOR_INVALID);
+ mErrorColor = getColor(ta, 6, COLOR_INVALID);
+ mRippleAlpha = Color.alpha(getColor(ta, 7, 0x33ffffff));
+ }
+ mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor,
+ mBackgroundColor, nightMode);
+
+ // make sure every color has a valid value
+ if (mPrimaryTextColor == COLOR_INVALID) {
+ mPrimaryTextColor = ContrastColorUtil.resolvePrimaryColor(
+ ctx, mBackgroundColor, nightMode);
+ }
+ if (mSecondaryTextColor == COLOR_INVALID) {
+ mSecondaryTextColor = ContrastColorUtil.resolveSecondaryColor(
+ ctx, mBackgroundColor, nightMode);
+ }
+ if (mPrimaryAccentColor == COLOR_INVALID) {
+ mPrimaryAccentColor = mContrastColor;
+ }
+ if (mSecondaryAccentColor == COLOR_INVALID) {
+ mSecondaryAccentColor = mContrastColor;
+ }
+ if (mErrorColor == COLOR_INVALID) {
+ mErrorColor = mPrimaryTextColor;
+ }
+ }
+ // make sure every color has a valid value
+ if (mProtectionColor == COLOR_INVALID) {
+ mProtectionColor = ColorUtils.blendARGB(mPrimaryTextColor, mBackgroundColor, 0.8f);
+ }
+ }
+
+ /** calculates the contrast color for the non-colorized notifications */
+ private static @ColorInt int calculateContrastColor(Context ctx, @ColorInt int rawColor,
+ @ColorInt int accentColor, @ColorInt int backgroundColor, boolean nightMode) {
+ int color;
+ if (rawColor == COLOR_DEFAULT) {
+ color = accentColor;
+ if (color == COLOR_INVALID) {
+ color = ContrastColorUtil.resolveDefaultColor(ctx, backgroundColor, nightMode);
+ }
+ } else {
+ color = ContrastColorUtil.resolveContrastColor(ctx, rawColor, backgroundColor,
+ nightMode);
+ }
+ return flattenAlpha(color, backgroundColor);
+ }
+
+ /** remove any alpha by manually blending it with the given background. */
+ private static @ColorInt int flattenAlpha(@ColorInt int color, @ColorInt int background) {
+ return Color.alpha(color) == 0xff ? color
+ : ContrastColorUtil.compositeColors(color, background);
+ }
+
+ /** @return the notification's background color */
+ public @ColorInt int getBackgroundColor() {
+ return mBackgroundColor;
+ }
+
+ /**
+ * @return the "surface protection" color from the theme,
+ * or a variant of the normal background color when colorized.
+ */
+ public @ColorInt int getProtectionColor() {
+ return mProtectionColor;
+ }
+
+ /** @return the color for the most prominent text */
+ public @ColorInt int getPrimaryTextColor() {
+ return mPrimaryTextColor;
+ }
+
+ /** @return the color for less prominent text */
+ public @ColorInt int getSecondaryTextColor() {
+ return mSecondaryTextColor;
+ }
+
+ /** @return the theme's accent color for colored UI elements. */
+ public @ColorInt int getPrimaryAccentColor() {
+ return mPrimaryAccentColor;
+ }
+
+ /** @return the theme's secondary accent color for colored UI elements. */
+ public @ColorInt int getSecondaryAccentColor() {
+ return mSecondaryAccentColor;
+ }
+
+ /**
+ * @return the contrast-adjusted version of the color provided by the app, or the
+ * primary text color when colorized.
+ */
+ public @ColorInt int getContrastColor() {
+ return mContrastColor;
+ }
+
+ /** @return the theme's error color, or the primary text color when colorized. */
+ public @ColorInt int getErrorColor() {
+ return mErrorColor;
+ }
+
+ /** @return the alpha component of the current theme's control highlight color. */
+ public int getRippleAlpha() {
+ return mRippleAlpha;
+ }
+ }
}
diff --git a/core/java/android/app/RESOURCES_OWNERS b/core/java/android/app/RESOURCES_OWNERS
index 21c39a8..5582803 100644
--- a/core/java/android/app/RESOURCES_OWNERS
+++ b/core/java/android/app/RESOURCES_OWNERS
@@ -1,2 +1,3 @@
rtmitchell@google.com
toddke@google.com
+patb@google.com
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index be62deb7..edd6047 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -101,7 +101,7 @@
// We also check if the image has dark pixels in it,
// to avoid bright images with some dark spots.
private static final float DARK_PIXEL_CONTRAST = 5.5f;
- private static final float MAX_DARK_AREA = 0.025f;
+ private static final float MAX_DARK_AREA = 0.05f;
private final List<Color> mMainColors;
private final Map<Integer, Integer> mAllColors;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index c23cacb..8d74796 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -505,6 +505,13 @@
"android.app.extra.bugreport_notification_type";
/**
+ * Default value for preferential network service enabling.
+ *
+ * @hide
+ */
+ public static final boolean PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT = false;
+
+ /**
* Notification type for a started remote bugreport flow.
*
* @hide
diff --git a/core/java/android/app/search/Query.java b/core/java/android/app/search/Query.java
index 34ace48..c64e107 100644
--- a/core/java/android/app/search/Query.java
+++ b/core/java/android/app/search/Query.java
@@ -37,6 +37,14 @@
public final class Query implements Parcelable {
/**
+ * The lookup key for a integer that indicates what the height of the soft keyboard
+ * (e.g., IME, also known as Input Method Editor) was on the client window
+ * in dp (density-independent pixels). This information is to be used by the consumer
+ * of the API in estimating how many search results will be visible above the keyboard.
+ */
+ public static final String EXTRA_IME_HEIGHT = "android.app.search.extra.IME_HEIGHT";
+
+ /**
* string typed from the client.
*/
@NonNull
@@ -45,7 +53,7 @@
private final long mTimestampMillis;
/**
- * Contains other client UI constraints related data
+ * Contains other client UI constraints related data (e.g., {@link #EXTRA_IME_HEIGHT}.
*/
@NonNull
private final Bundle mExtras;
diff --git a/core/java/android/app/search/SearchTarget.java b/core/java/android/app/search/SearchTarget.java
index 6d638d4..a590a5d 100644
--- a/core/java/android/app/search/SearchTarget.java
+++ b/core/java/android/app/search/SearchTarget.java
@@ -50,7 +50,7 @@
* can recommend which layout this target should be rendered in.
*
* The service can also use fields such as {@link #getScore()} to indicate
- * how confidence the search result is and {@link #shouldHide()} to indicate
+ * how confidence the search result is and {@link #isHidden()} to indicate
* whether it is recommended to be shown by default.
*
* Finally, {@link #getId()} is the unique identifier of this search target and a single
@@ -125,7 +125,7 @@
private final float mScore;
- private final boolean mShouldHide;
+ private final boolean mHidden;
@NonNull
private final String mPackageName;
@@ -149,7 +149,7 @@
mId = parcel.readString();
mParentId = parcel.readString();
mScore = parcel.readFloat();
- mShouldHide = parcel.readBoolean();
+ mHidden = parcel.readBoolean();
mPackageName = parcel.readString();
mUserHandle = UserHandle.of(parcel.readInt());
@@ -165,7 +165,7 @@
@NonNull String layoutType,
@NonNull String id,
@Nullable String parentId,
- float score, boolean shouldHide,
+ float score, boolean hidden,
@NonNull String packageName,
@NonNull UserHandle userHandle,
@Nullable SearchAction action,
@@ -178,7 +178,7 @@
mId = Objects.requireNonNull(id);
mParentId = parentId;
mScore = score;
- mShouldHide = shouldHide;
+ mHidden = hidden;
mPackageName = Objects.requireNonNull(packageName);
mUserHandle = Objects.requireNonNull(userHandle);
mSearchAction = action;
@@ -238,9 +238,20 @@
/**
* Indicates whether this object should be hidden and shown only on demand.
+ *
+ * @deprecated will be removed once SDK drops
+ * @removed
*/
+ @Deprecated
public boolean shouldHide() {
- return mShouldHide;
+ return mHidden;
+ }
+
+ /**
+ * Indicates whether this object should be hidden and shown only on demand.
+ */
+ public boolean isHidden() {
+ return mHidden;
}
/**
@@ -311,7 +322,7 @@
parcel.writeString(mId);
parcel.writeString(mParentId);
parcel.writeFloat(mScore);
- parcel.writeBoolean(mShouldHide);
+ parcel.writeBoolean(mHidden);
parcel.writeString(mPackageName);
parcel.writeInt(mUserHandle.getIdentifier());
parcel.writeTypedObject(mSearchAction, flags);
@@ -351,7 +362,7 @@
@Nullable
private String mParentId;
private float mScore;
- private boolean mShouldHide;
+ private boolean mHidden;
@NonNull
private String mPackageName;
@NonNull
@@ -374,7 +385,7 @@
mLayoutType = Objects.requireNonNull(layoutType);
mResultType = resultType;
mScore = 1f;
- mShouldHide = false;
+ mHidden = false;
}
/**
@@ -473,8 +484,20 @@
* Sets whether the result should be hidden (e.g. not visible) by default inside client.
*/
@NonNull
+ public Builder setHidden(boolean hidden) {
+ mHidden = hidden;
+ return this;
+ }
+
+ /**
+ * Sets whether the result should be hidden by default inside client.
+ * @deprecated will be removed once SDK drops
+ * @removed
+ */
+ @NonNull
+ @Deprecated
public Builder setShouldHide(boolean shouldHide) {
- mShouldHide = shouldHide;
+ mHidden = shouldHide;
return this;
}
@@ -485,7 +508,7 @@
*/
@NonNull
public SearchTarget build() {
- return new SearchTarget(mResultType, mLayoutType, mId, mParentId, mScore, mShouldHide,
+ return new SearchTarget(mResultType, mLayoutType, mId, mParentId, mScore, mHidden,
mPackageName, mUserHandle,
mSearchAction, mShortcutInfo, mSliceUri, mAppWidgetProviderInfo,
mExtras);
diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
index d5585db..032b57e 100644
--- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
+++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
@@ -40,7 +40,8 @@
@Override
public void preExecute(android.app.ClientTransactionHandler client, IBinder token) {
- final ActivityClientRecord r = getActivityClientRecord(client, token);
+ final ActivityClientRecord r = getActivityClientRecord(client, token,
+ true /* includeLaunching */);
// Notify the client of an upcoming change in the token configuration. This ensures that
// batches of config change items only process the newest configuration.
client.updatePendingActivityConfiguration(r, mConfiguration);
diff --git a/core/java/android/app/servertransaction/ActivityTransactionItem.java b/core/java/android/app/servertransaction/ActivityTransactionItem.java
index f7d7e9d..a539812 100644
--- a/core/java/android/app/servertransaction/ActivityTransactionItem.java
+++ b/core/java/android/app/servertransaction/ActivityTransactionItem.java
@@ -55,15 +55,40 @@
@NonNull ActivityClientRecord getActivityClientRecord(
@NonNull ClientTransactionHandler client, IBinder token) {
- final ActivityClientRecord r = client.getActivityClient(token);
+ return getActivityClientRecord(client, token, false /* includeLaunching */);
+ }
+
+ /**
+ * Get the {@link ActivityClientRecord} instance that corresponds to the provided token.
+ * @param client Target client handler.
+ * @param token Target activity token.
+ * @param includeLaunching Indicate to also find the {@link ActivityClientRecord} in launching
+ * activity list. It should be noted that there is no activity in
+ * {@link ActivityClientRecord} from the launching activity list.
+ * @return The {@link ActivityClientRecord} instance that corresponds to the provided token.
+ */
+ @NonNull ActivityClientRecord getActivityClientRecord(
+ @NonNull ClientTransactionHandler client, IBinder token, boolean includeLaunching) {
+ ActivityClientRecord r = client.getActivityClient(token);
+ if (r != null) {
+ if (client.getActivity(token) == null) {
+ throw new IllegalArgumentException("Activity must not be null to execute "
+ + "transaction item");
+ }
+ return r;
+ }
+ // The activity may not be launched yet. Fallback to check launching activity.
+ if (includeLaunching) {
+ r = client.getLaunchingActivity(token);
+ }
if (r == null) {
throw new IllegalArgumentException("Activity client record must not be null to execute "
+ "transaction item");
}
- if (client.getActivity(token) == null) {
- throw new IllegalArgumentException("Activity must not be null to execute "
- + "transaction item");
- }
+
+ // We don't need to check the activity of launching activity client records because they
+ // have not been launched yet.
+
return r;
}
}
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index e281a02..34e4fcd 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -82,7 +82,12 @@
@Override
public void preExecute(ClientTransactionHandler client, IBinder token) {
- client.countLaunchingActivities(1);
+ ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
+ mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
+ mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
+ client, mAssistToken, mFixedRotationAdjustments, mShareableActivityToken,
+ mLaunchedFromBubble);
+ client.addLaunchingActivity(token, r);
client.updateProcessState(mProcState, false);
client.updatePendingConfiguration(mCurConfig);
if (mActivityClientController != null) {
@@ -94,11 +99,7 @@
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
- ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
- mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
- mPendingResults, mPendingNewIntents, mActivityOptions, mIsForward, mProfilerInfo,
- client, mAssistToken, mFixedRotationAdjustments, mShareableActivityToken,
- mLaunchedFromBubble);
+ ActivityClientRecord r = client.getLaunchingActivity(token);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -106,7 +107,7 @@
@Override
public void postExecute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
- client.countLaunchingActivities(-1);
+ client.removeLaunchingActivity(token);
}
diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java
index 944367e..4b8a347 100644
--- a/core/java/android/app/servertransaction/MoveToDisplayItem.java
+++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java
@@ -40,7 +40,8 @@
@Override
public void preExecute(ClientTransactionHandler client, IBinder token) {
- final ActivityClientRecord r = getActivityClientRecord(client, token);
+ final ActivityClientRecord r = getActivityClientRecord(client, token,
+ true /* includeLaunching */);
// Notify the client of an upcoming change in the token configuration. This ensures that
// batches of config change items only process the newest configuration.
client.updatePendingActivityConfiguration(r, mConfiguration);
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index e6ffded..b99ad51 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -442,13 +442,18 @@
/**
* Associates given device with given app for the given user directly, without UI prompt.
*
+ * @param packageName package name of the companion app
+ * @param macAddress mac address of the device to associate
+ * @param certificate The SHA256 digest of the companion app's signing certificate
+ *
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES)
public void associate(
@NonNull String packageName,
- @NonNull MacAddress macAddress) {
+ @NonNull MacAddress macAddress,
+ @NonNull byte[] certificate) {
if (!checkFeaturePresent()) {
return;
}
@@ -458,7 +463,7 @@
UserHandle user = android.os.Process.myUserHandle();
try {
mService.createAssociation(
- packageName, macAddress.toString(), user.getIdentifier());
+ packageName, macAddress.toString(), user.getIdentifier(), certificate);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
index cc3749c..d113b92 100644
--- a/core/java/android/companion/ICompanionDeviceManager.aidl
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -52,5 +52,6 @@
boolean canPairWithoutPrompt(in String packageName, in String deviceMacAddress, int userId);
- void createAssociation(in String packageName, in String macAddress, int userId);
+ void createAssociation(in String packageName, in String macAddress, int userId,
+ in byte[] certificate);
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fc676cf..886cd7f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -400,10 +400,7 @@
public static final int BIND_BYPASS_POWER_NETWORK_RESTRICTIONS = 0x00020000;
/**
- * Flag for {@link #bindService}: allow background foreground service starts from the bound
- * service's process.
- * This flag is only respected if the caller is holding
- * {@link android.Manifest.permission#START_FOREGROUND_SERVICES_FROM_BACKGROUND}.
+ * Do not use. This flag is no longer needed nor used.
* @hide
*/
@SystemApi
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index a436fa4..688483a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1983,7 +1983,7 @@
* activities that are not properly protected.
*
* <p>
- * Input: {@link android.Manifest.permission_group} specifies the permission group
+ * Input: {@link #EXTRA_PERMISSION_GROUP_NAME} specifies the permission group
* for which the launched UI would be targeted.
* </p>
* <p>
@@ -2013,12 +2013,12 @@
* Input: {@link #EXTRA_ATTRIBUTION_TAGS} specifies the attribution tags for the usage entry.
* </p>
* <p>
- * Input: {@link #EXTRA_START_TIME} specifies the start time of the period. Both start time and
- * end time are needed and start time must be <= end time.
+ * Input: {@link #EXTRA_START_TIME} specifies the start time of the period (epoch time in
+ * millis). Both start time and end time are needed and start time must be <= end time.
* </p>
* <p>
- * Input: {@link #EXTRA_END_TIME} specifies the end time of the period. Both start time and end
- * time are needed and start time must be <= end time.
+ * Input: {@link #EXTRA_END_TIME} specifies the end time of the period (epoch time in
+ * millis). Both start time and end time are needed and start time must be <= end time.
* </p>
* <p>
* Output: Nothing.
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 03f6380..af5f9ce 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1348,7 +1348,8 @@
public boolean neverSandboxDisplayApis() {
return CompatChanges.isChangeEnabled(NEVER_SANDBOX_DISPLAY_APIS,
applicationInfo.packageName,
- UserHandle.getUserHandleForUid(applicationInfo.uid));
+ UserHandle.getUserHandleForUid(applicationInfo.uid))
+ || ConstrainDisplayApisConfig.neverConstrainDisplayApis(applicationInfo);
}
/**
diff --git a/core/java/android/content/pm/ConstrainDisplayApisConfig.java b/core/java/android/content/pm/ConstrainDisplayApisConfig.java
new file mode 100644
index 0000000..1337347
--- /dev/null
+++ b/core/java/android/content/pm/ConstrainDisplayApisConfig.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS;
+
+import android.provider.DeviceConfig;
+import android.util.Slog;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Class for processing flags in the Device Config namespace 'constrain_display_apis'.
+ *
+ * @hide
+ */
+public final class ConstrainDisplayApisConfig {
+ private static final String TAG = ConstrainDisplayApisConfig.class.getSimpleName();
+
+ /**
+ * A string flag whose value holds a comma separated list of package entries in the format
+ * '<package-name>:<min-version-code>?:<max-version-code>?' for which Display APIs should never
+ * be constrained.
+ */
+ private static final String FLAG_NEVER_CONSTRAIN_DISPLAY_APIS = "never_constrain_display_apis";
+
+ /**
+ * A boolean flag indicating whether Display APIs should never be constrained for all
+ * packages. If true, {@link #FLAG_NEVER_CONSTRAIN_DISPLAY_APIS} is ignored.
+ */
+ private static final String FLAG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES =
+ "never_constrain_display_apis_all_packages";
+
+ /**
+ * Returns true if either the flag 'never_constrain_display_apis_all_packages' is true or the
+ * flag 'never_constrain_display_apis' contains a package entry that matches the given {@code
+ * applicationInfo}.
+ *
+ * @param applicationInfo Information about the application/package.
+ */
+ public static boolean neverConstrainDisplayApis(ApplicationInfo applicationInfo) {
+ if (DeviceConfig.getBoolean(NAMESPACE_CONSTRAIN_DISPLAY_APIS,
+ FLAG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES, /* defaultValue= */ false)) {
+ return true;
+ }
+ String configStr = DeviceConfig.getString(NAMESPACE_CONSTRAIN_DISPLAY_APIS,
+ FLAG_NEVER_CONSTRAIN_DISPLAY_APIS, /* defaultValue= */ "");
+
+ // String#split returns a non-empty array given an empty string.
+ if (configStr.isEmpty()) {
+ return false;
+ }
+
+ for (String packageEntryString : configStr.split(",")) {
+ if (matchesApplicationInfo(packageEntryString, applicationInfo)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Parses the given {@code packageEntryString} and returns true if {@code
+ * applicationInfo.packageName} matches the package name in the config and {@code
+ * applicationInfo.longVersionCode} is within the version range in the config.
+ *
+ * <p>Logs a warning and returns false in case the given {@code packageEntryString} is invalid.
+ *
+ * @param packageEntryStr A package entry expected to be in the format
+ * '<package-name>:<min-version-code>?:<max-version-code>?'.
+ * @param applicationInfo Information about the application/package.
+ */
+ private static boolean matchesApplicationInfo(String packageEntryStr,
+ ApplicationInfo applicationInfo) {
+ List<String> packageAndVersions = Arrays.asList(packageEntryStr.split(":", 3));
+ if (packageAndVersions.size() != 3) {
+ Slog.w(TAG, "Invalid package entry in flag 'never_constrain_display_apis': "
+ + packageEntryStr);
+ return false;
+ }
+ String packageName = packageAndVersions.get(0);
+ String minVersionCodeStr = packageAndVersions.get(1);
+ String maxVersionCodeStr = packageAndVersions.get(2);
+
+ if (!packageName.equals(applicationInfo.packageName)) {
+ return false;
+ }
+ long version = applicationInfo.longVersionCode;
+ try {
+ if (!minVersionCodeStr.isEmpty() && version < Long.parseLong(minVersionCodeStr)) {
+ return false;
+ }
+ if (!maxVersionCodeStr.isEmpty() && version > Long.parseLong(maxVersionCodeStr)) {
+ return false;
+ }
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Invalid APK version code in package entry: " + packageEntryStr);
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 33606e8..33a34be 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4672,27 +4672,27 @@
@PermissionGroupInfoFlags int flags);
/**
- * Get the platform permissions which belong to a particular permission group.
+ * Get the platform-defined permissions which belong to a particular permission group.
*
- * @param permissionGroupName The permission group whose permissions are desired
- * @param executor Executor on which to invoke the callback
- * @param callback A callback which will receive a list of the platform permissions in the
- * group, or empty if the group is not a valid platform group, or there
- * was an exception.
+ * @param permissionGroupName the permission group whose permissions are desired
+ * @param executor the {@link Executor} on which to invoke the callback
+ * @param callback the callback which will receive a list of the platform-defined permissions in
+ * the group, or empty if the group is not a valid platform-defined permission
+ * group, or there was an exception
*/
public void getPlatformPermissionsForGroup(@NonNull String permissionGroupName,
@NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<List<String>> callback) {}
/**
- * Get the platform group of a particular permission, if the permission is a platform
- * permission.
+ * Get the platform-defined permission group of a particular permission, if the permission is a
+ * platform-defined permission.
*
- * @param permissionName The permission name whose group is desired
- * @param executor Executor on which to invoke the callback
- * @param callback A callback which will receive the name of the permission group this
- * permission belongs to, or null if it has no group, is not a platform
- * permission, or there was an exception.
+ * @param permissionName the permission whose group is desired
+ * @param executor the {@link Executor} on which to invoke the callback
+ * @param callback the callback which will receive the name of the permission group this
+ * permission belongs to, or {@code null} if it has no group, is not a
+ * platform-defined permission, or there was an exception
*/
public void getGroupOfPlatformPermission(@NonNull String permissionName,
@NonNull @CallbackExecutor Executor executor, @NonNull Consumer<String> callback) {}
diff --git a/core/java/android/ddm/DdmHandle.java b/core/java/android/ddm/DdmHandle.java
new file mode 100644
index 0000000..0505fee
--- /dev/null
+++ b/core/java/android/ddm/DdmHandle.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.ddm;
+
+import org.apache.harmony.dalvik.ddmc.ChunkHandler;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Contains utility methods for chunk serialization and deserialization.
+ */
+public abstract class DdmHandle extends ChunkHandler {
+
+ /**
+ * Utility function to copy a String out of a ByteBuffer.
+ *
+ * This is here because multiple chunk handlers can make use of it,
+ * and there's nowhere better to put it.
+ */
+ public static String getString(ByteBuffer buf, int len) {
+ char[] data = new char[len];
+ for (int i = 0; i < len; i++) {
+ data[i] = buf.getChar();
+ }
+ return new String(data);
+ }
+
+ /**
+ * Utility function to copy a String into a ByteBuffer.
+ */
+ public static void putString(ByteBuffer buf, String str) {
+ int len = str.length();
+ for (int i = 0; i < len; i++) {
+ buf.putChar(str.charAt(i));
+ }
+ }
+
+}
diff --git a/core/java/android/ddm/DdmHandleAppName.java b/core/java/android/ddm/DdmHandleAppName.java
index 35da062..e19f19f 100644
--- a/core/java/android/ddm/DdmHandleAppName.java
+++ b/core/java/android/ddm/DdmHandleAppName.java
@@ -30,9 +30,9 @@
/**
* Track our app name. We don't (currently) handle any inbound packets.
*/
-public class DdmHandleAppName extends ChunkHandler {
+public class DdmHandleAppName extends DdmHandle {
- public static final int CHUNK_APNM = type("APNM");
+ public static final int CHUNK_APNM = ChunkHandler.type("APNM");
private static volatile Names sNames = new Names("", "");
@@ -51,13 +51,13 @@
* Called when the DDM server connects. The handler is allowed to
* send messages to the server.
*/
- public void connected() {}
+ public void onConnected() {}
/**
* Called when the DDM server disconnects. Can be used to disable
* periodic transmissions or clean up saved state.
*/
- public void disconnected() {}
+ public void onDisconnected() {}
/**
* Handle a chunk of data.
diff --git a/core/java/android/ddm/DdmHandleExit.java b/core/java/android/ddm/DdmHandleExit.java
index 74ae37a..a9e3d16 100644
--- a/core/java/android/ddm/DdmHandleExit.java
+++ b/core/java/android/ddm/DdmHandleExit.java
@@ -16,18 +16,20 @@
package android.ddm;
+import android.util.Log;
+
import org.apache.harmony.dalvik.ddmc.Chunk;
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
import org.apache.harmony.dalvik.ddmc.DdmServer;
-import android.util.Log;
+
import java.nio.ByteBuffer;
/**
* Handle an EXIT chunk.
*/
-public class DdmHandleExit extends ChunkHandler {
+public class DdmHandleExit extends DdmHandle {
- public static final int CHUNK_EXIT = type("EXIT");
+ public static final int CHUNK_EXIT = ChunkHandler.type("EXIT");
private static DdmHandleExit mInstance = new DdmHandleExit();
@@ -46,13 +48,13 @@
* Called when the DDM server connects. The handler is allowed to
* send messages to the server.
*/
- public void connected() {}
+ public void onConnected() {}
/**
* Called when the DDM server disconnects. Can be used to disable
* periodic transmissions or clean up saved state.
*/
- public void disconnected() {}
+ public void onDisconnected() {}
/**
* Handle a chunk of data. We're only registered for "EXIT".
diff --git a/core/java/android/ddm/DdmHandleHeap.java b/core/java/android/ddm/DdmHandleHeap.java
index 8fa2352..2edb5c7 100644
--- a/core/java/android/ddm/DdmHandleHeap.java
+++ b/core/java/android/ddm/DdmHandleHeap.java
@@ -16,21 +16,18 @@
package android.ddm;
+import android.util.Log;
+
import org.apache.harmony.dalvik.ddmc.Chunk;
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
import org.apache.harmony.dalvik.ddmc.DdmServer;
-import org.apache.harmony.dalvik.ddmc.DdmVmInternal;
-import android.os.Debug;
-import android.util.Log;
-import java.io.IOException;
-import java.nio.ByteBuffer;
/**
* Handle native and virtual heap requests.
*/
-public class DdmHandleHeap extends ChunkHandler {
+public class DdmHandleHeap extends DdmHandle {
- public static final int CHUNK_HPGC = type("HPGC");
+ public static final int CHUNK_HPGC = ChunkHandler.type("HPGC");
private static DdmHandleHeap mInstance = new DdmHandleHeap();
@@ -49,13 +46,13 @@
* Called when the DDM server connects. The handler is allowed to
* send messages to the server.
*/
- public void connected() {}
+ public void onConnected() {}
/**
* Called when the DDM server disconnects. Can be used to disable
* periodic transmissions or clean up saved state.
*/
- public void disconnected() {}
+ public void onDisconnected() {}
/**
* Handle a chunk of data.
@@ -68,8 +65,7 @@
if (type == CHUNK_HPGC) {
return handleHPGC(request);
} else {
- throw new RuntimeException("Unknown packet "
- + ChunkHandler.name(type));
+ throw new RuntimeException("Unknown packet " + name(type));
}
}
diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java
index 60dfc8d..4160029 100644
--- a/core/java/android/ddm/DdmHandleHello.java
+++ b/core/java/android/ddm/DdmHandleHello.java
@@ -31,11 +31,11 @@
/**
* Handle "hello" messages and feature discovery.
*/
-public class DdmHandleHello extends ChunkHandler {
+public class DdmHandleHello extends DdmHandle {
- public static final int CHUNK_HELO = type("HELO");
- public static final int CHUNK_WAIT = type("WAIT");
- public static final int CHUNK_FEAT = type("FEAT");
+ public static final int CHUNK_HELO = ChunkHandler.type("HELO");
+ public static final int CHUNK_WAIT = ChunkHandler.type("WAIT");
+ public static final int CHUNK_FEAT = ChunkHandler.type("FEAT");
private static final int CLIENT_PROTOCOL_VERSION = 1;
@@ -61,15 +61,14 @@
* Called when the DDM server connects. The handler is allowed to
* send messages to the server.
*/
- public void connected() {
+ public void onConnected() {
if (false)
Log.v("ddm-hello", "Connected!");
if (false) {
/* test spontaneous transmission */
byte[] data = new byte[] { 0, 1, 2, 3, 4, -4, -3, -2, -1, 127 };
- Chunk testChunk =
- new Chunk(ChunkHandler.type("TEST"), data, 1, data.length-2);
+ Chunk testChunk = new Chunk(ChunkHandler.type("TEST"), data, 1, data.length - 2);
DdmServer.sendChunk(testChunk);
}
}
@@ -78,7 +77,7 @@
* Called when the DDM server disconnects. Can be used to disable
* periodic transmissions or clean up saved state.
*/
- public void disconnected() {
+ public void onDisconnected() {
if (false)
Log.v("ddm-hello", "Disconnected!");
}
@@ -96,8 +95,7 @@
} else if (type == CHUNK_FEAT) {
return handleFEAT(request);
} else {
- throw new RuntimeException("Unknown packet "
- + ChunkHandler.name(type));
+ throw new RuntimeException("Unknown packet " + name(type));
}
}
diff --git a/core/java/android/ddm/DdmHandleNativeHeap.java b/core/java/android/ddm/DdmHandleNativeHeap.java
index 775c570..dfd451c 100644
--- a/core/java/android/ddm/DdmHandleNativeHeap.java
+++ b/core/java/android/ddm/DdmHandleNativeHeap.java
@@ -16,17 +16,18 @@
package android.ddm;
+import android.util.Log;
+
import org.apache.harmony.dalvik.ddmc.Chunk;
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
import org.apache.harmony.dalvik.ddmc.DdmServer;
-import android.util.Log;
/**
* Handle thread-related traffic.
*/
-public class DdmHandleNativeHeap extends ChunkHandler {
+public class DdmHandleNativeHeap extends DdmHandle {
- public static final int CHUNK_NHGT = type("NHGT");
+ public static final int CHUNK_NHGT = ChunkHandler.type("NHGT");
private static DdmHandleNativeHeap mInstance = new DdmHandleNativeHeap();
@@ -45,13 +46,13 @@
* Called when the DDM server connects. The handler is allowed to
* send messages to the server.
*/
- public void connected() {}
+ public void onConnected() {}
/**
* Called when the DDM server disconnects. Can be used to disable
* periodic transmissions or clean up saved state.
*/
- public void disconnected() {}
+ public void onDisconnected() {}
/**
* Handle a chunk of data.
@@ -63,8 +64,7 @@
if (type == CHUNK_NHGT) {
return handleNHGT(request);
} else {
- throw new RuntimeException("Unknown packet "
- + ChunkHandler.name(type));
+ throw new RuntimeException("Unknown packet " + name(type));
}
}
diff --git a/core/java/android/ddm/DdmHandleProfiling.java b/core/java/android/ddm/DdmHandleProfiling.java
index cce4dd2..806e4bd 100644
--- a/core/java/android/ddm/DdmHandleProfiling.java
+++ b/core/java/android/ddm/DdmHandleProfiling.java
@@ -16,25 +16,28 @@
package android.ddm;
+
+import android.os.Debug;
+import android.util.Log;
+
import org.apache.harmony.dalvik.ddmc.Chunk;
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
import org.apache.harmony.dalvik.ddmc.DdmServer;
-import android.os.Debug;
-import android.util.Log;
+
import java.nio.ByteBuffer;
/**
* Handle profiling requests.
*/
-public class DdmHandleProfiling extends ChunkHandler {
+public class DdmHandleProfiling extends DdmHandle {
- public static final int CHUNK_MPRS = type("MPRS");
- public static final int CHUNK_MPRE = type("MPRE");
- public static final int CHUNK_MPSS = type("MPSS");
- public static final int CHUNK_MPSE = type("MPSE");
- public static final int CHUNK_MPRQ = type("MPRQ");
- public static final int CHUNK_SPSS = type("SPSS");
- public static final int CHUNK_SPSE = type("SPSE");
+ public static final int CHUNK_MPRS = ChunkHandler.type("MPRS");
+ public static final int CHUNK_MPRE = ChunkHandler.type("MPRE");
+ public static final int CHUNK_MPSS = ChunkHandler.type("MPSS");
+ public static final int CHUNK_MPSE = ChunkHandler.type("MPSE");
+ public static final int CHUNK_MPRQ = ChunkHandler.type("MPRQ");
+ public static final int CHUNK_SPSS = ChunkHandler.type("SPSS");
+ public static final int CHUNK_SPSE = ChunkHandler.type("SPSE");
private static final boolean DEBUG = false;
private static DdmHandleProfiling mInstance = new DdmHandleProfiling();
@@ -60,13 +63,13 @@
* Called when the DDM server connects. The handler is allowed to
* send messages to the server.
*/
- public void connected() {}
+ public void onConnected() {}
/**
* Called when the DDM server disconnects. Can be used to disable
* periodic transmissions or clean up saved state.
*/
- public void disconnected() {}
+ public void onDisconnected() {}
/**
* Handle a chunk of data.
@@ -91,8 +94,7 @@
} else if (type == CHUNK_SPSE) {
return handleMPSEOrSPSE(request, "Sample");
} else {
- throw new RuntimeException("Unknown packet "
- + ChunkHandler.name(type));
+ throw new RuntimeException("Unknown packet " + name(type));
}
}
diff --git a/core/java/android/ddm/DdmHandleViewDebug.java b/core/java/android/ddm/DdmHandleViewDebug.java
index 5539dc9..6b0f78f 100644
--- a/core/java/android/ddm/DdmHandleViewDebug.java
+++ b/core/java/android/ddm/DdmHandleViewDebug.java
@@ -39,12 +39,12 @@
* Handle various requests related to profiling / debugging of the view system.
* Support for these features are advertised via {@link DdmHandleHello}.
*/
-public class DdmHandleViewDebug extends ChunkHandler {
+public class DdmHandleViewDebug extends DdmHandle {
/** List {@link ViewRootImpl}'s of this process. */
- private static final int CHUNK_VULW = type("VULW");
+ private static final int CHUNK_VULW = ChunkHandler.type("VULW");
/** Operation on view root, first parameter in packet should be one of VURT_* constants */
- private static final int CHUNK_VURT = type("VURT");
+ private static final int CHUNK_VURT = ChunkHandler.type("VURT");
/** Dump view hierarchy. */
private static final int VURT_DUMP_HIERARCHY = 1;
@@ -59,7 +59,7 @@
* Generic View Operation, first parameter in the packet should be one of the
* VUOP_* constants below.
*/
- private static final int CHUNK_VUOP = type("VUOP");
+ private static final int CHUNK_VUOP = ChunkHandler.type("VUOP");
/** Capture View. */
private static final int VUOP_CAPTURE_VIEW = 1;
@@ -99,11 +99,11 @@
}
@Override
- public void connected() {
+ public void onConnected() {
}
@Override
- public void disconnected() {
+ public void onDisconnected() {
}
@Override
@@ -154,7 +154,7 @@
return createFailChunk(ERR_INVALID_OP, "Unknown view operation: " + op);
}
} else {
- throw new RuntimeException("Unknown packet " + ChunkHandler.name(type));
+ throw new RuntimeException("Unknown packet " + name(type));
}
}
diff --git a/core/java/android/hardware/ISensorPrivacyManager.aidl b/core/java/android/hardware/ISensorPrivacyManager.aidl
index a71bb09..1c8e959 100644
--- a/core/java/android/hardware/ISensorPrivacyManager.aidl
+++ b/core/java/android/hardware/ISensorPrivacyManager.aidl
@@ -33,6 +33,8 @@
void removeSensorPrivacyListener(in ISensorPrivacyListener listener);
+ void removeIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
+
boolean isSensorPrivacyEnabled();
boolean isIndividualSensorPrivacyEnabled(int userId, int sensor);
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index fc0204a..1a5e5a8 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -286,13 +286,15 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
- public void removeSensorPrivacyListener(@NonNull OnSensorPrivacyChangedListener listener) {
+ public void removeSensorPrivacyListener(@Sensors.Sensor int sensor,
+ @NonNull OnSensorPrivacyChangedListener listener) {
synchronized (mListeners) {
for (int i = 0; i < mIndividualListeners.size(); i++) {
Pair<OnSensorPrivacyChangedListener, Integer> pair = mIndividualListeners.keyAt(i);
- if (pair.first.equals(listener)) {
+ if (pair.second == sensor && pair.first.equals(listener)) {
try {
- mService.removeSensorPrivacyListener(mIndividualListeners.valueAt(i));
+ mService.removeIndividualSensorPrivacyListener(sensor,
+ mIndividualListeners.valueAt(i));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
index 83e273a..fe43c83 100644
--- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
@@ -53,9 +53,6 @@
// authentication or removal. Must agree with the list in HAL h file
//
- /**
- * @hide
- */
@IntDef({FACE_ERROR_HW_UNAVAILABLE,
FACE_ERROR_UNABLE_TO_PROCESS,
FACE_ERROR_TIMEOUT,
@@ -110,8 +107,6 @@
/**
* The {@link FaceManager#remove} call failed. Typically this will happen when the
* provided face id was incorrect.
- *
- * @hide
*/
int FACE_ERROR_UNABLE_TO_REMOVE = 6;
@@ -160,8 +155,6 @@
/**
* The user pressed the negative button. This is a placeholder that is currently only used
* by the support library.
- *
- * @hide
*/
int FACE_ERROR_NEGATIVE_BUTTON = 13;
@@ -177,24 +170,23 @@
* security update has addressed this issue. This error can be received if for example,
* authentication was requested with {@link Authenticators#BIOMETRIC_STRONG}, but the
* sensor's strength can currently only meet {@link Authenticators#BIOMETRIC_WEAK}.
- * @hide
*/
int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15;
/**
* Authentication cannot proceed because re-enrollment is required.
- * @hide
*/
int BIOMETRIC_ERROR_RE_ENROLL = 16;
/**
* Unknown error received from the HAL.
- * @hide
*/
int FACE_ERROR_UNKNOWN = 17;
/**
- * @hide
+ * Vendor codes received from the HAL start at 0. Codes that the framework exposes to keyguard
+ * append this value for some reason. We should probably remove this and just send the actual
+ * vendor code.
*/
int FACE_ERROR_VENDOR_BASE = 1000;
@@ -203,9 +195,6 @@
// existing constants. These must agree with face@1.0/types.hal.
//
- /**
- * @hide
- */
@IntDef({FACE_ACQUIRED_GOOD,
FACE_ACQUIRED_INSUFFICIENT,
FACE_ACQUIRED_TOO_BRIGHT,
@@ -229,7 +218,10 @@
FACE_ACQUIRED_START,
FACE_ACQUIRED_SENSOR_DIRTY,
FACE_ACQUIRED_VENDOR,
- FACE_ACQUIRED_UNKNOWN})
+ FACE_ACQUIRED_UNKNOWN,
+ FACE_ACQUIRED_FIRST_FRAME_RECEIVED,
+ FACE_ACQUIRED_DARK_GLASSES_DETECTED,
+ FACE_ACQUIRED_MOUTH_COVERING_DETECTED})
@Retention(RetentionPolicy.SOURCE)
@interface FaceAcquired {}
@@ -402,19 +394,35 @@
/**
* Hardware vendors may extend this list if there are conditions that do not fall under one of
* the above categories. Vendors are responsible for providing error strings for these errors.
- *
- * @hide
*/
int FACE_ACQUIRED_VENDOR = 22;
/**
* Unknown acquired code received from the HAL.
- * @hide
*/
int FACE_ACQUIRED_UNKNOWN = 23;
/**
- * @hide
+ * The first frame from the camera has been received.
+ */
+ int FACE_ACQUIRED_FIRST_FRAME_RECEIVED = 24;
+
+ /**
+ * Dark glasses detected. This can be useful for providing relevant feedback to the user and
+ * enabling an alternative authentication logic if the implementation supports it.
+ */
+ int FACE_ACQUIRED_DARK_GLASSES_DETECTED = 25;
+
+ /**
+ * A face mask or face covering detected. This can be useful for providing relevant feedback to
+ * the user and enabling an alternative authentication logic if the implementation supports it.
+ */
+ int FACE_ACQUIRED_MOUTH_COVERING_DETECTED = 26;
+
+ /**
+ * Vendor codes received from the HAL start at 0. Codes that the framework exposes to keyguard
+ * append this value for some reason. We should probably remove this and just send the actual
+ * vendor code.
*/
int FACE_ACQUIRED_VENDOR_BASE = 1000;
}
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index f3a8342..0ec508a 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -34,7 +34,6 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.util.Slog;
@@ -98,6 +97,27 @@
public @interface BiometricError {}
/**
+ * Single sensor or unspecified multi-sensor behavior (prefer an explicit choice if the
+ * device is multi-sensor).
+ * @hide
+ */
+ public static final int BIOMETRIC_MULTI_SENSOR_DEFAULT = 0;
+
+ /**
+ * Prefer the face sensor and fall back to fingerprint when needed.
+ * @hide
+ */
+ public static final int BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT = 1;
+
+ /**
+ * @hide
+ */
+ @IntDef({BIOMETRIC_MULTI_SENSOR_DEFAULT,
+ BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface BiometricMultiSensorMode {}
+
+ /**
* Types of authenticators, defined at a level of granularity supported by
* {@link BiometricManager} and {@link BiometricPrompt}.
*
diff --git a/core/java/android/hardware/biometrics/BiometricTestSession.java b/core/java/android/hardware/biometrics/BiometricTestSession.java
index 41672b7..c62680f 100644
--- a/core/java/android/hardware/biometrics/BiometricTestSession.java
+++ b/core/java/android/hardware/biometrics/BiometricTestSession.java
@@ -23,7 +23,6 @@
import android.annotation.RequiresPermission;
import android.annotation.TestApi;
import android.content.Context;
-import android.hardware.fingerprint.FingerprintManager;
import android.os.RemoteException;
import android.util.ArraySet;
import android.util.Log;
@@ -248,6 +247,12 @@
}
}
+ if (!mUsersCleaningUp.isEmpty()) {
+ // TODO(b/186600837): this seems common on multi sensor devices
+ Log.e(getTag(), "Cleanup not finished before shutdown - pending: "
+ + mUsersCleaningUp.size());
+ }
+
// Disable the test HAL after the sensor becomes idle.
setTestHalEnabled(false);
}
diff --git a/core/java/android/hardware/biometrics/IBiometricSysuiReceiver.aidl b/core/java/android/hardware/biometrics/IBiometricSysuiReceiver.aidl
index 492ceeb..5d9b5f3 100644
--- a/core/java/android/hardware/biometrics/IBiometricSysuiReceiver.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricSysuiReceiver.aidl
@@ -28,6 +28,8 @@
void onDeviceCredentialPressed();
// Notifies the client that an internal event, e.g. back button has occurred.
void onSystemEvent(int event);
- // Notifies that the dialog has finished animating in.
+ // Notifies that the dialog has finished animating.
void onDialogAnimatedIn();
+ // For multi-sensor devices, notifies that the fingerprint should start now.
+ void onStartFingerprintNow();
}
diff --git a/core/java/android/hardware/face/FaceDataFrame.java b/core/java/android/hardware/face/FaceDataFrame.java
index 092359c..4dbfc85 100644
--- a/core/java/android/hardware/face/FaceDataFrame.java
+++ b/core/java/android/hardware/face/FaceDataFrame.java
@@ -17,6 +17,7 @@
package android.hardware.face;
import android.annotation.NonNull;
+import android.hardware.biometrics.BiometricFaceConstants;
import android.os.Parcel;
import android.os.Parcelable;
@@ -26,7 +27,7 @@
* @hide
*/
public final class FaceDataFrame implements Parcelable {
- private final int mAcquiredInfo;
+ @BiometricFaceConstants.FaceAcquired private final int mAcquiredInfo;
private final int mVendorCode;
private final float mPan;
private final float mTilt;
@@ -48,7 +49,7 @@
* @param isCancellable Whether the ongoing face operation should be canceled.
*/
public FaceDataFrame(
- int acquiredInfo,
+ @BiometricFaceConstants.FaceAcquired int acquiredInfo,
int vendorCode,
float pan,
float tilt,
@@ -69,7 +70,7 @@
* @param vendorCode An integer representing a custom vendor-specific message. Ignored unless
* {@code acquiredInfo} is {@code FACE_ACQUIRED_VENDOR}.
*/
- public FaceDataFrame(int acquiredInfo, int vendorCode) {
+ public FaceDataFrame(@BiometricFaceConstants.FaceAcquired int acquiredInfo, int vendorCode) {
mAcquiredInfo = acquiredInfo;
mVendorCode = vendorCode;
mPan = 0f;
@@ -83,6 +84,7 @@
*
* @see android.hardware.biometrics.BiometricFaceConstants
*/
+ @BiometricFaceConstants.FaceAcquired
public int getAcquiredInfo() {
return mAcquiredInfo;
}
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 55c90ce..12557f9 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -1449,6 +1449,8 @@
case FACE_ACQUIRED_ROLL_TOO_EXTREME:
return context.getString(R.string.face_acquired_roll_too_extreme);
case FACE_ACQUIRED_FACE_OBSCURED:
+ case FACE_ACQUIRED_DARK_GLASSES_DETECTED:
+ case FACE_ACQUIRED_MOUTH_COVERING_DETECTED:
return context.getString(R.string.face_acquired_obscured);
case FACE_ACQUIRED_SENSOR_DIRTY:
return context.getString(R.string.face_acquired_sensor_dirty);
diff --git a/core/java/android/hardware/lights/Light.java b/core/java/android/hardware/lights/Light.java
index 2812868..dbe7a41 100644
--- a/core/java/android/hardware/lights/Light.java
+++ b/core/java/android/hardware/lights/Light.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -41,36 +42,52 @@
/**
* Type for lights that indicate a monochrome color LED light.
*/
- public static final int LIGHT_TYPE_INPUT_SINGLE = 10001;
+ public static final int LIGHT_TYPE_INPUT = 10001;
/**
- * Type for lights that indicate a group of LED lights representing player ID.
- * Player ID lights normally present on game controllers are lights that consist of a row of
+ * Type for lights that indicate a group of LED lights representing player id.
+ * Player id lights normally present on game controllers are lights that consist of a row of
* LEDs.
- * During multi-player game, the player ID for the current game controller is represented by
+ * During multi-player game, the player id for the current game controller is represented by
* one of the LED that is lit according to its position in the row.
*/
- public static final int LIGHT_TYPE_INPUT_PLAYER_ID = 10002;
+ public static final int LIGHT_TYPE_PLAYER_ID = 10002;
/**
- * Type for lights that indicate a color LED light.
+ * Capability for lights that could adjust its LED brightness. If the capability is not present
+ * the led can only be turned either on or off.
*/
- public static final int LIGHT_TYPE_INPUT_RGB = 10003;
+ public static final int LIGHT_CAPABILITY_BRIGHTNESS = 1 << 0;
+
+ /**
+ * Capability for lights that has red, green and blue LEDs to control the light's color.
+ */
+ public static final int LIGHT_CAPABILITY_RGB = 0 << 1;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"LIGHT_TYPE_"},
value = {
- LIGHT_TYPE_INPUT_PLAYER_ID,
- LIGHT_TYPE_INPUT_SINGLE,
- LIGHT_TYPE_INPUT_RGB,
+ LIGHT_TYPE_MICROPHONE,
+ LIGHT_TYPE_INPUT,
+ LIGHT_TYPE_PLAYER_ID,
})
public @interface LightType {}
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = {"LIGHT_CAPABILITY_"},
+ value = {
+ LIGHT_CAPABILITY_BRIGHTNESS,
+ LIGHT_CAPABILITY_RGB,
+ })
+ public @interface LightCapability {}
+
private final int mId;
+ private final String mName;
private final int mOrdinal;
private final int mType;
- private final String mName;
+ private final int mCapabilities;
/**
* Creates a new light with the given data.
@@ -78,7 +95,7 @@
* @hide
*/
public Light(int id, int ordinal, int type) {
- this(id, ordinal, type, "Light");
+ this(id, "Light", ordinal, type, 0);
}
/**
@@ -86,27 +103,30 @@
*
* @hide
*/
- public Light(int id, int ordinal, int type, String name) {
+ public Light(int id, String name, int ordinal, int type, int capabilities) {
mId = id;
+ mName = name;
mOrdinal = ordinal;
mType = type;
- mName = name;
+ mCapabilities = capabilities;
}
private Light(@NonNull Parcel in) {
mId = in.readInt();
+ mName = in.readString();
mOrdinal = in.readInt();
mType = in.readInt();
- mName = in.readString();
+ mCapabilities = in.readInt();
}
/** Implement the Parcelable interface */
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mId);
+ dest.writeString(mName);
dest.writeInt(mOrdinal);
dest.writeInt(mType);
- dest.writeString(mName);
+ dest.writeInt(mCapabilities);
}
/** Implement the Parcelable interface */
@@ -131,7 +151,8 @@
public boolean equals(@Nullable Object obj) {
if (obj instanceof Light) {
Light light = (Light) obj;
- return mId == light.mId && mOrdinal == light.mOrdinal && mType == light.mType;
+ return mId == light.mId && mOrdinal == light.mOrdinal && mType == light.mType
+ && mCapabilities == light.mCapabilities;
}
return false;
}
@@ -143,7 +164,8 @@
@Override
public String toString() {
- return "[Name=" + mName + " Id=" + mId + " Type=" + mType + " Ordinal=" + mOrdinal + "]";
+ return "[Name=" + mName + " Id=" + mId + " Type=" + mType + " Capabilities="
+ + mCapabilities + " Ordinal=" + mOrdinal + "]";
}
/**
@@ -177,7 +199,35 @@
/**
* Returns the logical type of the light.
*/
- public @LightsManager.LightType int getType() {
+ public @LightType int getType() {
return mType;
}
+
+ /**
+ * Returns the capabilities of the light.
+ * @hide
+ */
+ @TestApi
+ public @LightCapability int getCapabilities() {
+ return mCapabilities;
+ }
+
+ /**
+ * Check whether the light has led brightness control.
+ *
+ * @return True if the hardware can control the led brightness, otherwise false.
+ */
+ public boolean hasBrightnessControl() {
+ return (mCapabilities & LIGHT_CAPABILITY_BRIGHTNESS) == LIGHT_CAPABILITY_BRIGHTNESS;
+ }
+
+ /**
+ * Check whether the light has RGB led control.
+ *
+ * @return True if the hardware can control the RGB led, otherwise false.
+ */
+ public boolean hasRgbControl() {
+ return (mCapabilities & LIGHT_CAPABILITY_RGB) == LIGHT_CAPABILITY_RGB;
+ }
+
}
diff --git a/core/java/android/hardware/lights/LightState.java b/core/java/android/hardware/lights/LightState.java
index c6d7f63..8b31e88 100644
--- a/core/java/android/hardware/lights/LightState.java
+++ b/core/java/android/hardware/lights/LightState.java
@@ -43,7 +43,7 @@
* of RBG color or monochrome color.
*
* @param color the desired color and intensity in ARGB format.
- * @deprecated this has been replaced with {@link android.hardware.lights.LightState#forColor }
+ * @deprecated this has been replaced with {@link android.hardware.lights.LightState.Builder }
* @hide
*/
@Deprecated
@@ -54,8 +54,8 @@
/**
* Creates a new LightState with the desired color and intensity, and the player Id.
- * Player Id will only be applied on Light type
- * {@link android.hardware.lights.Light#LIGHT_TYPE_INPUT_PLAYER_ID}
+ * Player Id will only be applied on Light with type
+ * {@link android.hardware.lights.Light#LIGHT_TYPE_PLAYER_ID}
*
* @param color the desired color and intensity in ARGB format.
* @hide
@@ -94,8 +94,8 @@
}
/**
- * Set the desired player id of the LightState Builder, for a light of type
- * {@link android.hardware.lights.Light#LIGHT_TYPE_INPUT_PLAYER_ID}.
+ * Set the desired player id of the LightState Builder, for a light with type
+ * {@link android.hardware.lights.Light#LIGHT_TYPE_PLAYER_ID}.
*
* @param playerId the desired player id.
* @return The {@link LightState.Builder} object contains the player id.
@@ -134,15 +134,16 @@
/**
* Returns the color and intensity associated with this LightState.
* @return the color and intensity in ARGB format. The A channel is ignored. return 0 when
- * calling LightsManager.getLightState with LIGHT_TYPE_INPUT_PLAYER_ID.
+ * calling LightsManager.getLightState with
+ * {@link android.hardware.lights.Light#LIGHT_TYPE_PLAYER_ID}.
*/
public @ColorInt int getColor() {
return mColor;
}
/**
- * Returns the player ID associated with this LightState for Light type
- * {@link android.hardware.lights.Light#LIGHT_TYPE_INPUT_PLAYER_ID},
+ * Returns the player ID associated with this LightState for Light with type
+ * {@link android.hardware.lights.Light#LIGHT_TYPE_PLAYER_ID},
* or 0 for other types.
* @return the player ID.
*/
diff --git a/core/java/android/hardware/lights/LightsRequest.java b/core/java/android/hardware/lights/LightsRequest.java
index 8d27dfd..256bd14 100644
--- a/core/java/android/hardware/lights/LightsRequest.java
+++ b/core/java/android/hardware/lights/LightsRequest.java
@@ -18,12 +18,10 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
-import android.util.SparseArray;
import com.android.internal.util.Preconditions;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -34,58 +32,48 @@
public final class LightsRequest {
/** Visible to {@link LightsManager.Session}. */
- final int[] mLightIds;
-
- /** Visible to {@link LightsManager.Session}. */
- final LightState[] mLightStates;
+ final Map<Light, LightState> mRequests = new HashMap<>();
+ final List<Integer> mLightIds = new ArrayList<>();
+ final List<LightState> mLightStates = new ArrayList<>();
/**
* Can only be constructed via {@link LightsRequest.Builder#build()}.
*/
- private LightsRequest(SparseArray<LightState> changes) {
- final int n = changes.size();
- mLightIds = new int[n];
- mLightStates = new LightState[n];
- for (int i = 0; i < n; i++) {
- mLightIds[i] = changes.keyAt(i);
- mLightStates[i] = changes.valueAt(i);
+ private LightsRequest(Map<Light, LightState> requests) {
+ mRequests.putAll(requests);
+ List<Light> lights = new ArrayList<Light>(mRequests.keySet());
+ for (int i = 0; i < lights.size(); i++) {
+ final Light light = lights.get(i);
+ mLightIds.add(i, light.getId());
+ mLightStates.add(i, mRequests.get(light));
}
}
/**
- * Get a list of Light as ids. The ids will returned in same order as the lights passed
- * in Builder.
+ * Get a list of Light as ids.
*
- * @return List of light ids
+ * @return List of light ids in the request.
*/
public @NonNull List<Integer> getLights() {
- List<Integer> lightList = new ArrayList<Integer>(mLightIds.length);
- for (int i = 0; i < mLightIds.length; i++) {
- lightList.add(mLightIds[i]);
- }
- return lightList;
+ return mLightIds;
}
/**
- * Get a list of LightState. The states will be returned in same order as the light states
- * passed in Builder.
+ * Get a list of LightState. The states will be returned in same order as the light ids
+ * returned by {@link #getLights()}.
*
* @return List of light states
*/
public @NonNull List<LightState> getLightStates() {
- return Arrays.asList(mLightStates);
+ return mLightStates;
}
/**
- * Get a map of light ids and states. The map will contain all the light ids as keys and
+ * Get a map of lights and states. The map will contain all the lights as keys and
* the corresponding LightState requested as values.
*/
- public @NonNull Map<Integer, LightState> getLightsAndStates() {
- Map<Integer, LightState> map = new HashMap<>();
- for (int i = 0; i < mLightIds.length; i++) {
- map.put(mLightIds[i], mLightStates[i]);
- }
- return map;
+ public @NonNull Map<Light, LightState> getLightsAndStates() {
+ return mRequests;
}
/**
@@ -93,8 +81,7 @@
*/
public static final class Builder {
- private final SparseArray<LightState> mChanges = new SparseArray<>();
-
+ final Map<Light, LightState> mChanges = new HashMap<>();
/**
* Overrides the color and intensity of a given light.
*
@@ -104,7 +91,7 @@
public @NonNull Builder addLight(@NonNull Light light, @NonNull LightState state) {
Preconditions.checkNotNull(light);
Preconditions.checkNotNull(state);
- mChanges.put(light.getId(), state);
+ mChanges.put(light, state);
return this;
}
@@ -129,7 +116,7 @@
*/
public @NonNull Builder clearLight(@NonNull Light light) {
Preconditions.checkNotNull(light);
- mChanges.put(light.getId(), null);
+ mChanges.put(light, null);
return this;
}
diff --git a/core/java/android/hardware/lights/SystemLightsManager.java b/core/java/android/hardware/lights/SystemLightsManager.java
index da034ee..d0df611 100644
--- a/core/java/android/hardware/lights/SystemLightsManager.java
+++ b/core/java/android/hardware/lights/SystemLightsManager.java
@@ -163,7 +163,17 @@
Preconditions.checkNotNull(request);
if (!mClosed) {
try {
- mService.setLightStates(getToken(), request.mLightIds, request.mLightStates);
+ List<Integer> idList = request.getLights();
+ List<LightState> stateList = request.getLightStates();
+ int[] ids = new int[idList.size()];
+ for (int i = 0; i < idList.size(); i++) {
+ ids[i] = idList.get(i);
+ }
+ LightState[] states = new LightState[stateList.size()];
+ for (int i = 0; i < stateList.size(); i++) {
+ states[i] = stateList.get(i);
+ }
+ mService.setLightStates(getToken(), ids, states);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index f0d410f..881e0cf 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -481,6 +481,7 @@
boolean mFullscreenApplied;
boolean mIsFullscreen;
+ private boolean mLastWasInFullscreenMode;
@UnsupportedAppUsage
View mExtractView;
boolean mExtractViewHidden;
@@ -920,8 +921,17 @@
if (mHandler == null) {
mHandler = new Handler(getMainLooper());
}
- mImeSurfaceScheduledForRemoval = true;
- mHandler.postDelayed(() -> removeImeSurface(), TIMEOUT_SURFACE_REMOVAL_MILLIS);
+
+ if (mLastWasInFullscreenMode) {
+ // Caching surface / delaying surface removal can cause mServedView to detach in certain
+ // cases in RecyclerView (b/187772544).
+ // TODO(b/188818557): Re-enable IME surface caching for fullscreen mode once detaching
+ // view issues is resolved in RecyclerView.
+ removeImeSurface();
+ } else {
+ mImeSurfaceScheduledForRemoval = true;
+ mHandler.postDelayed(() -> removeImeSurface(), TIMEOUT_SURFACE_REMOVAL_MILLIS);
+ }
}
private void removeImeSurface() {
@@ -2350,6 +2360,7 @@
onWindowHidden();
mDecorViewWasVisible = false;
}
+ mLastWasInFullscreenMode = mIsFullscreen;
updateFullscreenMode();
}
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index cc1312b..b18e9be 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -16,6 +16,16 @@
package android.net;
+import static android.net.IpSecAlgorithm.AUTH_AES_CMAC;
+import static android.net.IpSecAlgorithm.AUTH_AES_XCBC;
+import static android.net.IpSecAlgorithm.AUTH_CRYPT_AES_GCM;
+import static android.net.IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305;
+import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA256;
+import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA384;
+import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA512;
+import static android.net.IpSecAlgorithm.CRYPT_AES_CBC;
+import static android.net.IpSecAlgorithm.CRYPT_AES_CTR;
+
import static com.android.internal.annotations.VisibleForTesting.Visibility;
import static com.android.internal.util.Preconditions.checkStringNotEmpty;
import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
@@ -70,13 +80,28 @@
private static final String EMPTY_CERT = "";
/** @hide */
- public static final List<String> DEFAULT_ALGORITHMS =
- Collections.unmodifiableList(Arrays.asList(
- IpSecAlgorithm.CRYPT_AES_CBC,
- IpSecAlgorithm.AUTH_HMAC_SHA256,
- IpSecAlgorithm.AUTH_HMAC_SHA384,
- IpSecAlgorithm.AUTH_HMAC_SHA512,
- IpSecAlgorithm.AUTH_CRYPT_AES_GCM));
+ public static final List<String> DEFAULT_ALGORITHMS;
+
+ private static void addAlgorithmIfSupported(List<String> algorithms, String ipSecAlgoName) {
+ if (IpSecAlgorithm.getSupportedAlgorithms().contains(ipSecAlgoName)) {
+ algorithms.add(ipSecAlgoName);
+ }
+ }
+
+ static {
+ final List<String> algorithms = new ArrayList<>();
+ addAlgorithmIfSupported(algorithms, CRYPT_AES_CBC);
+ addAlgorithmIfSupported(algorithms, CRYPT_AES_CTR);
+ addAlgorithmIfSupported(algorithms, AUTH_HMAC_SHA256);
+ addAlgorithmIfSupported(algorithms, AUTH_HMAC_SHA384);
+ addAlgorithmIfSupported(algorithms, AUTH_HMAC_SHA512);
+ addAlgorithmIfSupported(algorithms, AUTH_AES_XCBC);
+ addAlgorithmIfSupported(algorithms, AUTH_AES_CMAC);
+ addAlgorithmIfSupported(algorithms, AUTH_CRYPT_AES_GCM);
+ addAlgorithmIfSupported(algorithms, AUTH_CRYPT_CHACHA20_POLY1305);
+
+ DEFAULT_ALGORITHMS = Collections.unmodifiableList(algorithms);
+ }
@NonNull private final String mServerAddr;
@NonNull private final String mUserIdentity;
@@ -195,8 +220,6 @@
* @param allowedAlgorithms The list to be validated
*/
private static void validateAllowedAlgorithms(@NonNull List<String> algorithmNames) {
- VpnProfile.validateAllowedAlgorithms(algorithmNames);
-
// First, make sure no insecure algorithms were proposed.
if (algorithmNames.contains(IpSecAlgorithm.AUTH_HMAC_MD5)
|| algorithmNames.contains(IpSecAlgorithm.AUTH_HMAC_SHA1)) {
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index 370052d..f2857ce 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -368,27 +368,19 @@
};
/** Returns a proto (as used for atoms.proto) corresponding to this BatteryUsageStats. */
- public byte[] getStatsProto(long sessionEndTimestampMs) {
-
- final long sessionStartMillis = getStatsStartTimestamp();
- // TODO(b/187223764): Use the getStatsEndTimestamp() instead, once that is added.
- final long sessionEndMillis = sessionEndTimestampMs;
- final long sessionDurationMillis = sessionEndTimestampMs - getStatsStartTimestamp();
-
+ public byte[] getStatsProto() {
final BatteryConsumer deviceBatteryConsumer = getAggregateBatteryConsumer(
AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE);
- final int sessionDischargePercentage = getDischargePercentage();
-
final ProtoOutputStream proto = new ProtoOutputStream();
- proto.write(BatteryUsageStatsAtomsProto.SESSION_START_MILLIS, sessionStartMillis);
- proto.write(BatteryUsageStatsAtomsProto.SESSION_END_MILLIS, sessionEndMillis);
- proto.write(BatteryUsageStatsAtomsProto.SESSION_DURATION_MILLIS, sessionDurationMillis);
+ proto.write(BatteryUsageStatsAtomsProto.SESSION_START_MILLIS, getStatsStartTimestamp());
+ proto.write(BatteryUsageStatsAtomsProto.SESSION_END_MILLIS, getStatsEndTimestamp());
+ proto.write(BatteryUsageStatsAtomsProto.SESSION_DURATION_MILLIS, getStatsDuration());
deviceBatteryConsumer.writeStatsProto(proto,
BatteryUsageStatsAtomsProto.DEVICE_BATTERY_CONSUMER);
writeUidBatteryConsumersProto(proto);
proto.write(BatteryUsageStatsAtomsProto.SESSION_DISCHARGE_PERCENTAGE,
- sessionDischargePercentage);
+ getDischargePercentage());
return proto.getBytes();
}
@@ -399,8 +391,8 @@
private void writeUidBatteryConsumersProto(ProtoOutputStream proto) {
final List<UidBatteryConsumer> consumers = getUidBatteryConsumers();
- // TODO: Sort the list by power consumption. If during the for, proto.getRawSize() > 45kb,
- // truncate the remainder of the list.
+ // TODO(b/189225426): Sort the list by power consumption. If during the for,
+ // proto.getRawSize() > 45kb, truncate the remainder of the list.
final int size = consumers.size();
for (int i = 0; i < size; i++) {
final UidBatteryConsumer consumer = consumers.get(i);
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 2a9b703..d44b016 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -565,8 +565,7 @@
}
try {
- boolean replyOwnsNative = (reply == null) ? false : reply.ownsNativeParcelObject();
- return transactNative(code, data, reply, replyOwnsNative, flags);
+ return transactNative(code, data, reply, flags);
} finally {
if (transactListener != null) {
transactListener.onTransactEnded(session);
@@ -589,7 +588,7 @@
* Native implementation of transact() for proxies
*/
public native boolean transactNative(int code, Parcel data, Parcel reply,
- boolean replyOwnsNativeParcelObject, int flags) throws RemoteException;
+ int flags) throws RemoteException;
/**
* See {@link IBinder#linkToDeath(DeathRecipient, int)}
*/
diff --git a/core/java/android/os/HidlMemory.java b/core/java/android/os/HidlMemory.java
index 26fc6f0..2539a6b 100644
--- a/core/java/android/os/HidlMemory.java
+++ b/core/java/android/os/HidlMemory.java
@@ -79,6 +79,7 @@
public void close() throws IOException {
if (mHandle != null) {
mHandle.close();
+ mHandle = null;
}
}
diff --git a/core/java/android/os/HidlMemoryUtil.java b/core/java/android/os/HidlMemoryUtil.java
index 4252fe3..a1b2aef 100644
--- a/core/java/android/os/HidlMemoryUtil.java
+++ b/core/java/android/os/HidlMemoryUtil.java
@@ -76,8 +76,7 @@
return new HidlMemory("ashmem", 0, null);
}
- try {
- SharedMemory shmem = SharedMemory.create(name != null ? name : "", input.length);
+ try (SharedMemory shmem = SharedMemory.create(name != null ? name : "", input.length)) {
ByteBuffer buffer = shmem.mapReadWrite();
buffer.put(input);
shmem.unmap(buffer);
@@ -119,8 +118,7 @@
return new HidlMemory("ashmem", 0, null);
}
- try {
- SharedMemory shmem = SharedMemory.create(name != null ? name : "", input.size());
+ try (SharedMemory shmem = SharedMemory.create(name != null ? name : "", input.size())) {
ByteBuffer buffer = shmem.mapReadWrite();
for (Byte b : input) {
buffer.put(b);
@@ -214,8 +212,12 @@
if (fd == null) {
return new HidlMemory("ashmem", 0, null);
}
- NativeHandle handle = new NativeHandle(fd, true);
- return new HidlMemory("ashmem", size, handle);
+ try {
+ NativeHandle handle = new NativeHandle(Os.dup(fd), true);
+ return new HidlMemory("ashmem", size, handle);
+ } catch (ErrnoException e) {
+ throw new RuntimeException(e);
+ }
}
private static ByteBuffer getBuffer(@NonNull HidlMemory mem) {
diff --git a/packages/Connectivity/framework/aidl-export/android/net/QosSession.aidl b/core/java/android/os/PackageTagsList.aidl
similarity index 83%
rename from packages/Connectivity/framework/aidl-export/android/net/QosSession.aidl
rename to core/java/android/os/PackageTagsList.aidl
index c2cf366..ac2c4e4 100644
--- a/packages/Connectivity/framework/aidl-export/android/net/QosSession.aidl
+++ b/core/java/android/os/PackageTagsList.aidl
@@ -1,6 +1,4 @@
-/*
-**
-** Copyright (C) 2020 The Android Open Source Project
+/* Copyright 2018, 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.
@@ -15,7 +13,6 @@
** limitations under the License.
*/
-package android.net;
+package android.os;
-parcelable QosSession;
-
+parcelable PackageTagsList;
diff --git a/core/java/android/os/PackageTagsList.java b/core/java/android/os/PackageTagsList.java
new file mode 100644
index 0000000..c94d3de
--- /dev/null
+++ b/core/java/android/os/PackageTagsList.java
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.TestApi;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import java.io.PrintWriter;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * A list of packages and associated attribution tags that supports easy membership checks.
+ *
+ * @hide
+ */
+@TestApi
+public final class PackageTagsList implements Parcelable {
+
+ // an empty set value matches any attribution tag
+ private final ArrayMap<String, ArraySet<String>> mPackageTags;
+
+ private PackageTagsList(@NonNull ArrayMap<String, ArraySet<String>> packageTags) {
+ mPackageTags = Objects.requireNonNull(packageTags);
+ }
+
+ /**
+ * Returns true if this instance is empty;
+ */
+ public boolean isEmpty() {
+ return mPackageTags.isEmpty();
+ }
+
+ /**
+ * Returns true if the given package is represented within this instance. If this returns true
+ * this does not imply anything about whether any given attribution tag under the given package
+ * name is present.
+ */
+ public boolean includes(@NonNull String packageName) {
+ return mPackageTags.containsKey(packageName);
+ }
+
+ /**
+ * Returns true if all attribution tags under the given package are contained within this
+ * instance.
+ */
+ public boolean containsAll(@NonNull String packageName) {
+ Set<String> tags = mPackageTags.get(packageName);
+ return tags != null && tags.isEmpty();
+ }
+
+ /**
+ * Returns true if the given package and attribution tag are contained within this instance.
+ */
+ public boolean contains(@NonNull String packageName, @Nullable String attributionTag) {
+ Set<String> tags = mPackageTags.get(packageName);
+ if (tags == null) {
+ return false;
+ } else if (tags.isEmpty()) {
+ return true;
+ } else {
+ return tags.contains(attributionTag);
+ }
+ }
+
+ /**
+ * Returns true if the given PackageTagsList is a subset of this instance.
+ */
+ public boolean contains(@NonNull PackageTagsList packageTagsList) {
+ int otherSize = packageTagsList.mPackageTags.size();
+ if (otherSize > mPackageTags.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < otherSize; i++) {
+ String packageName = packageTagsList.mPackageTags.keyAt(i);
+ ArraySet<String> tags = mPackageTags.get(packageName);
+ if (tags == null) {
+ return false;
+ }
+ if (tags.isEmpty()) {
+ continue;
+ }
+ ArraySet<String> otherTags = packageTagsList.mPackageTags.valueAt(i);
+ if (otherTags.isEmpty()) {
+ return false;
+ }
+ if (!tags.containsAll(otherTags)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static final @NonNull Parcelable.Creator<PackageTagsList> CREATOR =
+ new Parcelable.Creator<PackageTagsList>() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public PackageTagsList createFromParcel(Parcel in) {
+ int count = in.readInt();
+ ArrayMap<String, ArraySet<String>> packageTags = new ArrayMap<>(count);
+ for (int i = 0; i < count; i++) {
+ String key = in.readString8();
+ ArraySet<String> value = (ArraySet<String>) in.readArraySet(null);
+ packageTags.append(key, value);
+ }
+ return new PackageTagsList(packageTags);
+ }
+
+ @Override
+ public PackageTagsList[] newArray(int size) {
+ return new PackageTagsList[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(@NonNull Parcel parcel, int flags) {
+ int count = mPackageTags.size();
+ parcel.writeInt(count);
+ for (int i = 0; i < count; i++) {
+ parcel.writeString8(mPackageTags.keyAt(i));
+ parcel.writeArraySet(mPackageTags.valueAt(i));
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof PackageTagsList)) {
+ return false;
+ }
+
+ PackageTagsList that = (PackageTagsList) o;
+ return mPackageTags.equals(that.mPackageTags);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPackageTags);
+ }
+
+ @Override
+ public @NonNull String toString() {
+ return mPackageTags.toString();
+ }
+
+ /**
+ * @hide
+ */
+ public void dump(PrintWriter pw) {
+ int size = mPackageTags.size();
+ for (int i = 0; i < size; i++) {
+ String packageName = mPackageTags.keyAt(i);
+ pw.print(packageName);
+ pw.print("[");
+ int tagsSize = mPackageTags.valueAt(i).size();
+ if (tagsSize == 0) {
+ pw.print("*");
+ } else {
+ for (int j = 0; j < tagsSize; j++) {
+ String attributionTag = mPackageTags.valueAt(i).valueAt(j);
+ if (j > 0) {
+ pw.print(", ");
+ }
+ if (attributionTag.startsWith(packageName)) {
+ pw.print(attributionTag.substring(packageName.length()));
+ } else {
+ pw.print(attributionTag);
+ }
+ }
+ }
+ pw.println("]");
+ }
+ }
+
+ /**
+ * Builder class for {@link PackageTagsList}.
+ */
+ public static final class Builder {
+
+ private final ArrayMap<String, ArraySet<String>> mPackageTags;
+
+ /**
+ * Creates a new builder.
+ */
+ public Builder() {
+ mPackageTags = new ArrayMap<>();
+ }
+
+ /**
+ * Creates a new builder with the given initial capacity.
+ */
+ public Builder(int capacity) {
+ mPackageTags = new ArrayMap<>(capacity);
+ }
+
+ /**
+ * Adds all attribution tags under the specified package to the builder.
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public @NonNull Builder add(@NonNull String packageName) {
+ mPackageTags.computeIfAbsent(packageName, p -> new ArraySet<>()).clear();
+ return this;
+ }
+
+ /**
+ * Adds the specified package and attribution tag to the builder.
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public @NonNull Builder add(@NonNull String packageName, @Nullable String attributionTag) {
+ ArraySet<String> tags = mPackageTags.get(packageName);
+ if (tags == null) {
+ tags = new ArraySet<>(1);
+ tags.add(attributionTag);
+ mPackageTags.put(packageName, tags);
+ } else if (!tags.isEmpty()) {
+ tags.add(attributionTag);
+ }
+
+ return this;
+ }
+
+ /**
+ * Adds the specified {@link PackageTagsList} to the builder.
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public @NonNull Builder add(@NonNull PackageTagsList packageTagsList) {
+ return add(packageTagsList.mPackageTags);
+ }
+
+ /**
+ * Adds the given map of package to attribution tags to the builder. An empty set of
+ * attribution tags is interpreted to imply all attribution tags under that package.
+ */
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public @NonNull Builder add(@NonNull Map<String, ? extends Set<String>> packageTagsMap) {
+ mPackageTags.ensureCapacity(packageTagsMap.size());
+ for (Map.Entry<String, ? extends Set<String>> entry : packageTagsMap.entrySet()) {
+ Set<String> newTags = entry.getValue();
+ if (newTags.isEmpty()) {
+ add(entry.getKey());
+ } else {
+ ArraySet<String> tags = mPackageTags.get(entry.getKey());
+ if (tags == null) {
+ tags = new ArraySet<>(newTags);
+ mPackageTags.put(entry.getKey(), tags);
+ } else if (!tags.isEmpty()) {
+ tags.addAll(newTags);
+ }
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Clears the builder.
+ */
+ public @NonNull Builder clear() {
+ mPackageTags.clear();
+ return this;
+ }
+
+ /**
+ * Constructs a new {@link PackageTagsList}.
+ */
+ public @NonNull PackageTagsList build() {
+ return new PackageTagsList(copy(mPackageTags));
+ }
+
+ private static ArrayMap<String, ArraySet<String>> copy(
+ ArrayMap<String, ArraySet<String>> value) {
+ int size = value.size();
+ ArrayMap<String, ArraySet<String>> copy = new ArrayMap<>(size);
+ for (int i = 0; i < size; i++) {
+ String packageName = value.keyAt(i);
+ ArraySet<String> tags = new ArraySet<>(Objects.requireNonNull(value.valueAt(i)));
+ copy.append(packageName, tags);
+ }
+ return copy;
+ }
+ }
+}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 50f390b..e06e7b6 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -3736,9 +3736,4 @@
public long getBlobAshmemSize() {
return nativeGetBlobAshmemSize(mNativePtr);
}
-
- /** @hide */
- /*package*/ boolean ownsNativeParcelObject() {
- return mOwnsNativeParcelObject;
- }
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 5848d2f..224cd84 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -189,28 +189,6 @@
public @interface QuietModeFlag {}
/**
- * Flag returned by {@link #getUserPrivacySensitivity} to indicate that the user isn't
- * particularly sensitive about a certain aspect of privacy.
- */
- public static final int PRIVACY_SENSITIVITY_DEFAULT = 0x0;
-
- /**
- * Flag returned by {@link #getUserPrivacySensitivity} to indicate that the user is sensitive
- * about location privacy.
- */
- public static final int PRIVACY_SENSITIVITY_LOCATION = 0x1;
-
- /**
- * List of flags available for the {@link #getUserPrivacySensitivity} method.
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, prefix = { "PRIVACY_SENSITIVITY_" }, value = {
- PRIVACY_SENSITIVITY_DEFAULT,
- PRIVACY_SENSITIVITY_LOCATION})
- public @interface PrivacySensitivityFlag {}
-
- /**
* @hide
* No user restriction.
*/
@@ -3960,17 +3938,6 @@
}
/**
- * Get the privacy sensitivity of the user.
- *
- * @return the privacy sensitivity of the user
- */
- @PrivacySensitivityFlag
- public int getUserPrivacySensitivity() {
- // TODO: Add actual implementation.
- return PRIVACY_SENSITIVITY_DEFAULT;
- }
-
- /**
* Returns whether the given user has a badge (generally to put on profiles' icons).
*
* @param userId userId of the user in question
diff --git a/core/java/android/os/VibratorManager.java b/core/java/android/os/VibratorManager.java
index 01cece3..c82a516 100644
--- a/core/java/android/os/VibratorManager.java
+++ b/core/java/android/os/VibratorManager.java
@@ -94,6 +94,8 @@
* VibrationEffect VibrationEffects} to be played on one or more vibrators.
* </p>
*
+ * <p>The app should be in foreground for the vibration to happen.</p>
+ *
* @param effect a combination of effects to be performed by one or more vibrators.
*/
@RequiresPermission(android.Manifest.permission.VIBRATE)
@@ -109,6 +111,9 @@
* VibrationEffect} to be played on one or more vibrators.
* </p>
*
+ * <p>The app should be in foreground for the vibration to happen. Background apps should
+ * specify a ringtone, notification or alarm usage in order to vibrate.</p>
+ *
* @param effect a combination of effects to be performed by one or more vibrators.
* @param attributes {@link VibrationAttributes} corresponding to the vibration. For example,
* specify {@link VibrationAttributes#USAGE_ALARM} for alarm vibrations or
diff --git a/core/java/android/os/incremental/OWNERS b/core/java/android/os/incremental/OWNERS
index 3795493..47eee64 100644
--- a/core/java/android/os/incremental/OWNERS
+++ b/core/java/android/os/incremental/OWNERS
@@ -3,3 +3,4 @@
schfan@google.com
toddke@google.com
zyy@google.com
+patb@google.com
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 3daa3a5..0c0d70c 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -258,6 +258,14 @@
public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler";
/**
+ * Namespace for all location related features.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_LOCATION = "location";
+
+ /**
* Namespace for all media related features.
*
* @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3f5fc05..e3302d1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10986,10 +10986,12 @@
/**
* Packages that are whitelisted for ignoring location settings (may retrieve location even
* when user location settings are off), for emergency purposes.
+ * @deprecated No longer used from Android 12+
* @hide
*/
@TestApi
@Readable
+ @Deprecated
public static final String LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST =
"location_ignore_settings_package_whitelist";
diff --git a/core/java/android/service/translation/TranslationService.java b/core/java/android/service/translation/TranslationService.java
index 2f704f4..e1d4a56 100644
--- a/core/java/android/service/translation/TranslationService.java
+++ b/core/java/android/service/translation/TranslationService.java
@@ -230,12 +230,8 @@
*/
// TODO(b/176464808): the session id won't be unique cross client/server process. Need to find
// solution to make it's safe.
- // TODO: make abstract once aiai is implemented.
- public void onCreateTranslationSession(@NonNull TranslationContext translationContext,
- int sessionId, @NonNull Consumer<Boolean> callback) {
- onCreateTranslationSession(translationContext, sessionId);
- callback.accept(true);
- }
+ public abstract void onCreateTranslationSession(@NonNull TranslationContext translationContext,
+ int sessionId, @NonNull Consumer<Boolean> callback);
/**
* TODO: fill in javadoc.
@@ -285,23 +281,9 @@
* @param callback
* @param cancellationSignal
*/
- //TODO: make abstract once aiai transitions.
- public void onTranslationRequest(@NonNull TranslationRequest request, int sessionId,
+ public abstract void onTranslationRequest(@NonNull TranslationRequest request, int sessionId,
@Nullable CancellationSignal cancellationSignal,
- @NonNull Consumer<TranslationResponse> callback) {
- onTranslationRequest(request, sessionId, cancellationSignal,
- new OnTranslationResultCallback() {
- @Override
- public void onTranslationSuccess(@NonNull TranslationResponse response) {
- callback.accept(response);
- }
-
- @Override
- public void onError() {
- // null-op
- }
- });
- }
+ @NonNull Consumer<TranslationResponse> callback);
/**
* TODO: fill in javadoc
diff --git a/core/java/android/service/voice/HotwordDetectedResult.java b/core/java/android/service/voice/HotwordDetectedResult.java
index ee82c37..846f2f9 100644
--- a/core/java/android/service/voice/HotwordDetectedResult.java
+++ b/core/java/android/service/voice/HotwordDetectedResult.java
@@ -16,8 +16,7 @@
package android.service.voice;
-import static android.service.voice.HotwordDetector.CONFIDENCE_LEVEL_NONE;
-
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -43,11 +42,48 @@
@SystemApi
public final class HotwordDetectedResult implements Parcelable {
- /** Represents unset value for byte offset. */
- public static final int BYTE_OFFSET_UNSET = -1;
+ /** No confidence in hotword detector result. */
+ public static final int CONFIDENCE_LEVEL_NONE = 0;
+
+ /** Low confidence in hotword detector result. */
+ public static final int CONFIDENCE_LEVEL_LOW = 1;
+
+ /** Low-to-medium confidence in hotword detector result. */
+ public static final int CONFIDENCE_LEVEL_LOW_MEDIUM = 2;
+
+ /** Medium confidence in hotword detector result. */
+ public static final int CONFIDENCE_LEVEL_MEDIUM = 3;
+
+ /** Medium-to-high confidence in hotword detector result. */
+ public static final int CONFIDENCE_LEVEL_MEDIUM_HIGH = 4;
+
+ /** High confidence in hotword detector result. */
+ public static final int CONFIDENCE_LEVEL_HIGH = 5;
+
+ /** Very high confidence in hotword detector result. */
+ public static final int CONFIDENCE_LEVEL_VERY_HIGH = 6;
+
+ /** @hide */
+ @IntDef(prefix = {"CONFIDENCE_LEVEL_"}, value = {
+ CONFIDENCE_LEVEL_NONE,
+ CONFIDENCE_LEVEL_LOW,
+ CONFIDENCE_LEVEL_LOW_MEDIUM,
+ CONFIDENCE_LEVEL_MEDIUM,
+ CONFIDENCE_LEVEL_MEDIUM_HIGH,
+ CONFIDENCE_LEVEL_HIGH,
+ CONFIDENCE_LEVEL_VERY_HIGH
+ })
+ @interface HotwordConfidenceLevelValue {
+ }
+
+ /** Represents unset value for the hotword offset. */
+ public static final int HOTWORD_OFFSET_UNSET = -1;
+
+ /** Represents unset value for the triggered audio channel. */
+ public static final int AUDIO_CHANNEL_UNSET = -1;
/** Confidence level in the trigger outcome. */
- @HotwordDetector.HotwordConfidenceLevelValue
+ @HotwordConfidenceLevelValue
private final int mConfidenceLevel;
private static int defaultConfidenceLevel() {
return CONFIDENCE_LEVEL_NONE;
@@ -62,12 +98,27 @@
private MediaSyncEvent mMediaSyncEvent = null;
/**
- * Byte offset in the audio stream when the trigger event happened.
+ * Offset in milliseconds the audio stream when the trigger event happened (end of hotword
+ * phrase).
*/
- private final int mByteOffset;
- private static int defaultByteOffset() {
- return BYTE_OFFSET_UNSET;
- }
+ private int mHotwordOffsetMillis = HOTWORD_OFFSET_UNSET;
+
+ /**
+ * Duration in milliseconds of the hotword trigger phrase.
+ *
+ * <p>Only values between 0 and {@link android.media.AudioRecord#getMaxSharedAudioHistoryMillis}
+ * (inclusive) are accepted.
+ */
+ private int mHotwordDurationMillis = 0;
+
+ /** Audio channel containing the highest-confidence hotword signal. **/
+ private int mAudioChannel = AUDIO_CHANNEL_UNSET;
+
+ /**
+ * Returns whether the trigger has happened due to model having been personalized to fit user's
+ * voice.
+ */
+ private boolean mHotwordDetectionPersonalized = false;
/**
* Score for the hotword trigger.
@@ -162,6 +213,7 @@
}
+
// Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
@@ -175,20 +227,62 @@
//@formatter:off
+ /** @hide */
+ @IntDef(prefix = "CONFIDENCE_LEVEL_", value = {
+ CONFIDENCE_LEVEL_NONE,
+ CONFIDENCE_LEVEL_LOW,
+ CONFIDENCE_LEVEL_LOW_MEDIUM,
+ CONFIDENCE_LEVEL_MEDIUM,
+ CONFIDENCE_LEVEL_MEDIUM_HIGH,
+ CONFIDENCE_LEVEL_HIGH,
+ CONFIDENCE_LEVEL_VERY_HIGH
+ })
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+ @DataClass.Generated.Member
+ public @interface ConfidenceLevel {}
+
+ /** @hide */
+ @DataClass.Generated.Member
+ public static String confidenceLevelToString(@ConfidenceLevel int value) {
+ switch (value) {
+ case CONFIDENCE_LEVEL_NONE:
+ return "CONFIDENCE_LEVEL_NONE";
+ case CONFIDENCE_LEVEL_LOW:
+ return "CONFIDENCE_LEVEL_LOW";
+ case CONFIDENCE_LEVEL_LOW_MEDIUM:
+ return "CONFIDENCE_LEVEL_LOW_MEDIUM";
+ case CONFIDENCE_LEVEL_MEDIUM:
+ return "CONFIDENCE_LEVEL_MEDIUM";
+ case CONFIDENCE_LEVEL_MEDIUM_HIGH:
+ return "CONFIDENCE_LEVEL_MEDIUM_HIGH";
+ case CONFIDENCE_LEVEL_HIGH:
+ return "CONFIDENCE_LEVEL_HIGH";
+ case CONFIDENCE_LEVEL_VERY_HIGH:
+ return "CONFIDENCE_LEVEL_VERY_HIGH";
+ default: return Integer.toHexString(value);
+ }
+ }
+
@DataClass.Generated.Member
/* package-private */ HotwordDetectedResult(
- @HotwordDetector.HotwordConfidenceLevelValue int confidenceLevel,
+ @HotwordConfidenceLevelValue int confidenceLevel,
@Nullable MediaSyncEvent mediaSyncEvent,
- int byteOffset,
+ int hotwordOffsetMillis,
+ int hotwordDurationMillis,
+ int audioChannel,
+ boolean hotwordDetectionPersonalized,
int score,
int personalizedScore,
int hotwordPhraseId,
@NonNull PersistableBundle extras) {
this.mConfidenceLevel = confidenceLevel;
com.android.internal.util.AnnotationValidations.validate(
- HotwordDetector.HotwordConfidenceLevelValue.class, null, mConfidenceLevel);
+ HotwordConfidenceLevelValue.class, null, mConfidenceLevel);
this.mMediaSyncEvent = mediaSyncEvent;
- this.mByteOffset = byteOffset;
+ this.mHotwordOffsetMillis = hotwordOffsetMillis;
+ this.mHotwordDurationMillis = hotwordDurationMillis;
+ this.mAudioChannel = audioChannel;
+ this.mHotwordDetectionPersonalized = hotwordDetectionPersonalized;
this.mScore = score;
this.mPersonalizedScore = personalizedScore;
this.mHotwordPhraseId = hotwordPhraseId;
@@ -203,16 +297,45 @@
* Confidence level in the trigger outcome.
*/
@DataClass.Generated.Member
- public @HotwordDetector.HotwordConfidenceLevelValue int getConfidenceLevel() {
+ public @HotwordConfidenceLevelValue int getConfidenceLevel() {
return mConfidenceLevel;
}
/**
- * Byte offset in the audio stream when the trigger event happened.
+ * Offset in milliseconds the audio stream when the trigger event happened (end of hotword
+ * phrase).
*/
@DataClass.Generated.Member
- public int getByteOffset() {
- return mByteOffset;
+ public int getHotwordOffsetMillis() {
+ return mHotwordOffsetMillis;
+ }
+
+ /**
+ * Duration in milliseconds of the hotword trigger phrase.
+ *
+ * <p>Only values between 0 and {@link android.media.AudioRecord#getMaxSharedAudioHistoryMillis}
+ * (inclusive) are accepted.
+ */
+ @DataClass.Generated.Member
+ public int getHotwordDurationMillis() {
+ return mHotwordDurationMillis;
+ }
+
+ /**
+ * Audio channel containing the highest-confidence hotword signal. *
+ */
+ @DataClass.Generated.Member
+ public int getAudioChannel() {
+ return mAudioChannel;
+ }
+
+ /**
+ * Returns whether the trigger has happened due to model having been personalized to fit user's
+ * voice.
+ */
+ @DataClass.Generated.Member
+ public boolean isHotwordDetectionPersonalized() {
+ return mHotwordDetectionPersonalized;
}
/**
@@ -274,7 +397,10 @@
return "HotwordDetectedResult { " +
"confidenceLevel = " + mConfidenceLevel + ", " +
"mediaSyncEvent = " + mMediaSyncEvent + ", " +
- "byteOffset = " + mByteOffset + ", " +
+ "hotwordOffsetMillis = " + mHotwordOffsetMillis + ", " +
+ "hotwordDurationMillis = " + mHotwordDurationMillis + ", " +
+ "audioChannel = " + mAudioChannel + ", " +
+ "hotwordDetectionPersonalized = " + mHotwordDetectionPersonalized + ", " +
"score = " + mScore + ", " +
"personalizedScore = " + mPersonalizedScore + ", " +
"hotwordPhraseId = " + mHotwordPhraseId + ", " +
@@ -297,7 +423,10 @@
return true
&& mConfidenceLevel == that.mConfidenceLevel
&& java.util.Objects.equals(mMediaSyncEvent, that.mMediaSyncEvent)
- && mByteOffset == that.mByteOffset
+ && mHotwordOffsetMillis == that.mHotwordOffsetMillis
+ && mHotwordDurationMillis == that.mHotwordDurationMillis
+ && mAudioChannel == that.mAudioChannel
+ && mHotwordDetectionPersonalized == that.mHotwordDetectionPersonalized
&& mScore == that.mScore
&& mPersonalizedScore == that.mPersonalizedScore
&& mHotwordPhraseId == that.mHotwordPhraseId
@@ -313,7 +442,10 @@
int _hash = 1;
_hash = 31 * _hash + mConfidenceLevel;
_hash = 31 * _hash + java.util.Objects.hashCode(mMediaSyncEvent);
- _hash = 31 * _hash + mByteOffset;
+ _hash = 31 * _hash + mHotwordOffsetMillis;
+ _hash = 31 * _hash + mHotwordDurationMillis;
+ _hash = 31 * _hash + mAudioChannel;
+ _hash = 31 * _hash + Boolean.hashCode(mHotwordDetectionPersonalized);
_hash = 31 * _hash + mScore;
_hash = 31 * _hash + mPersonalizedScore;
_hash = 31 * _hash + mHotwordPhraseId;
@@ -327,12 +459,15 @@
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
- byte flg = 0;
+ int flg = 0;
+ if (mHotwordDetectionPersonalized) flg |= 0x20;
if (mMediaSyncEvent != null) flg |= 0x2;
- dest.writeByte(flg);
+ dest.writeInt(flg);
dest.writeInt(mConfidenceLevel);
if (mMediaSyncEvent != null) dest.writeTypedObject(mMediaSyncEvent, flags);
- dest.writeInt(mByteOffset);
+ dest.writeInt(mHotwordOffsetMillis);
+ dest.writeInt(mHotwordDurationMillis);
+ dest.writeInt(mAudioChannel);
dest.writeInt(mScore);
dest.writeInt(mPersonalizedScore);
dest.writeInt(mHotwordPhraseId);
@@ -350,10 +485,13 @@
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
- byte flg = in.readByte();
+ int flg = in.readInt();
+ boolean hotwordDetectionPersonalized = (flg & 0x20) != 0;
int confidenceLevel = in.readInt();
MediaSyncEvent mediaSyncEvent = (flg & 0x2) == 0 ? null : (MediaSyncEvent) in.readTypedObject(MediaSyncEvent.CREATOR);
- int byteOffset = in.readInt();
+ int hotwordOffsetMillis = in.readInt();
+ int hotwordDurationMillis = in.readInt();
+ int audioChannel = in.readInt();
int score = in.readInt();
int personalizedScore = in.readInt();
int hotwordPhraseId = in.readInt();
@@ -361,9 +499,12 @@
this.mConfidenceLevel = confidenceLevel;
com.android.internal.util.AnnotationValidations.validate(
- HotwordDetector.HotwordConfidenceLevelValue.class, null, mConfidenceLevel);
+ HotwordConfidenceLevelValue.class, null, mConfidenceLevel);
this.mMediaSyncEvent = mediaSyncEvent;
- this.mByteOffset = byteOffset;
+ this.mHotwordOffsetMillis = hotwordOffsetMillis;
+ this.mHotwordDurationMillis = hotwordDurationMillis;
+ this.mAudioChannel = audioChannel;
+ this.mHotwordDetectionPersonalized = hotwordDetectionPersonalized;
this.mScore = score;
this.mPersonalizedScore = personalizedScore;
this.mHotwordPhraseId = hotwordPhraseId;
@@ -395,9 +536,12 @@
@DataClass.Generated.Member
public static final class Builder {
- private @HotwordDetector.HotwordConfidenceLevelValue int mConfidenceLevel;
+ private @HotwordConfidenceLevelValue int mConfidenceLevel;
private @Nullable MediaSyncEvent mMediaSyncEvent;
- private int mByteOffset;
+ private int mHotwordOffsetMillis;
+ private int mHotwordDurationMillis;
+ private int mAudioChannel;
+ private boolean mHotwordDetectionPersonalized;
private int mScore;
private int mPersonalizedScore;
private int mHotwordPhraseId;
@@ -412,7 +556,7 @@
* Confidence level in the trigger outcome.
*/
@DataClass.Generated.Member
- public @NonNull Builder setConfidenceLevel(@HotwordDetector.HotwordConfidenceLevelValue int value) {
+ public @NonNull Builder setConfidenceLevel(@HotwordConfidenceLevelValue int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x1;
mConfidenceLevel = value;
@@ -433,13 +577,51 @@
}
/**
- * Byte offset in the audio stream when the trigger event happened.
+ * Offset in milliseconds the audio stream when the trigger event happened (end of hotword
+ * phrase).
*/
@DataClass.Generated.Member
- public @NonNull Builder setByteOffset(int value) {
+ public @NonNull Builder setHotwordOffsetMillis(int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x4;
- mByteOffset = value;
+ mHotwordOffsetMillis = value;
+ return this;
+ }
+
+ /**
+ * Duration in milliseconds of the hotword trigger phrase.
+ *
+ * <p>Only values between 0 and {@link android.media.AudioRecord#getMaxSharedAudioHistoryMillis}
+ * (inclusive) are accepted.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setHotwordDurationMillis(int value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x8;
+ mHotwordDurationMillis = value;
+ return this;
+ }
+
+ /**
+ * Audio channel containing the highest-confidence hotword signal. *
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setAudioChannel(int value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x10;
+ mAudioChannel = value;
+ return this;
+ }
+
+ /**
+ * Returns whether the trigger has happened due to model having been personalized to fit user's
+ * voice.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setHotwordDetectionPersonalized(boolean value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x20;
+ mHotwordDetectionPersonalized = value;
return this;
}
@@ -451,7 +633,7 @@
@DataClass.Generated.Member
public @NonNull Builder setScore(int value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x8;
+ mBuilderFieldsSet |= 0x40;
mScore = value;
return this;
}
@@ -464,7 +646,7 @@
@DataClass.Generated.Member
public @NonNull Builder setPersonalizedScore(int value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x10;
+ mBuilderFieldsSet |= 0x80;
mPersonalizedScore = value;
return this;
}
@@ -477,7 +659,7 @@
@DataClass.Generated.Member
public @NonNull Builder setHotwordPhraseId(int value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x20;
+ mBuilderFieldsSet |= 0x100;
mHotwordPhraseId = value;
return this;
}
@@ -500,7 +682,7 @@
@DataClass.Generated.Member
public @NonNull Builder setExtras(@NonNull PersistableBundle value) {
checkNotUsed();
- mBuilderFieldsSet |= 0x40;
+ mBuilderFieldsSet |= 0x200;
mExtras = value;
return this;
}
@@ -508,7 +690,7 @@
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull HotwordDetectedResult build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x80; // Mark builder used
+ mBuilderFieldsSet |= 0x400; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mConfidenceLevel = defaultConfidenceLevel();
@@ -517,24 +699,36 @@
mMediaSyncEvent = null;
}
if ((mBuilderFieldsSet & 0x4) == 0) {
- mByteOffset = defaultByteOffset();
+ mHotwordOffsetMillis = HOTWORD_OFFSET_UNSET;
}
if ((mBuilderFieldsSet & 0x8) == 0) {
- mScore = defaultScore();
+ mHotwordDurationMillis = 0;
}
if ((mBuilderFieldsSet & 0x10) == 0) {
- mPersonalizedScore = defaultPersonalizedScore();
+ mAudioChannel = AUDIO_CHANNEL_UNSET;
}
if ((mBuilderFieldsSet & 0x20) == 0) {
- mHotwordPhraseId = defaultHotwordPhraseId();
+ mHotwordDetectionPersonalized = false;
}
if ((mBuilderFieldsSet & 0x40) == 0) {
+ mScore = defaultScore();
+ }
+ if ((mBuilderFieldsSet & 0x80) == 0) {
+ mPersonalizedScore = defaultPersonalizedScore();
+ }
+ if ((mBuilderFieldsSet & 0x100) == 0) {
+ mHotwordPhraseId = defaultHotwordPhraseId();
+ }
+ if ((mBuilderFieldsSet & 0x200) == 0) {
mExtras = defaultExtras();
}
HotwordDetectedResult o = new HotwordDetectedResult(
mConfidenceLevel,
mMediaSyncEvent,
- mByteOffset,
+ mHotwordOffsetMillis,
+ mHotwordDurationMillis,
+ mAudioChannel,
+ mHotwordDetectionPersonalized,
mScore,
mPersonalizedScore,
mHotwordPhraseId,
@@ -543,7 +737,7 @@
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x80) != 0) {
+ if ((mBuilderFieldsSet & 0x400) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
@@ -551,10 +745,10 @@
}
@DataClass.Generated(
- time = 1620133603958L,
+ time = 1621943150502L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/voice/HotwordDetectedResult.java",
- inputSignatures = "public static final int BYTE_OFFSET_UNSET\nprivate final @android.service.voice.HotwordDetector.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate final int mByteOffset\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int defaultConfidenceLevel()\nprivate static int defaultByteOffset()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\npublic @android.annotation.Nullable android.media.MediaSyncEvent getMediaSyncEvent()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+ inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_LOW_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM_HIGH\npublic static final int CONFIDENCE_LEVEL_HIGH\npublic static final int CONFIDENCE_LEVEL_VERY_HIGH\npublic static final int HOTWORD_OFFSET_UNSET\npublic static final int AUDIO_CHANNEL_UNSET\nprivate final @android.service.voice.HotwordDetectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate int mHotwordOffsetMillis\nprivate int mHotwordDurationMillis\nprivate int mAudioChannel\nprivate boolean mHotwordDetectionPersonalized\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int defaultConfidenceLevel()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\npublic @android.annotation.Nullable android.media.MediaSyncEvent getMediaSyncEvent()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index 3960e38..deb6c01 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -192,6 +192,11 @@
mContentCaptureManager = new ContentCaptureManager(
HotwordDetectionService.this, manager, options);
}
+
+ @Override
+ public void stopDetection() {
+ HotwordDetectionService.this.onStopDetection();
+ }
};
@Override
@@ -232,36 +237,6 @@
* Called when the device hardware (such as a DSP) detected the hotword, to request second stage
* validation before handing over the audio to the {@link AlwaysOnHotwordDetector}.
* <p>
- * After {@code callback} is invoked or {@code timeoutMillis} has passed, the system closes
- * {@code audioStream} and invokes the appropriate {@link AlwaysOnHotwordDetector.Callback
- * callback}.
- *
- * @param audioStream Stream containing audio bytes returned from DSP
- * @param audioFormat Format of the supplied audio
- * @param timeoutMillis Timeout in milliseconds for the operation to invoke the callback. If
- * the application fails to abide by the timeout, system will close the
- * microphone and cancel the operation.
- * @param callback The callback to use for responding to the detection request.
- * @deprecated Implement
- * {@link #onDetect(AlwaysOnHotwordDetector.EventPayload, long, Callback)} instead.
- *
- * @hide
- */
- @Deprecated
- @SystemApi
- public void onDetect(
- @NonNull ParcelFileDescriptor audioStream,
- @NonNull AudioFormat audioFormat,
- @DurationMillisLong long timeoutMillis,
- @NonNull Callback callback) {
- // TODO: Add a helpful error message.
- throw new UnsupportedOperationException();
- }
-
- /**
- * Called when the device hardware (such as a DSP) detected the hotword, to request second stage
- * validation before handing over the audio to the {@link AlwaysOnHotwordDetector}.
- * <p>
* After {@code callback} is invoked or {@code timeoutMillis} has passed, and invokes the
* appropriate {@link AlwaysOnHotwordDetector.Callback callback}.
*
@@ -319,34 +294,6 @@
* {@link HotwordDetector#startRecognition() start} hotword recognition on audio coming directly
* from the device microphone.
* <p>
- * On such a request, the system streams mic audio to this service through {@code audioStream}.
- * Audio is streamed until {@link HotwordDetector#stopRecognition()} is called, at which point
- * the system closes {code audioStream}.
- * <p>
- * On successful detection of a hotword within {@code audioStream}, call
- * {@link Callback#onDetected(HotwordDetectedResult)}. The system continues to stream audio
- * through {@code audioStream}; {@code callback} is reusable.
- *
- * @param audioStream Stream containing audio bytes returned from a microphone
- * @param audioFormat Format of the supplied audio
- * @param callback The callback to use for responding to the detection request.
- * {@link Callback#onRejected(HotwordRejectedResult) callback.onRejected} cannot be used here.
- * @deprecated Implement {@link #onDetect(Callback)} instead.
- */
- @Deprecated
- public void onDetect(
- @NonNull ParcelFileDescriptor audioStream,
- @NonNull AudioFormat audioFormat,
- @NonNull Callback callback) {
- // TODO: Add a helpful error message.
- throw new UnsupportedOperationException();
- }
-
- /**
- * Called when the {@link VoiceInteractionService} requests that this service
- * {@link HotwordDetector#startRecognition() start} hotword recognition on audio coming directly
- * from the device microphone.
- * <p>
* On successful detection of a hotword, call
* {@link Callback#onDetected(HotwordDetectedResult)}.
*
@@ -407,6 +354,15 @@
}
/**
+ * Called when the {@link VoiceInteractionService}
+ * {@link HotwordDetector#stopRecognition() requests} that hotword recognition be stopped.
+ * <p>
+ * Any open {@link android.media.AudioRecord} should be closed here.
+ */
+ public void onStopDetection() {
+ }
+
+ /**
* Callback for returning the detection result.
*
* @hide
diff --git a/core/java/android/service/voice/HotwordDetector.java b/core/java/android/service/voice/HotwordDetector.java
index b2f810a..e247819 100644
--- a/core/java/android/service/voice/HotwordDetector.java
+++ b/core/java/android/service/voice/HotwordDetector.java
@@ -19,7 +19,6 @@
import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD;
import static android.Manifest.permission.RECORD_AUDIO;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -37,28 +36,6 @@
@SystemApi
public interface HotwordDetector {
- /** No confidence in hotword detector result. */
- int CONFIDENCE_LEVEL_NONE = 0;
-
- /** Small confidence in hotword detector result. */
- int CONFIDENCE_LEVEL_LOW = 1;
-
- /** Medium confidence in hotword detector result. */
- int CONFIDENCE_LEVEL_MEDIUM = 2;
-
- /** High confidence in hotword detector result. */
- int CONFIDENCE_LEVEL_HIGH = 3;
-
- /** @hide */
- @IntDef(prefix = {"CONFIDENCE_LEVEL_"}, value = {
- CONFIDENCE_LEVEL_NONE,
- CONFIDENCE_LEVEL_LOW,
- CONFIDENCE_LEVEL_MEDIUM,
- CONFIDENCE_LEVEL_HIGH
- })
- @interface HotwordConfidenceLevelValue {
- }
-
/**
* Starts hotword recognition.
* <p>
diff --git a/core/java/android/service/voice/HotwordRejectedResult.java b/core/java/android/service/voice/HotwordRejectedResult.java
index 5d85662..7b3f47d 100644
--- a/core/java/android/service/voice/HotwordRejectedResult.java
+++ b/core/java/android/service/voice/HotwordRejectedResult.java
@@ -16,8 +16,7 @@
package android.service.voice;
-import static android.service.voice.HotwordDetector.CONFIDENCE_LEVEL_NONE;
-
+import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.os.Parcelable;
@@ -30,7 +29,7 @@
*/
@DataClass(
genConstructor = false,
- genHiddenBuilder = true,
+ genBuilder = true,
genEqualsHashCode = true,
genHiddenConstDefs = true,
genParcelable = true,
@@ -39,8 +38,30 @@
@SystemApi
public final class HotwordRejectedResult implements Parcelable {
+ /** No confidence in hotword detector result. */
+ public static final int CONFIDENCE_LEVEL_NONE = 0;
+
+ /** Small confidence in hotword detector result. */
+ public static final int CONFIDENCE_LEVEL_LOW = 1;
+
+ /** Medium confidence in hotword detector result. */
+ public static final int CONFIDENCE_LEVEL_MEDIUM = 2;
+
+ /** High confidence in hotword detector result. */
+ public static final int CONFIDENCE_LEVEL_HIGH = 3;
+
+ /** @hide */
+ @IntDef(prefix = {"CONFIDENCE_LEVEL_"}, value = {
+ CONFIDENCE_LEVEL_NONE,
+ CONFIDENCE_LEVEL_LOW,
+ CONFIDENCE_LEVEL_MEDIUM,
+ CONFIDENCE_LEVEL_HIGH
+ })
+ @interface HotwordConfidenceLevelValue {
+ }
+
/** Confidence level in the trigger outcome. */
- @HotwordDetector.HotwordConfidenceLevelValue
+ @HotwordConfidenceLevelValue
private final int mConfidenceLevel;
private static int defaultConfidenceLevel() {
return CONFIDENCE_LEVEL_NONE;
@@ -48,7 +69,7 @@
- // Code below generated by codegen v1.0.22.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -61,12 +82,39 @@
//@formatter:off
+ /** @hide */
+ @IntDef(prefix = "CONFIDENCE_LEVEL_", value = {
+ CONFIDENCE_LEVEL_NONE,
+ CONFIDENCE_LEVEL_LOW,
+ CONFIDENCE_LEVEL_MEDIUM,
+ CONFIDENCE_LEVEL_HIGH
+ })
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+ @DataClass.Generated.Member
+ public @interface ConfidenceLevel {}
+
+ /** @hide */
+ @DataClass.Generated.Member
+ public static String confidenceLevelToString(@ConfidenceLevel int value) {
+ switch (value) {
+ case CONFIDENCE_LEVEL_NONE:
+ return "CONFIDENCE_LEVEL_NONE";
+ case CONFIDENCE_LEVEL_LOW:
+ return "CONFIDENCE_LEVEL_LOW";
+ case CONFIDENCE_LEVEL_MEDIUM:
+ return "CONFIDENCE_LEVEL_MEDIUM";
+ case CONFIDENCE_LEVEL_HIGH:
+ return "CONFIDENCE_LEVEL_HIGH";
+ default: return Integer.toHexString(value);
+ }
+ }
+
@DataClass.Generated.Member
/* package-private */ HotwordRejectedResult(
- @HotwordDetector.HotwordConfidenceLevelValue int confidenceLevel) {
+ @HotwordConfidenceLevelValue int confidenceLevel) {
this.mConfidenceLevel = confidenceLevel;
com.android.internal.util.AnnotationValidations.validate(
- HotwordDetector.HotwordConfidenceLevelValue.class, null, mConfidenceLevel);
+ HotwordConfidenceLevelValue.class, null, mConfidenceLevel);
// onConstructed(); // You can define this method to get a callback
}
@@ -75,7 +123,7 @@
* Confidence level in the trigger outcome.
*/
@DataClass.Generated.Member
- public @HotwordDetector.HotwordConfidenceLevelValue int getConfidenceLevel() {
+ public @HotwordConfidenceLevelValue int getConfidenceLevel() {
return mConfidenceLevel;
}
@@ -141,7 +189,7 @@
this.mConfidenceLevel = confidenceLevel;
com.android.internal.util.AnnotationValidations.validate(
- HotwordDetector.HotwordConfidenceLevelValue.class, null, mConfidenceLevel);
+ HotwordConfidenceLevelValue.class, null, mConfidenceLevel);
// onConstructed(); // You can define this method to get a callback
}
@@ -162,13 +210,12 @@
/**
* A builder for {@link HotwordRejectedResult}
- * @hide
*/
@SuppressWarnings("WeakerAccess")
@DataClass.Generated.Member
public static final class Builder {
- private @HotwordDetector.HotwordConfidenceLevelValue int mConfidenceLevel;
+ private @HotwordConfidenceLevelValue int mConfidenceLevel;
private long mBuilderFieldsSet = 0L;
@@ -179,7 +226,7 @@
* Confidence level in the trigger outcome.
*/
@DataClass.Generated.Member
- public @android.annotation.NonNull Builder setConfidenceLevel(@HotwordDetector.HotwordConfidenceLevelValue int value) {
+ public @android.annotation.NonNull Builder setConfidenceLevel(@HotwordConfidenceLevelValue int value) {
checkNotUsed();
mBuilderFieldsSet |= 0x1;
mConfidenceLevel = value;
@@ -208,10 +255,10 @@
}
@DataClass.Generated(
- time = 1616108967315L,
- codegenVersion = "1.0.22",
+ time = 1621961370106L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/voice/HotwordRejectedResult.java",
- inputSignatures = "private final @android.service.voice.HotwordDetector.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate static int defaultConfidenceLevel()\nclass HotwordRejectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genHiddenBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+ inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_HIGH\nprivate final @android.service.voice.HotwordRejectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate static int defaultConfidenceLevel()\nclass HotwordRejectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/voice/IHotwordDetectionService.aidl b/core/java/android/service/voice/IHotwordDetectionService.aidl
index 7ba0098..72dd45a 100644
--- a/core/java/android/service/voice/IHotwordDetectionService.aidl
+++ b/core/java/android/service/voice/IHotwordDetectionService.aidl
@@ -53,4 +53,6 @@
void updateContentCaptureManager(
in IContentCaptureManager contentCaptureManager,
in ContentCaptureOptions options);
+
+ void stopDetection();
}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index b5c838b..6a0fec7 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -29,7 +29,6 @@
import android.content.Context;
import android.content.Intent;
import android.hardware.soundtrigger.KeyphraseEnrollmentInfo;
-import android.media.AudioFormat;
import android.media.voice.KeyphraseModelManager;
import android.os.Bundle;
import android.os.Handler;
@@ -408,64 +407,6 @@
* devices where hardware filtering is available (such as through a DSP), it's highly
* recommended to use {@link #createAlwaysOnHotwordDetector} instead.
*
- * @param audioFormat Format of the audio to be passed to {@link HotwordDetectionService}.
- * @param options Application configuration data to be provided to the
- * {@link HotwordDetectionService}. PersistableBundle does not allow any remotable objects or
- * other contents that can be used to communicate with other processes.
- * @param sharedMemory The unrestricted data blob to be provided to the
- * {@link HotwordDetectionService}. Use this to provide hotword models or other such data to the
- * sandboxed process.
- * @param callback The callback to notify of detection events.
- * @return A hotword detector for the given audio format.
- *
- * @see #createAlwaysOnHotwordDetector(String, Locale, PersistableBundle, SharedMemory,
- * AlwaysOnHotwordDetector.Callback)
- * @deprecated Use
- * {@link #createHotwordDetector(PersistableBundle, SharedMemory, HotwordDetector.Callback)}
- * instead.
- *
- * @hide
- */
- @Deprecated
- @SystemApi
- @RequiresPermission(Manifest.permission.MANAGE_HOTWORD_DETECTION)
- @NonNull
- public final HotwordDetector createHotwordDetector(
- @NonNull AudioFormat audioFormat,
- @Nullable PersistableBundle options,
- @Nullable SharedMemory sharedMemory,
- @NonNull HotwordDetector.Callback callback) {
- if (mSystemService == null) {
- throw new IllegalStateException("Not available until onReady() is called");
- }
- synchronized (mLock) {
- // Allow only one concurrent recognition via the APIs.
- safelyShutdownHotwordDetector();
- mSoftwareHotwordDetector =
- new SoftwareHotwordDetector(
- mSystemService, audioFormat, options, sharedMemory, callback);
- }
- return mSoftwareHotwordDetector;
- }
-
- /**
- * Creates a {@link HotwordDetector} and initializes the application's
- * {@link HotwordDetectionService} using {@code options} and {code sharedMemory}.
- *
- * <p>To be able to call this, you need to set android:hotwordDetectionService in the
- * android.voice_interaction metadata file to a valid hotword detection service, and set
- * android:isolatedProcess="true" in the hotword detection service's declaration. Otherwise,
- * this throws an {@link IllegalStateException}.
- *
- * <p>This instance must be retained and used by the client.
- * Calling this a second time invalidates the previously created hotword detector
- * which can no longer be used to manage recognition.
- *
- * <p>Using this has a noticeable impact on battery, since the microphone is kept open
- * for the lifetime of the recognition {@link HotwordDetector#startRecognition() session}. On
- * devices where hardware filtering is available (such as through a DSP), it's highly
- * recommended to use {@link #createAlwaysOnHotwordDetector} instead.
- *
* @param options Application configuration data to be provided to the
* {@link HotwordDetectionService}. PersistableBundle does not allow any remotable objects or
* other contents that can be used to communicate with other processes.
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index cd82489..8021636 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -385,6 +385,13 @@
oneway void setRecentsVisibility(boolean visible);
/**
+ * Called by System UI to indicate the maximum bounds of the system Privacy Indicator, for the
+ * current orientation, whether the indicator is showing or not. Should be an array of length
+ * 4, with the bounds for ROTATION_0, 90, 180, and 270, in that order.
+ */
+ oneway void updateStaticPrivacyIndicatorBounds(int displayId, in Rect[] staticBounds);
+
+ /**
* Called by System UI to enable or disable haptic feedback on the navigation bar buttons.
*/
@UnsupportedAppUsage
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 3255dd6..b3caac0 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -28,6 +28,8 @@
import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
import static android.view.InsetsController.AnimationType;
import static android.view.InsetsController.DEBUG;
+import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
+import static android.view.InsetsController.LayoutInsetsDuringAnimation;
import static android.view.InsetsState.ISIDE_BOTTOM;
import static android.view.InsetsState.ISIDE_FLOATING;
import static android.view.InsetsState.ISIDE_LEFT;
@@ -85,6 +87,7 @@
private final Matrix mTmpMatrix = new Matrix();
private final InsetsState mInitialInsetsState;
private final @AnimationType int mAnimationType;
+ private final @LayoutInsetsDuringAnimation int mLayoutInsetsDuringAnimation;
private final @InsetsType int mTypes;
private @InsetsType int mControllingTypes;
private final InsetsAnimationControlCallbacks mController;
@@ -107,9 +110,10 @@
@VisibleForTesting
public InsetsAnimationControlImpl(SparseArray<InsetsSourceControl> controls,
@Nullable Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener,
- @InsetsType int types,
- InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
- @AnimationType int animationType, CompatibilityInfo.Translator translator) {
+ @InsetsType int types, InsetsAnimationControlCallbacks controller, long durationMs,
+ Interpolator interpolator, @AnimationType int animationType,
+ @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
+ CompatibilityInfo.Translator translator) {
mControls = controls;
mListener = listener;
mTypes = types;
@@ -145,6 +149,7 @@
durationMs);
mAnimation.setAlpha(getCurrentAlpha());
mAnimationType = animationType;
+ mLayoutInsetsDuringAnimation = layoutInsetsDuringAnimation;
mTranslator = translator;
mController.startAnimation(this, listener, types, mAnimation,
new Bounds(mHiddenInsets, mShownInsets));
@@ -299,6 +304,10 @@
if (mFinished) {
return;
}
+ mPendingInsets = mLayoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN
+ ? mShownInsets : mHiddenInsets;
+ mPendingAlpha = 1f;
+ applyChangeInsets(null);
mCancelled = true;
mListener.onCancelled(mReadyDispatched ? this : null);
if (DEBUG) Log.d(TAG, "notify Control request cancelled for types: " + mTypes);
diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java
index 436a17c..c6ebc9e 100644
--- a/core/java/android/view/InsetsAnimationThreadControlRunner.java
+++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java
@@ -29,6 +29,7 @@
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.InsetsController.AnimationType;
+import android.view.InsetsController.LayoutInsetsDuringAnimation;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation.Bounds;
@@ -103,14 +104,15 @@
@UiThread
public InsetsAnimationThreadControlRunner(SparseArray<InsetsSourceControl> controls,
@Nullable Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener,
- @InsetsType int types,
- InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
- @AnimationType int animationType, CompatibilityInfo.Translator translator,
- Handler mainThreadHandler) {
+ @InsetsType int types, InsetsAnimationControlCallbacks controller, long durationMs,
+ Interpolator interpolator, @AnimationType int animationType,
+ @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
+ CompatibilityInfo.Translator translator, Handler mainThreadHandler) {
mMainThreadHandler = mainThreadHandler;
mOuterCallbacks = controller;
- mControl = new InsetsAnimationControlImpl(controls, frame, state, listener,
- types, mCallbacks, durationMs, interpolator, animationType, translator);
+ mControl = new InsetsAnimationControlImpl(controls, frame, state, listener, types,
+ mCallbacks, durationMs, interpolator, animationType, layoutInsetsDuringAnimation,
+ translator);
InsetsAnimationThread.getHandler().post(() -> {
if (mControl.isCancelled()) {
return;
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index de7cc18..d339c04 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -690,6 +690,7 @@
mState.setDisplayFrame(newState.getDisplayFrame());
mState.setDisplayCutout(newState.getDisplayCutout());
mState.setRoundedCorners(newState.getRoundedCorners());
+ mState.setPrivacyIndicatorBounds(newState.getPrivacyIndicatorBounds());
@InsetsType int disabledUserAnimationTypes = 0;
@InsetsType int[] cancelledUserAnimationTypes = {0};
for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {
@@ -1052,10 +1053,11 @@
final InsetsAnimationControlRunner runner = useInsetsAnimationThread
? new InsetsAnimationThreadControlRunner(controls,
frame, mState, listener, typesReady, this, durationMs, interpolator,
- animationType, mHost.getTranslator(), mHost.getHandler())
+ animationType, layoutInsetsDuringAnimation, mHost.getTranslator(),
+ mHost.getHandler())
: new InsetsAnimationControlImpl(controls,
frame, mState, listener, typesReady, this, durationMs, interpolator,
- animationType, mHost.getTranslator());
+ animationType, layoutInsetsDuringAnimation, mHost.getTranslator());
if ((typesReady & WindowInsets.Type.ime()) != 0) {
ImeTracing.getInstance().triggerClientDump("InsetsAnimationControlImpl",
mHost.getInputMethodManager(), null /* icProto */);
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index f487c6c..37101b7 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -171,6 +171,10 @@
/** The rounded corners on the display */
private RoundedCorners mRoundedCorners = RoundedCorners.NO_ROUNDED_CORNERS;
+ /** The bounds of the Privacy Indicator */
+ private PrivacyIndicatorBounds mPrivacyIndicatorBounds =
+ new PrivacyIndicatorBounds();
+
public InsetsState() {
}
@@ -243,8 +247,9 @@
return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
alwaysConsumeSystemBars, calculateRelativeCutout(frame),
- calculateRelativeRoundedCorners(frame), compatInsetsTypes,
- (legacySystemUiFlags & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0);
+ calculateRelativeRoundedCorners(frame),
+ calculateRelativePrivacyIndicatorBounds(frame),
+ compatInsetsTypes, (legacySystemUiFlags & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0);
}
private DisplayCutout calculateRelativeCutout(Rect frame) {
@@ -282,6 +287,20 @@
return mRoundedCorners.inset(insetLeft, insetTop, insetRight, insetBottom);
}
+ private PrivacyIndicatorBounds calculateRelativePrivacyIndicatorBounds(Rect frame) {
+ if (mDisplayFrame.equals(frame)) {
+ return mPrivacyIndicatorBounds;
+ }
+ if (frame == null) {
+ return null;
+ }
+ final int insetLeft = frame.left - mDisplayFrame.left;
+ final int insetTop = frame.top - mDisplayFrame.top;
+ final int insetRight = mDisplayFrame.right - frame.right;
+ final int insetBottom = mDisplayFrame.bottom - frame.bottom;
+ return mPrivacyIndicatorBounds.inset(insetLeft, insetTop, insetRight, insetBottom);
+ }
+
public Rect calculateInsets(Rect frame, @InsetsType int types, boolean ignoreVisibility) {
Insets insets = Insets.NONE;
for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
@@ -471,6 +490,14 @@
return mRoundedCorners;
}
+ public void setPrivacyIndicatorBounds(PrivacyIndicatorBounds bounds) {
+ mPrivacyIndicatorBounds = bounds;
+ }
+
+ public PrivacyIndicatorBounds getPrivacyIndicatorBounds() {
+ return mPrivacyIndicatorBounds;
+ }
+
/**
* Modifies the state of this class to exclude a certain type to make it ready for dispatching
* to the client.
@@ -508,6 +535,7 @@
mDisplayFrame.scale(scale);
mDisplayCutout.scale(scale);
mRoundedCorners = mRoundedCorners.scale(scale);
+ mPrivacyIndicatorBounds = mPrivacyIndicatorBounds.scale(scale);
for (int i = 0; i < SIZE; i++) {
final InsetsSource source = mSources[i];
if (source != null) {
@@ -528,6 +556,7 @@
mDisplayFrame.set(other.mDisplayFrame);
mDisplayCutout.set(other.mDisplayCutout);
mRoundedCorners = other.getRoundedCorners();
+ mPrivacyIndicatorBounds = other.getPrivacyIndicatorBounds();
if (copySources) {
for (int i = 0; i < SIZE; i++) {
InsetsSource source = other.mSources[i];
@@ -551,6 +580,7 @@
mDisplayFrame.set(other.mDisplayFrame);
mDisplayCutout.set(other.mDisplayCutout);
mRoundedCorners = other.getRoundedCorners();
+ mPrivacyIndicatorBounds = other.getPrivacyIndicatorBounds();
final ArraySet<Integer> t = toInternalType(types);
for (int i = t.size() - 1; i >= 0; i--) {
final int type = t.valueAt(i);
@@ -670,6 +700,7 @@
pw.println(newPrefix + "mDisplayFrame=" + mDisplayFrame);
pw.println(newPrefix + "mDisplayCutout=" + mDisplayCutout.get());
pw.println(newPrefix + "mRoundedCorners=" + mRoundedCorners);
+ pw.println(newPrefix + "mPrivacyIndicatorBounds=" + mPrivacyIndicatorBounds);
for (int i = 0; i < SIZE; i++) {
InsetsSource source = mSources[i];
if (source == null) continue;
@@ -764,7 +795,8 @@
if (!mDisplayFrame.equals(state.mDisplayFrame)
|| !mDisplayCutout.equals(state.mDisplayCutout)
- || !mRoundedCorners.equals(state.mRoundedCorners)) {
+ || !mRoundedCorners.equals(state.mRoundedCorners)
+ || !mPrivacyIndicatorBounds.equals(state.mPrivacyIndicatorBounds)) {
return false;
}
for (int i = 0; i < SIZE; i++) {
@@ -789,7 +821,7 @@
@Override
public int hashCode() {
return Objects.hash(mDisplayFrame, mDisplayCutout, Arrays.hashCode(mSources),
- mRoundedCorners);
+ mRoundedCorners, mPrivacyIndicatorBounds);
}
public InsetsState(Parcel in) {
@@ -807,6 +839,7 @@
mDisplayCutout.writeToParcel(dest, flags);
dest.writeTypedArray(mSources, 0 /* parcelableFlags */);
dest.writeTypedObject(mRoundedCorners, flags);
+ dest.writeTypedObject(mPrivacyIndicatorBounds, flags);
}
public static final @NonNull Creator<InsetsState> CREATOR = new Creator<InsetsState>() {
@@ -825,6 +858,7 @@
mDisplayCutout.readFromParcel(in);
in.readTypedArray(mSources, InsetsSource.CREATOR);
mRoundedCorners = in.readTypedObject(RoundedCorners.CREATOR);
+ mPrivacyIndicatorBounds = in.readTypedObject(PrivacyIndicatorBounds.CREATOR);
}
@Override
@@ -840,6 +874,7 @@
+ "mDisplayFrame=" + mDisplayFrame
+ ", mDisplayCutout=" + mDisplayCutout
+ ", mRoundedCorners=" + mRoundedCorners
+ + ", mPrivacyIndicatorBounds=" + mPrivacyIndicatorBounds
+ ", mSources= { " + joiner
+ " }";
}
diff --git a/core/java/android/view/OnReceiveContentListener.java b/core/java/android/view/OnReceiveContentListener.java
index f90e01c..f2a763a 100644
--- a/core/java/android/view/OnReceiveContentListener.java
+++ b/core/java/android/view/OnReceiveContentListener.java
@@ -92,21 +92,25 @@
* {@link android.content.ContentResolver#SCHEME_CONTENT content URIs} in the payload passed
* to this listener. Permissions are transient and will be released automatically by the
* platform.
- * <ul>
- * <li>If the {@link ContentInfo#getSource() source} is the
- * {@link ContentInfo#SOURCE_CLIPBOARD clipboard}, permissions are released whenever the
- * next copy action is performed by the user.
- * <li>If the source is {@link ContentInfo#SOURCE_AUTOFILL autofill}, permissions are tied
- * to the target {@link android.app.Activity} lifecycle (released when the activity
- * finishes).
- * <li>For other sources, permissions are tied to the passed-in {@code payload} object
- * (released automatically when there are no more references to it). To ensure that
- * permissions are not released prematurely, implementations of this listener should pass
- * along the {@code payload} object if processing is done on a background thread.
- * </ul>
+ * <p>Processing of content should normally be done in a service or activity.
+ * For long-running processing, using {@code androidx.work.WorkManager} is recommended.
+ * When implementing this, permissions should be extended to the target service or activity
+ * by passing the content using {@link android.content.Intent#setClipData Intent.setClipData}
+ * and {@link android.content.Intent#addFlags(int) setting} the flag
+ * {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION FLAG_GRANT_READ_URI_PERMISSION}.
+ * <p>Alternatively, if using a background thread within the current context to process the
+ * content, a reference to the {@code payload} object should be maintained to ensure that
+ * permissions are not revoked prematurely.
*
* @param view The view where the content insertion was requested.
- * @param payload The content to insert and related metadata.
+ * @param payload The content to insert and related metadata. The payload may contain multiple
+ * items and their MIME types may be different (e.g. an image item and a text
+ * item). The payload may also contain items whose MIME type is not in the list
+ * of MIME types specified when
+ * {@link View#setOnReceiveContentListener setting} the listener. For
+ * those items, the listener may reject the content (defer to the default
+ * platform behavior) or execute some other fallback logic (e.g. show an
+ * appropriate message to the user).
*
* @return The portion of the passed-in content whose processing should be delegated to
* the platform. Return null if all content was handled in some way. Actual insertion of
diff --git a/core/java/android/view/PrivacyIndicatorBounds.java b/core/java/android/view/PrivacyIndicatorBounds.java
new file mode 100644
index 0000000..4cf5eda
--- /dev/null
+++ b/core/java/android/view/PrivacyIndicatorBounds.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static android.view.Surface.ROTATION_0;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Rect;
+import android.os.Parcelable;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.DataClass;
+
+/**
+ * A class which manages the bounds of the privacy indicator
+ *
+ * @hide
+ */
+@DataClass(
+ genEqualsHashCode = true,
+ genConstructor = false,
+ genAidl = false,
+ genGetters = false
+)
+public class PrivacyIndicatorBounds implements Parcelable {
+
+ private final @NonNull Rect[] mStaticBounds;
+ private final int mRotation;
+
+ public PrivacyIndicatorBounds() {
+ mStaticBounds = new Rect[4];
+ mRotation = ROTATION_0;
+ }
+
+ public PrivacyIndicatorBounds(@NonNull Rect[] staticBounds, @Surface.Rotation int rotation) {
+ mStaticBounds = staticBounds;
+ mRotation = rotation;
+ }
+
+ /**
+ * Return a PrivacyIndicatorBounds with updated static bounds
+ */
+ public PrivacyIndicatorBounds updateStaticBounds(@NonNull Rect[] staticPositions) {
+ return new PrivacyIndicatorBounds(staticPositions, mRotation);
+ }
+
+ /**
+ * Update the bounds of the indicator for a specific rotation, or ROTATION_0, if the provided
+ * rotation integer isn't found
+ */
+ public PrivacyIndicatorBounds updateBoundsForRotation(@Nullable Rect bounds,
+ @Surface.Rotation int rotation) {
+ if (rotation >= mStaticBounds.length || rotation < 0) {
+ return this;
+ }
+ Rect[] newBounds = ArrayUtils.cloneOrNull(mStaticBounds);
+ newBounds[rotation] = bounds;
+ return updateStaticBounds(newBounds);
+ }
+
+ /**
+ * Return an inset PrivacyIndicatorBounds
+ */
+ public PrivacyIndicatorBounds inset(int insetLeft, int insetTop, int insetRight,
+ int insetBottom) {
+ if (insetLeft == 0 && insetTop == 0 && insetRight == 0 && insetBottom == 0) {
+ return this;
+ }
+ Rect[] insetStaticBounds = new Rect[mStaticBounds.length];
+ for (int i = 0; i < mStaticBounds.length; i++) {
+ insetStaticBounds[i] =
+ insetRect(mStaticBounds[i], insetLeft, insetTop, insetRight, insetBottom);
+ }
+ return updateStaticBounds(insetStaticBounds);
+ }
+
+ private static Rect insetRect(Rect orig, int insetLeft, int insetTop, int insetRight,
+ int insetBottom) {
+ if (orig == null) {
+ return null;
+ }
+ int left = Math.max(0, orig.left - insetLeft);
+ int top = Math.max(0, orig.top - insetTop);
+ int right = Math.max(left, orig.right - insetRight);
+ int bottom = Math.max(top, orig.bottom - insetBottom);
+ return new Rect(left, top, right, bottom);
+ }
+
+ /**
+ * Return a PrivacyIndicatorBounds with the static position rotated.
+ */
+ public PrivacyIndicatorBounds rotate(@Surface.Rotation int rotation) {
+ if (rotation == ROTATION_0) {
+ return this;
+ }
+ return new PrivacyIndicatorBounds(mStaticBounds, rotation);
+ }
+
+ /**
+ * Returns a scaled PrivacyIndicatorBounds
+ */
+ public PrivacyIndicatorBounds scale(float scale) {
+ if (scale == 1f) {
+ return this;
+ }
+
+ Rect[] scaledStaticPos = new Rect[mStaticBounds.length];
+ for (int i = 0; i < mStaticBounds.length; i++) {
+ scaledStaticPos[i] = scaleRect(mStaticBounds[i], scale);
+ }
+ return new PrivacyIndicatorBounds(scaledStaticPos, mRotation);
+ }
+
+ private static Rect scaleRect(Rect orig, float scale) {
+ if (orig == null) {
+ return null;
+ }
+
+ Rect newRect = new Rect(orig);
+ newRect.scale(scale);
+ return newRect;
+ }
+
+ public Rect getStaticPrivacyIndicatorBounds() {
+ return mStaticBounds[mRotation];
+ }
+
+ @Override
+ public String toString() {
+ return "PrivacyIndicatorBounds {static bounds=" + getStaticPrivacyIndicatorBounds()
+ + " rotation=" + mRotation + "}";
+ }
+
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/PrivacyIndicatorBounds.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ @Override
+ @DataClass.Generated.Member
+ public boolean equals(@Nullable Object o) {
+ // You can override field equality logic by defining either of the methods like:
+ // boolean fieldNameEquals(PrivacyIndicatorBounds other) { ... }
+ // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ PrivacyIndicatorBounds that = (PrivacyIndicatorBounds) o;
+ //noinspection PointlessBooleanExpression
+ return true
+ && java.util.Arrays.equals(mStaticBounds, that.mStaticBounds)
+ && mRotation == that.mRotation;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int hashCode() {
+ // You can override field hashCode logic by defining methods like:
+ // int fieldNameHashCode() { ... }
+
+ int _hash = 1;
+ _hash = 31 * _hash + java.util.Arrays.hashCode(mStaticBounds);
+ _hash = 31 * _hash + mRotation;
+ return _hash;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeTypedArray(mStaticBounds, flags);
+ dest.writeInt(mRotation);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ protected PrivacyIndicatorBounds(@NonNull android.os.Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ Rect[] staticBounds = (Rect[]) in.createTypedArray(Rect.CREATOR);
+ int rotation = in.readInt();
+
+ this.mStaticBounds = staticBounds;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mStaticBounds);
+ this.mRotation = rotation;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<PrivacyIndicatorBounds> CREATOR
+ = new Parcelable.Creator<PrivacyIndicatorBounds>() {
+ @Override
+ public PrivacyIndicatorBounds[] newArray(int size) {
+ return new PrivacyIndicatorBounds[size];
+ }
+
+ @Override
+ public PrivacyIndicatorBounds createFromParcel(@NonNull android.os.Parcel in) {
+ return new PrivacyIndicatorBounds(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1621526273838L,
+ codegenVersion = "1.0.23",
+ sourceFile = "frameworks/base/core/java/android/view/PrivacyIndicatorBounds.java",
+ inputSignatures = "private final @android.annotation.NonNull android.graphics.Rect[] mStaticBounds\nprivate final int mRotation\npublic android.view.PrivacyIndicatorBounds updateStaticBounds(android.graphics.Rect[])\npublic android.view.PrivacyIndicatorBounds updateBoundsForRotation(android.graphics.Rect,int)\npublic android.view.PrivacyIndicatorBounds inset(int,int,int,int)\nprivate static android.graphics.Rect insetRect(android.graphics.Rect,int,int,int,int)\npublic android.view.PrivacyIndicatorBounds rotate(int)\npublic android.view.PrivacyIndicatorBounds scale(float)\nprivate static android.graphics.Rect scaleRect(android.graphics.Rect,float)\npublic android.graphics.Rect getStaticPrivacyIndicatorBounds()\npublic @java.lang.Override java.lang.String toString()\nclass PrivacyIndicatorBounds extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genConstructor=false, genAidl=false, genGetters=false)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 2fce434..6b0bb9d 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -571,7 +571,10 @@
// recreate this Surface, so only release it when we are fully
// detached.
if (mSurfacePackage != null) {
- mTmpTransaction.reparent(mSurfacePackage.getSurfaceControl(), null).apply();
+ final SurfaceControl sc = mSurfacePackage.getSurfaceControl();
+ if (sc != null && sc.isValid()) {
+ mTmpTransaction.reparent(sc, null).apply();
+ }
mSurfacePackage.release();
mSurfacePackage = null;
}
@@ -1826,7 +1829,7 @@
*/
public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) {
final SurfaceControl lastSc = mSurfacePackage != null ?
- mSurfacePackage.getSurfaceControl() : null;
+ mSurfacePackage.getSurfaceControl() : null;
if (mSurfaceControl != null && lastSc != null) {
mTmpTransaction.reparent(lastSc, null).apply();
mSurfacePackage.release();
@@ -1839,8 +1842,11 @@
private void reparentSurfacePackage(SurfaceControl.Transaction t,
SurfaceControlViewHost.SurfacePackage p) {
- initEmbeddedHierarchyForAccessibility(p);
final SurfaceControl sc = p.getSurfaceControl();
+ if (sc == null || !sc.isValid()) {
+ return;
+ }
+ initEmbeddedHierarchyForAccessibility(p);
final SurfaceControl parent;
if (mUseBlastAdapter) {
parent = mBlastSurfaceControl;
diff --git a/core/java/android/view/TunnelModeEnabledListener.java b/core/java/android/view/TunnelModeEnabledListener.java
new file mode 100644
index 0000000..c158da9
--- /dev/null
+++ b/core/java/android/view/TunnelModeEnabledListener.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Listens for tunnel mode enabled/disabled events from SurfaceFlinger.
+ * {@hide}
+ */
+public abstract class TunnelModeEnabledListener {
+
+ private long mNativeListener;
+ private final Executor mExecutor;
+
+ public TunnelModeEnabledListener(Executor executor) {
+ mExecutor = executor;
+ mNativeListener = nativeCreate(this);
+ }
+
+ /**
+ * Destroys the listener.
+ */
+ public void destroy() {
+ if (mNativeListener == 0) {
+ return;
+ }
+ unregister(this);
+ nativeDestroy(mNativeListener);
+ mNativeListener = 0;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ destroy();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Reports when tunnel mode has been enabled/disabled.
+ */
+ public abstract void onTunnelModeEnabledChanged(boolean tunnelModeEnabled);
+
+ /**
+ * Registers a listener.
+ */
+ public static void register(TunnelModeEnabledListener listener) {
+ if (listener.mNativeListener == 0) {
+ return;
+ }
+ nativeRegister(listener.mNativeListener);
+ }
+
+ /**
+ * Unregisters a listener.
+ */
+ public static void unregister(TunnelModeEnabledListener listener) {
+ if (listener.mNativeListener == 0) {
+ return;
+ }
+ nativeUnregister(listener.mNativeListener);
+ }
+
+ /**
+ * Dispatch tunnel mode enabled.
+ *
+ * Called from native code on a binder thread.
+ */
+ @VisibleForTesting
+ public static void dispatchOnTunnelModeEnabledChanged(TunnelModeEnabledListener listener,
+ boolean tunnelModeEnabled) {
+ listener.mExecutor.execute(() -> listener.onTunnelModeEnabledChanged(tunnelModeEnabled));
+ }
+
+ private static native long nativeCreate(TunnelModeEnabledListener thiz);
+ private static native void nativeDestroy(long ptr);
+ private static native void nativeRegister(long ptr);
+ private static native void nativeUnregister(long ptr);
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index acc0fc1..908d236 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3514,6 +3514,7 @@
* 11 PFLAG4_SCROLL_CAPTURE_HINT_MASK
* 1 PFLAG4_ALLOW_CLICK_WHEN_DISABLED
* 1 PFLAG4_DETACHED
+ * 1 PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE
* |-------|-------|-------|-------|
*/
@@ -3580,6 +3581,11 @@
*/
private static final int PFLAG4_DETACHED = 0x000002000;
+ /**
+ * Indicates that the view has transient state because the system is translating it.
+ */
+ private static final int PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE = 0x000004000;
+
/* End of masks for mPrivateFlags4 */
/** @hide */
@@ -9046,22 +9052,27 @@
* content into this view.
*
* <p>Depending on the type of view, this listener may be invoked for different scenarios. For
- * example, for editable TextViews, this listener will be invoked for the following scenarios:
+ * example, for an editable {@link android.widget.TextView}, this listener will be invoked for
+ * the following scenarios:
* <ol>
* <li>Paste from the clipboard (e.g. "Paste" or "Paste as plain text" action in the
* insertion/selection menu)
* <li>Content insertion from the keyboard (from {@link InputConnection#commitContent})
- * <li>Drag and drop (drop events from {@link #onDragEvent(DragEvent)})
+ * <li>Drag and drop (drop events from {@link #onDragEvent})
* <li>Autofill
* <li>Selection replacement via {@link Intent#ACTION_PROCESS_TEXT}
* </ol>
*
- * <p>When setting a listener, clients should also declare the MIME types accepted by it.
- * When invoked with other types of content, the listener may reject the content (defer to
- * the default platform behavior) or execute some other fallback logic. The MIME types
- * declared here allow different features to optionally alter their behavior. For example,
- * the soft keyboard may choose to hide its UI for inserting GIFs for a particular input
- * field if the MIME types set here for that field don't include "image/gif" or "image/*".
+ * <p>When setting a listener, clients must also declare the accepted MIME types.
+ * The listener will still be invoked even if the MIME type of the content is not one of the
+ * declared MIME types (e.g. if the user pastes content whose type is not one of the declared
+ * MIME types).
+ * In that case, the listener may reject the content (defer to the default platform behavior)
+ * or execute some other fallback logic (e.g. show an appropriate message to the user).
+ * The declared MIME types serve as a hint to allow different features to optionally alter
+ * their behavior. For example, a soft keyboard may optionally choose to hide its UI for
+ * inserting GIFs for a particular input field if the MIME types set here for that field
+ * don't include "image/gif" or "image/*".
*
* <p>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC
* MIME types. As a result, you should always write your MIME types with lowercase letters,
@@ -9817,30 +9828,37 @@
if (mContext.getContentCaptureOptions() == null) return;
if (appeared) {
- if (!isLaidOut() || getVisibility() != VISIBLE
- || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) {
+ // The appeared event stops sending to AiAi.
+ // 1. The view is hidden.
+ // 2. The same event was sent.
+ // 3. The view is not laid out, and it will be laid out in the future.
+ // Some recycled views cached its layout and a relayout is unnecessary. In this case,
+ // system still needs to notify content capture the view appeared. When a view is
+ // recycled, it will set the flag PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED.
+ final boolean isRecycledWithoutRelayout = getNotifiedContentCaptureDisappeared()
+ && getVisibility() == VISIBLE
+ && !isLayoutRequested();
+ if (getVisibility() != VISIBLE || getNotifiedContentCaptureAppeared()
+ || !(isLaidOut() || isRecycledWithoutRelayout)) {
if (DEBUG_CONTENT_CAPTURE) {
Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid="
+ isLaidOut() + ", visibleToUser=" + isVisibleToUser()
+ ", visible=" + (getVisibility() == VISIBLE)
- + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4
- & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0)
- + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4
- & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0));
+ + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared()
+ + ", alreadyNotifiedDisappeared="
+ + getNotifiedContentCaptureDisappeared());
}
return;
}
} else {
- if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) == 0
- || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0) {
+ if (!getNotifiedContentCaptureAppeared() || getNotifiedContentCaptureDisappeared()) {
if (DEBUG_CONTENT_CAPTURE) {
Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": laid="
+ isLaidOut() + ", visibleToUser=" + isVisibleToUser()
+ ", visible=" + (getVisibility() == VISIBLE)
- + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4
- & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0)
- + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4
- & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0));
+ + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared()
+ + ", alreadyNotifiedDisappeared="
+ + getNotifiedContentCaptureDisappeared());
}
return;
}
@@ -9888,6 +9906,10 @@
}
+ private boolean getNotifiedContentCaptureDisappeared() {
+ return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0;
+ }
+
/**
* Sets the (optional) {@link ContentCaptureSession} associated with this view.
*
@@ -12266,6 +12288,30 @@
}
/**
+ * Set the view is tracking translation transient state. This flag is used to check if the view
+ * need to call setHasTransientState(false) to reset transient state that set when starting
+ * translation.
+ *
+ * @param hasTranslationTransientState true if this view has translation transient state
+ * @hide
+ */
+ public void setHasTranslationTransientState(boolean hasTranslationTransientState) {
+ if (hasTranslationTransientState) {
+ mPrivateFlags4 |= PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE;
+ } else {
+ mPrivateFlags4 &= ~PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public boolean hasTranslationTransientState() {
+ return (mPrivateFlags4 & PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE)
+ == PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE;
+ }
+
+ /**
* Returns true if this view is currently attached to a window.
*/
public boolean isAttachedToWindow() {
@@ -30834,6 +30880,9 @@
}
/**
+ * Returns a {@link ViewTranslationCallback} that is used to display the translated information
+ * or {@code null} if this View doesn't support translation.
+ *
* @hide
*/
@Nullable
@@ -30920,7 +30969,8 @@
* view or calls {@link View#onVirtualViewTranslationResponses} for view contains virtual
* children to build {@link ViewTranslationRequest} if the view should be translated.
* The view is marked as having {@link #setHasTransientState(boolean) transient state} so that
- * recycling of views doesn't prevent the system from attaching the response to it.</p>
+ * recycling of views doesn't prevent the system from attaching the response to it. Therefore,
+ * if overriding this method, you should set or reset the transient state. </p>
*
* @param viewIds a map for the view's {@link AutofillId} and its virtual child ids or
* {@code null} if the view doesn't have virtual child that should be translated. The virtual
@@ -30970,10 +31020,8 @@
Log.v(CONTENT_CAPTURE_LOG_TAG, "Calling setHasTransientState(true) for "
+ getAutofillId());
}
- // TODO: Add a default ViewTranslationCallback for View that resets this in
- // onClearTranslation(). Also update the javadoc for this method to mention
- // that.
setHasTransientState(true);
+ setHasTranslationTransientState(true);
}
}
}
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 41c38a1..0f1a9d9 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -17,6 +17,7 @@
package android.view;
+import static android.view.Surface.ROTATION_0;
import static android.view.WindowInsets.Type.DISPLAY_CUTOUT;
import static android.view.WindowInsets.Type.FIRST;
import static android.view.WindowInsets.Type.IME;
@@ -83,6 +84,7 @@
private final boolean mIsRound;
@Nullable private final DisplayCutout mDisplayCutout;
@Nullable private final RoundedCorners mRoundedCorners;
+ @Nullable private final PrivacyIndicatorBounds mPrivacyIndicatorBounds;
/**
* In multi-window we force show the navigation bar. Because we don't want that the surface size
@@ -131,8 +133,8 @@
boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
this(createCompatTypeMap(systemWindowInsetsRect), createCompatTypeMap(stableInsetsRect),
createCompatVisibilityMap(createCompatTypeMap(systemWindowInsetsRect)),
- isRound, alwaysConsumeSystemBars, displayCutout, null, systemBars(),
- false /* compatIgnoreVisibility */);
+ isRound, alwaysConsumeSystemBars, displayCutout, null, null,
+ systemBars(), false /* compatIgnoreVisibility */);
}
/**
@@ -152,8 +154,9 @@
boolean[] typeVisibilityMap,
boolean isRound,
boolean alwaysConsumeSystemBars, DisplayCutout displayCutout,
- RoundedCorners roundedCorners, @InsetsType int compatInsetsTypes,
- boolean compatIgnoreVisibility) {
+ RoundedCorners roundedCorners,
+ PrivacyIndicatorBounds privacyIndicatorBounds,
+ @InsetsType int compatInsetsTypes, boolean compatIgnoreVisibility) {
mSystemWindowInsetsConsumed = typeInsetsMap == null;
mTypeInsetsMap = mSystemWindowInsetsConsumed
? new Insets[SIZE]
@@ -175,6 +178,7 @@
? null : displayCutout;
mRoundedCorners = roundedCorners;
+ mPrivacyIndicatorBounds = privacyIndicatorBounds;
}
/**
@@ -188,6 +192,7 @@
src.mTypeVisibilityMap, src.mIsRound,
src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src),
src.mRoundedCorners,
+ src.mPrivacyIndicatorBounds,
src.mCompatInsetsTypes,
src.mCompatIgnoreVisibility);
}
@@ -241,7 +246,7 @@
@UnsupportedAppUsage
public WindowInsets(Rect systemWindowInsets) {
this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null,
- null, systemBars(), false /* compatIgnoreVisibility */);
+ null, null, systemBars(), false /* compatIgnoreVisibility */);
}
/**
@@ -510,6 +515,19 @@
}
/**
+ * Returns the {@link Rect} of the maximum bounds of the system privacy indicator, for the
+ * current orientation, in relative coordinates, or null if the bounds have not been loaded yet.
+ * The privacy indicator shows over apps when an app uses the microphone or camera permissions,
+ * while an app is in immersive mode.
+ *
+ * @return A rectangle representing the maximum bounds of the indicator
+ */
+ public @Nullable Rect getPrivacyIndicatorBounds() {
+ return mPrivacyIndicatorBounds == null ? null
+ : mPrivacyIndicatorBounds.getStaticPrivacyIndicatorBounds();
+ }
+
+ /**
* Returns a copy of this WindowInsets with the cutout fully consumed.
*
* @return A modified copy of this WindowInsets
@@ -524,7 +542,7 @@
mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
- null /* displayCutout */, mRoundedCorners,
+ null /* displayCutout */, mRoundedCorners, mPrivacyIndicatorBounds,
mCompatInsetsTypes, mCompatIgnoreVisibility);
}
@@ -576,7 +594,8 @@
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
displayCutoutCopyConstructorArgument(this),
- mRoundedCorners, mCompatInsetsTypes, mCompatIgnoreVisibility);
+ mRoundedCorners, mPrivacyIndicatorBounds, mCompatInsetsTypes,
+ mCompatIgnoreVisibility);
}
// TODO(b/119190588): replace @code with @link below
@@ -881,6 +900,9 @@
result.append("\n ");
result.append(mRoundedCorners != null ? "roundedCorners=" + mRoundedCorners : "");
result.append("\n ");
+ result.append(mPrivacyIndicatorBounds != null ? "privacyIndicatorBounds="
+ + mPrivacyIndicatorBounds : "");
+ result.append("\n ");
result.append(isRound() ? "round" : "");
result.append("}");
return result.toString();
@@ -975,6 +997,9 @@
mRoundedCorners == null
? RoundedCorners.NO_ROUNDED_CORNERS
: mRoundedCorners.inset(left, top, right, bottom),
+ mPrivacyIndicatorBounds == null
+ ? null
+ : mPrivacyIndicatorBounds.inset(left, top, right, bottom),
mCompatInsetsTypes, mCompatIgnoreVisibility);
}
@@ -993,7 +1018,8 @@
&& Arrays.equals(mTypeMaxInsetsMap, that.mTypeMaxInsetsMap)
&& Arrays.equals(mTypeVisibilityMap, that.mTypeVisibilityMap)
&& Objects.equals(mDisplayCutout, that.mDisplayCutout)
- && Objects.equals(mRoundedCorners, that.mRoundedCorners);
+ && Objects.equals(mRoundedCorners, that.mRoundedCorners)
+ && Objects.equals(mPrivacyIndicatorBounds, that.mPrivacyIndicatorBounds);
}
@Override
@@ -1001,7 +1027,7 @@
return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap),
Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout, mRoundedCorners,
mAlwaysConsumeSystemBars, mSystemWindowInsetsConsumed, mStableInsetsConsumed,
- mDisplayCutoutConsumed);
+ mDisplayCutoutConsumed, mPrivacyIndicatorBounds);
}
@@ -1066,6 +1092,8 @@
private boolean mIsRound;
private boolean mAlwaysConsumeSystemBars;
+ private PrivacyIndicatorBounds mPrivacyIndicatorBounds = new PrivacyIndicatorBounds();
+
/**
* Creates a builder where all insets are initially consumed.
*/
@@ -1090,6 +1118,7 @@
mRoundedCorners = insets.mRoundedCorners;
mIsRound = insets.mIsRound;
mAlwaysConsumeSystemBars = insets.mAlwaysConsumeSystemBars;
+ mPrivacyIndicatorBounds = insets.mPrivacyIndicatorBounds;
}
/**
@@ -1316,6 +1345,26 @@
/** @hide */
@NonNull
+ public Builder setPrivacyIndicatorBounds(@Nullable PrivacyIndicatorBounds bounds) {
+ mPrivacyIndicatorBounds = bounds;
+ return this;
+ }
+
+ /**
+ * Sets the bounds of the system privacy indicator.
+ *
+ * @param bounds The bounds of the system privacy indicator
+ */
+ @NonNull
+ public Builder setPrivacyIndicatorBounds(@Nullable Rect bounds) {
+ //TODO 188788786: refactor the indicator bounds
+ Rect[] boundsArr = { bounds, bounds, bounds, bounds };
+ mPrivacyIndicatorBounds = new PrivacyIndicatorBounds(boundsArr, ROTATION_0);
+ return this;
+ }
+
+ /** @hide */
+ @NonNull
public Builder setRound(boolean round) {
mIsRound = round;
return this;
@@ -1338,7 +1387,7 @@
return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout, mRoundedCorners,
- systemBars(), false /* compatIgnoreVisibility */);
+ mPrivacyIndicatorBounds, systemBars(), false /* compatIgnoreVisibility */);
}
}
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
index c8c1d87..fbc9470 100644
--- a/core/java/android/view/inputmethod/CursorAnchorInfo.java
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -389,7 +389,7 @@
"required when positional parameters are specified.");
}
}
- return CursorAnchorInfo.create(this);
+ return new CursorAnchorInfo(this);
}
/**
@@ -413,90 +413,30 @@
}
}
- private static CursorAnchorInfo create(Builder builder) {
- final SparseRectFArray characterBoundsArray =
- builder.mCharacterBoundsArrayBuilder != null
- ? builder.mCharacterBoundsArrayBuilder.build()
- : null;
- final float[] matrixValues = new float[9];
+ private CursorAnchorInfo(final Builder builder) {
+ mSelectionStart = builder.mSelectionStart;
+ mSelectionEnd = builder.mSelectionEnd;
+ mComposingTextStart = builder.mComposingTextStart;
+ mComposingText = builder.mComposingText;
+ mInsertionMarkerFlags = builder.mInsertionMarkerFlags;
+ mInsertionMarkerHorizontal = builder.mInsertionMarkerHorizontal;
+ mInsertionMarkerTop = builder.mInsertionMarkerTop;
+ mInsertionMarkerBaseline = builder.mInsertionMarkerBaseline;
+ mInsertionMarkerBottom = builder.mInsertionMarkerBottom;
+ mCharacterBoundsArray = builder.mCharacterBoundsArrayBuilder != null
+ ? builder.mCharacterBoundsArrayBuilder.build() : null;
+ mMatrixValues = new float[9];
if (builder.mMatrixInitialized) {
- System.arraycopy(builder.mMatrixValues, 0, matrixValues, 0, 9);
+ System.arraycopy(builder.mMatrixValues, 0, mMatrixValues, 0, 9);
} else {
- Matrix.IDENTITY_MATRIX.getValues(matrixValues);
+ Matrix.IDENTITY_MATRIX.getValues(mMatrixValues);
}
- return new CursorAnchorInfo(builder.mSelectionStart, builder.mSelectionEnd,
- builder.mComposingTextStart, builder.mComposingText, builder.mInsertionMarkerFlags,
- builder.mInsertionMarkerHorizontal, builder.mInsertionMarkerTop,
- builder.mInsertionMarkerBaseline, builder.mInsertionMarkerBottom,
- characterBoundsArray, matrixValues);
- }
-
- private CursorAnchorInfo(int selectionStart, int selectionEnd, int composingTextStart,
- @Nullable CharSequence composingText, int insertionMarkerFlags,
- float insertionMarkerHorizontal, float insertionMarkerTop,
- float insertionMarkerBaseline, float insertionMarkerBottom,
- @Nullable SparseRectFArray characterBoundsArray, @NonNull float[] matrixValues) {
- mSelectionStart = selectionStart;
- mSelectionEnd = selectionEnd;
- mComposingTextStart = composingTextStart;
- mComposingText = composingText;
- mInsertionMarkerFlags = insertionMarkerFlags;
- mInsertionMarkerHorizontal = insertionMarkerHorizontal;
- mInsertionMarkerTop = insertionMarkerTop;
- mInsertionMarkerBaseline = insertionMarkerBaseline;
- mInsertionMarkerBottom = insertionMarkerBottom;
- mCharacterBoundsArray = characterBoundsArray;
- mMatrixValues = matrixValues;
-
// To keep hash function simple, we only use some complex objects for hash.
- int hashCode = Objects.hashCode(mComposingText);
- hashCode *= 31;
- hashCode += Arrays.hashCode(matrixValues);
- mHashCode = hashCode;
- }
-
- /**
- * Creates a new instance of {@link CursorAnchorInfo} by applying {@code parentMatrix} to
- * the coordinate transformation matrix.
- *
- * @param original {@link CursorAnchorInfo} to be cloned from.
- * @param parentMatrix {@link Matrix} to be applied to {@code original.getMatrix()}
- * @return A new instance of {@link CursorAnchorInfo} whose {@link CursorAnchorInfo#getMatrix()}
- * returns {@code parentMatrix * original.getMatrix()}.
- * @hide
- */
- public static CursorAnchorInfo createForAdditionalParentMatrix(CursorAnchorInfo original,
- @NonNull Matrix parentMatrix) {
- return new CursorAnchorInfo(original.mSelectionStart, original.mSelectionEnd,
- original.mComposingTextStart, original.mComposingText,
- original.mInsertionMarkerFlags, original.mInsertionMarkerHorizontal,
- original.mInsertionMarkerTop, original.mInsertionMarkerBaseline,
- original.mInsertionMarkerBottom, original.mCharacterBoundsArray,
- computeMatrixValues(parentMatrix, original));
- }
-
- /**
- * Returns a float array that represents {@link Matrix} elements for
- * {@code parentMatrix * info.getMatrix()}.
- *
- * @param parentMatrix {@link Matrix} to be multiplied.
- * @param info {@link CursorAnchorInfo} to provide {@link Matrix} to be multiplied.
- * @return {@code parentMatrix * info.getMatrix()}.
- */
- private static float[] computeMatrixValues(@NonNull Matrix parentMatrix,
- @NonNull CursorAnchorInfo info) {
- if (parentMatrix.isIdentity()) {
- return info.mMatrixValues;
- }
-
- final Matrix newMatrix = new Matrix();
- newMatrix.setValues(info.mMatrixValues);
- newMatrix.postConcat(parentMatrix);
-
- final float[] matrixValues = new float[9];
- newMatrix.getValues(matrixValues);
- return matrixValues;
+ int hash = Objects.hashCode(mComposingText);
+ hash *= 31;
+ hash += Arrays.hashCode(mMatrixValues);
+ mHashCode = hash;
}
/**
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 7eb8400..b572d08 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -49,7 +49,6 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.graphics.Matrix;
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
import android.os.Binder;
@@ -443,17 +442,6 @@
private CursorAnchorInfo mCursorAnchorInfo = null;
/**
- * A special {@link Matrix} that can be provided by the system when this instance is running
- * inside a virtual display that is managed by {@link android.app.ActivityView}.
- *
- * <p>If this is non-{@code null}, {@link #updateCursorAnchorInfo(View, CursorAnchorInfo)}
- * should be adjusted with this {@link Matrix}.</p>
- *
- * <p>{@code null} when not used.</p>
- */
- private Matrix mActivityViewToScreenMatrix = null;
-
- /**
* As reported by {@link InputBindResult}. This value is determined by
* {@link com.android.internal.R.styleable#InputMethod_suppressesSpellChecking}.
*/
@@ -520,7 +508,6 @@
static final int MSG_TIMEOUT_INPUT_EVENT = 6;
static final int MSG_FLUSH_INPUT_EVENT = 7;
static final int MSG_REPORT_FULLSCREEN_MODE = 10;
- static final int MSG_UPDATE_ACTIVITY_VIEW_TO_SCREEN_MATRIX = 30;
private static boolean isAutofillUIShowing(View servedView) {
AutofillManager afm = servedView.getContext().getSystemService(AutofillManager.class);
@@ -895,7 +882,6 @@
InputMethodSessionWrapper.createOrNull(res.method);
mCurId = res.id;
mBindSequence = res.sequence;
- mActivityViewToScreenMatrix = res.getActivityViewToScreenMatrix();
mIsInputMethodSuppressingSpellChecker =
res.isInputMethodSuppressingSpellChecker;
}
@@ -1002,45 +988,6 @@
}
return;
}
- case MSG_UPDATE_ACTIVITY_VIEW_TO_SCREEN_MATRIX: {
- final float[] matrixValues = (float[]) msg.obj;
- final int bindSequence = msg.arg1;
- synchronized (mH) {
- if (mBindSequence != bindSequence) {
- return;
- }
- if (matrixValues == null || mActivityViewToScreenMatrix == null) {
- // Either InputBoundResult#mActivityViewToScreenMatrixValues is null
- // OR this app is unbound from the parent ActivityView. In this case,
- // calling updateCursorAnchorInfo() isn't safe. Only clear the matrix.
- mActivityViewToScreenMatrix = null;
- return;
- }
-
- final float[] currentValues = new float[9];
- mActivityViewToScreenMatrix.getValues(currentValues);
- if (Arrays.equals(currentValues, matrixValues)) {
- return;
- }
- mActivityViewToScreenMatrix.setValues(matrixValues);
-
- if (mCursorAnchorInfo == null || mCurrentInputMethodSession == null
- || mServedInputConnectionWrapper == null) {
- return;
- }
- final boolean isMonitoring = (mRequestUpdateCursorAnchorInfoMonitorMode
- & InputConnection.CURSOR_UPDATE_MONITOR) != 0;
- if (!isMonitoring) {
- return;
- }
- // Since the host ActivityView is moved, we need to issue
- // IMS#updateCursorAnchorInfo() again.
- mCurrentInputMethodSession.updateCursorAnchorInfo(
- CursorAnchorInfo.createForAdditionalParentMatrix(
- mCursorAnchorInfo, mActivityViewToScreenMatrix));
- }
- return;
- }
}
}
}
@@ -1096,12 +1043,6 @@
}
@Override
- public void updateActivityViewToScreenMatrix(int bindSequence, float[] matrixValues) {
- mH.obtainMessage(MSG_UPDATE_ACTIVITY_VIEW_TO_SCREEN_MATRIX, bindSequence, 0,
- matrixValues).sendToTarget();
- }
-
- @Override
public void setImeTraceEnabled(boolean enabled) {
ImeTracing.getInstance().setEnabled(enabled);
}
@@ -1557,7 +1498,6 @@
*/
@UnsupportedAppUsage
void finishInputLocked() {
- mActivityViewToScreenMatrix = null;
mIsInputMethodSuppressingSpellChecker = false;
setNextServedViewLocked(null);
if (getServedViewLocked() != null) {
@@ -2110,7 +2050,6 @@
+ InputMethodDebug.startInputFlagsToString(startInputFlags));
return false;
}
- mActivityViewToScreenMatrix = res.getActivityViewToScreenMatrix();
mIsInputMethodSuppressingSpellChecker = res.isInputMethodSuppressingSpellChecker;
if (res.id != null) {
setInputChannelLocked(res.channel);
@@ -2499,13 +2438,7 @@
return;
}
if (DEBUG) Log.v(TAG, "updateCursorAnchorInfo: " + cursorAnchorInfo);
- if (mActivityViewToScreenMatrix != null) {
- mCurrentInputMethodSession.updateCursorAnchorInfo(
- CursorAnchorInfo.createForAdditionalParentMatrix(
- cursorAnchorInfo, mActivityViewToScreenMatrix));
- } else {
- mCurrentInputMethodSession.updateCursorAnchorInfo(cursorAnchorInfo);
- }
+ mCurrentInputMethodSession.updateCursorAnchorInfo(cursorAnchorInfo);
mCursorAnchorInfo = cursorAnchorInfo;
// Clear immediate bit (if any).
mRequestUpdateCursorAnchorInfoMonitorMode &= ~InputConnection.CURSOR_UPDATE_IMMEDIATE;
@@ -3097,30 +3030,6 @@
}
/**
- * An internal API for {@link android.app.ActivityView} to report where its embedded virtual
- * display is placed.
- *
- * @param childDisplayId Display ID of the embedded virtual display.
- * @param matrix {@link Matrix} to convert virtual display screen coordinates to
- * the host screen coordinates. {@code null} to clear the relationship.
- * @hide
- */
- public void reportActivityView(int childDisplayId, @Nullable Matrix matrix) {
- try {
- final float[] matrixValues;
- if (matrix == null) {
- matrixValues = null;
- } else {
- matrixValues = new float[9];
- matrix.getValues(matrixValues);
- }
- mService.reportActivityViewAsync(mClient, childDisplayId, matrixValues);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Force switch to the last used input method and subtype. If the last input method didn't have
* any subtypes, the framework will simply switch to the last input method with no subtype
* specified.
diff --git a/core/java/android/view/translation/TranslationRequest.java b/core/java/android/view/translation/TranslationRequest.java
index da1baf9..df4836e 100644
--- a/core/java/android/view/translation/TranslationRequest.java
+++ b/core/java/android/view/translation/TranslationRequest.java
@@ -327,7 +327,9 @@
return this;
}
- /** @see #setTranslationRequestValues */
+ /** @see #setTranslationRequestValues
+ * @removed
+ */
@DataClass.Generated.Member
@Override
@Deprecated
@@ -350,7 +352,9 @@
return this;
}
- /** @see #setViewTranslationRequests */
+ /** @see #setViewTranslationRequests
+ * @removed
+ */
@DataClass.Generated.Member
@Override
@Deprecated
diff --git a/core/java/android/view/translation/TranslationResponse.java b/core/java/android/view/translation/TranslationResponse.java
index 7d23e19..b77f2e2 100644
--- a/core/java/android/view/translation/TranslationResponse.java
+++ b/core/java/android/view/translation/TranslationResponse.java
@@ -367,6 +367,7 @@
/**
* The translation result status code.
+ * @removed
*/
@DataClass.Generated.Member
@Override
@@ -447,7 +448,7 @@
}
@DataClass.Generated(
- time = 1620089618357L,
+ time = 1621972659130L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/translation/TranslationResponse.java",
inputSignatures = "public static final int TRANSLATION_STATUS_SUCCESS\npublic static final int TRANSLATION_STATUS_UNKNOWN_ERROR\npublic static final int TRANSLATION_STATUS_CONTEXT_UNSUPPORTED\nprivate final @android.view.translation.TranslationResponse.TranslationStatus int mTranslationStatus\nprivate final @android.annotation.NonNull android.util.SparseArray<android.view.translation.TranslationResponseValue> mTranslationResponseValues\nprivate final @android.annotation.NonNull android.util.SparseArray<android.view.translation.ViewTranslationResponse> mViewTranslationResponses\nprivate final boolean mFinalResponse\nprivate static android.util.SparseArray<android.view.translation.TranslationResponseValue> defaultTranslationResponseValues()\nprivate static android.util.SparseArray<android.view.translation.ViewTranslationResponse> defaultViewTranslationResponses()\nprivate static boolean defaultFinalResponse()\nclass TranslationResponse extends java.lang.Object implements [android.os.Parcelable]\npublic abstract @java.lang.Deprecated android.view.translation.TranslationResponse.Builder setTranslationStatus(int)\npublic @android.annotation.NonNull @java.lang.SuppressWarnings android.view.translation.TranslationResponse.Builder setTranslationResponseValue(int,android.view.translation.TranslationResponseValue)\npublic @android.annotation.NonNull @java.lang.SuppressWarnings android.view.translation.TranslationResponse.Builder setViewTranslationResponse(int,android.view.translation.ViewTranslationResponse)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genHiddenConstDefs=true)\npublic abstract @java.lang.Deprecated android.view.translation.TranslationResponse.Builder setTranslationStatus(int)\npublic @android.annotation.NonNull @java.lang.SuppressWarnings android.view.translation.TranslationResponse.Builder setTranslationResponseValue(int,android.view.translation.TranslationResponseValue)\npublic @android.annotation.NonNull @java.lang.SuppressWarnings android.view.translation.TranslationResponse.Builder setViewTranslationResponse(int,android.view.translation.ViewTranslationResponse)\nclass BaseBuilder extends java.lang.Object implements []")
diff --git a/core/java/android/view/translation/TranslationResponseValue.java b/core/java/android/view/translation/TranslationResponseValue.java
index a68ae56..e2ef5d3 100644
--- a/core/java/android/view/translation/TranslationResponseValue.java
+++ b/core/java/android/view/translation/TranslationResponseValue.java
@@ -49,7 +49,24 @@
* <p>The dictionary definitions consists of groups of terms keyed by their corresponding parts
* of speech. This map-like structure is stored in a {@link Bundle}. The individual parts of
* speech can be traversed by {@link Bundle#keySet()} and used to get the corresponding list
- * of terms as {@link CharSequence}s.</p>
+ * of terms as {@link CharSequence}s.
+ *
+ * <ul>
+ * <li>"noun" -> ["def1", "def2", ...]</li>
+ * <li>"verb" -> ["def3", "def4", ...]</li>
+ * <li>...</li>
+ * </ul>
+ *
+ * The set of parts of speech can then be used by
+ * {@link Bundle#getCharSequenceArrayList(String)} to get the list of terms.
+ *
+ * <b>Example</b>:
+ *
+ * {@code for (String partOfSpeech : extras.getBundle(EXTRA_DEFINITIONS).keySet()) {
+ * ArrayList<CharSequence> terms =
+ * extras.getBundle(EXTRA_DEFINITIONS).getCharSequenceArrayList(partOfSpeech);
+ * ...
+ * }}</p>
*/
public static final String EXTRA_DEFINITIONS = "android.view.translation.extra.DEFINITIONS";
@@ -70,7 +87,8 @@
/**
* Extra results associated with the translated text.
*
- * <p>The bundle includes {@link #EXTRA_DEFINITIONS}, obtained by {@link Bundle#getBundle}.</p>
+ * <p>The bundle includes {@link #EXTRA_DEFINITIONS}, obtained by {@link Bundle#getBundle}.
+ * </p>
*/
@NonNull
private final Bundle mExtras;
@@ -190,7 +208,8 @@
/**
* Extra results associated with the translated text.
*
- * <p>The bundle includes {@link #EXTRA_DEFINITIONS}, obtained by {@link Bundle#getBundle}.</p>
+ * <p>The bundle includes {@link #EXTRA_DEFINITIONS}, obtained by {@link Bundle#getBundle}.
+ * </p>
*/
@DataClass.Generated.Member
public @NonNull Bundle getExtras() {
@@ -370,7 +389,8 @@
/**
* Extra results associated with the translated text.
*
- * <p>The bundle includes {@link #EXTRA_DEFINITIONS}, obtained by {@link Bundle#getBundle}.</p>
+ * <p>The bundle includes {@link #EXTRA_DEFINITIONS}, obtained by {@link Bundle#getBundle}.
+ * </p>
*/
@DataClass.Generated.Member
public @NonNull Builder setExtras(@NonNull Bundle value) {
@@ -423,7 +443,7 @@
}
@DataClass.Generated(
- time = 1621034223313L,
+ time = 1621623218037L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/translation/TranslationResponseValue.java",
inputSignatures = "public static final int STATUS_SUCCESS\npublic static final int STATUS_ERROR\npublic static final java.lang.String EXTRA_DEFINITIONS\nprivate final @android.view.translation.TranslationResponseValue.Status int mStatusCode\nprivate final @android.annotation.Nullable java.lang.CharSequence mText\nprivate final @android.annotation.NonNull android.os.Bundle mExtras\nprivate final @android.annotation.Nullable java.lang.CharSequence mTransliteration\npublic static @android.annotation.NonNull android.view.translation.TranslationResponseValue forError()\nprivate static java.lang.CharSequence defaultText()\nprivate static android.os.Bundle defaultExtras()\nprivate static java.lang.CharSequence defaultTransliteration()\nclass TranslationResponseValue extends java.lang.Object implements [android.os.Parcelable]\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genEqualsHashCode=true, genHiddenConstDefs=true)\nclass BaseBuilder extends java.lang.Object implements []")
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index f79c329..4b2c343 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -43,6 +43,8 @@
import android.view.WindowManagerGlobal;
import android.view.autofill.AutofillId;
import android.view.translation.UiTranslationManager.UiTranslationState;
+import android.widget.TextView;
+import android.widget.TextViewTranslationCallback;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -146,7 +148,13 @@
break;
case STATE_UI_TRANSLATION_FINISHED:
destroyTranslators();
- runForEachView((view, callback) -> callback.onClearTranslation(view));
+ runForEachView((view, callback) -> {
+ callback.onClearTranslation(view);
+ if (view.hasTranslationTransientState()) {
+ view.setHasTransientState(false);
+ view.setHasTranslationTransientState(false);
+ }
+ });
synchronized (mLock) {
mViews.clear();
}
@@ -381,17 +389,23 @@
continue;
}
mActivity.runOnUiThread(() -> {
- final ViewTranslationCallback callback = view.getViewTranslationCallback();
+ ViewTranslationCallback callback = view.getViewTranslationCallback();
if (callback == null) {
- if (DEBUG) {
- Log.d(TAG, view + " doesn't support showing translation because of "
- + "null ViewTranslationCallback.");
+ if (view instanceof TextView) {
+ // developer doesn't provide their override, we set the default TextView
+ // implememtation.
+ callback = new TextViewTranslationCallback();
+ view.setViewTranslationCallback(callback);
+ if (mViewsToPadContent.contains(autofillId)) {
+ callback.enableContentPadding();
+ }
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, view + " doesn't support showing translation because of "
+ + "null ViewTranslationCallback.");
+ }
+ return;
}
- return;
- }
-
- if (mViewsToPadContent.contains(autofillId)) {
- callback.enableContentPadding();
}
view.onViewTranslationResponse(response);
callback.onShowTranslation(view);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 4d35655..5e2209e 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3574,28 +3574,27 @@
private void scrollIfNeeded(int x, int y, MotionEvent vtev) {
int rawDeltaY = y - mMotionY;
int scrollOffsetCorrection = 0;
- int scrollConsumedCorrection = 0;
if (mLastY == Integer.MIN_VALUE) {
rawDeltaY -= mMotionCorrection;
}
- if (dispatchNestedPreScroll(0, mLastY != Integer.MIN_VALUE ? mLastY - y : -rawDeltaY,
- mScrollConsumed, mScrollOffset)) {
+
+ int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : rawDeltaY;
+
+ // First allow releasing existing overscroll effect:
+ incrementalDeltaY = releaseGlow(incrementalDeltaY, x);
+
+ if (dispatchNestedPreScroll(0, -incrementalDeltaY, mScrollConsumed, mScrollOffset)) {
rawDeltaY += mScrollConsumed[1];
scrollOffsetCorrection = -mScrollOffset[1];
- scrollConsumedCorrection = mScrollConsumed[1];
+ incrementalDeltaY += mScrollConsumed[1];
if (vtev != null) {
vtev.offsetLocation(0, mScrollOffset[1]);
mNestedYOffset += mScrollOffset[1];
}
}
final int deltaY = rawDeltaY;
- int incrementalDeltaY =
- mLastY != Integer.MIN_VALUE ? y - mLastY + scrollConsumedCorrection : deltaY;
int lastYCorrection = 0;
- // First allow releasing existing overscroll effect:
- incrementalDeltaY = releaseGlow(incrementalDeltaY, x);
-
if (mTouchMode == TOUCH_MODE_SCROLL) {
if (PROFILE_SCROLLING) {
if (!mScrollProfilingStarted) {
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 5bb8a8e..40cce7c 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.AppGlobals;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -61,8 +62,9 @@
@Deprecated
public class AnalogClock extends View {
private static final String LOG_TAG = "AnalogClock";
+
/** How many times per second that the seconds hand advances. */
- private static final long SECONDS_HAND_FPS = 30;
+ private final int mSecondsHandFps;
private Clock mClock;
@Nullable
@@ -106,6 +108,10 @@
public AnalogClock(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ mSecondsHandFps = AppGlobals.getIntCoreSetting(
+ WidgetFlags.KEY_ANALOG_CLOCK_SECONDS_HAND_FPS,
+ WidgetFlags.ANALOG_CLOCK_SECONDS_HAND_FPS_DEFAULT);
+
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.AnalogClock, defStyleAttr, defStyleRes);
saveAttributeDataForStyleable(context, com.android.internal.R.styleable.AnalogClock,
@@ -743,7 +749,7 @@
// n positions between two given numbers, where n is the number of ticks per second. This
// ensures the second hand advances by a consistent distance despite our handler callbacks
// occurring at inconsistent frequencies.
- mSeconds = Math.round(rawSeconds * SECONDS_HAND_FPS) / (float) SECONDS_HAND_FPS;
+ mSeconds = Math.round(rawSeconds * mSecondsHandFps) / (float) mSecondsHandFps;
mMinutes = localTime.getMinute() + mSeconds / 60.0f;
mHour = localTime.getHour() + mMinutes / 60.0f;
mChanged = true;
@@ -781,7 +787,7 @@
// How many milliseconds through the second we currently are.
long millisOfSecond = Duration.ofNanos(localTime.getNano()).toMillis();
// How many milliseconds there are between tick positions for the seconds hand.
- double millisPerTick = 1000 / (double) SECONDS_HAND_FPS;
+ double millisPerTick = 1000 / (double) mSecondsHandFps;
// How many milliseconds we are past the last tick position.
long millisPastLastTick = Math.round(millisOfSecond % millisPerTick);
// How many milliseconds there are until the next tick position.
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 756e3ce..207385d 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -342,6 +342,9 @@
mGlowAlphaFinish = mGlowAlpha;
mGlowScaleYFinish = mGlowScaleY;
+ if (mEdgeEffectType == TYPE_STRETCH && mDistance == 0) {
+ mState = STATE_IDLE;
+ }
}
/**
@@ -739,8 +742,12 @@
private boolean isAtEquilibrium() {
double displacement = mDistance * mHeight; // in pixels
double velocity = mVelocity;
- return Math.abs(velocity) < VELOCITY_THRESHOLD
- && Math.abs(displacement) < VALUE_THRESHOLD;
+
+ // Don't allow displacement to drop below 0. We don't want it stretching the opposite
+ // direction if it is flung that way. We also want to stop the animation as soon as
+ // it gets very close to its destination.
+ return displacement < 0 || (Math.abs(velocity) < VELOCITY_THRESHOLD
+ && displacement < VALUE_THRESHOLD);
}
private float dampStretchVector(float normalizedVec) {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 4447361..0c4da88 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1725,23 +1725,15 @@
}
private void updateFloatingToolbarVisibility(MotionEvent event) {
- if (mTextActionMode == null) {
- return;
- }
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_MOVE:
- hideFloatingToolbar(ActionMode.DEFAULT_HIDE_DURATION);
- break;
- case MotionEvent.ACTION_UP: // fall through
- case MotionEvent.ACTION_CANCEL:
- final SelectionModifierCursorController selectionController =
- getSelectionController();
- final InsertionPointCursorController insertionController = getInsertionController();
- if ((selectionController != null && selectionController.isCursorBeingModified())
- || (insertionController != null
- && insertionController.isCursorBeingModified())) {
+ if (mTextActionMode != null) {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_MOVE:
+ hideFloatingToolbar(ActionMode.DEFAULT_HIDE_DURATION);
+ break;
+ case MotionEvent.ACTION_UP: // fall through
+ case MotionEvent.ACTION_CANCEL:
showFloatingToolbar();
- }
+ }
}
}
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 7c04b1c..6b3a698 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -375,6 +375,13 @@
final int sequenceNumber = suggestionsInfo.getSequence();
for (int k = 0; k < mLength; ++k) {
if (sequenceNumber == mIds[k]) {
+ final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[k];
+ final int spellCheckSpanStart = editable.getSpanStart(spellCheckSpan);
+ if (spellCheckSpanStart < 0) {
+ // Skips the suggestion if the matched span has been removed.
+ return null;
+ }
+
final int attributes = suggestionsInfo.getSuggestionsAttributes();
final boolean isInDictionary =
((attributes & SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY) > 0);
@@ -383,7 +390,11 @@
final boolean looksLikeGrammarError =
((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR) > 0);
- final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[k];
+ // Validates the suggestions range in case the SpellCheckSpan is out-of-date but not
+ // removed as expected.
+ if (spellCheckSpanStart + offset + length > editable.length()) {
+ return spellCheckSpan;
+ }
//TODO: we need to change that rule for results from a sentence-level spell
// checker that will probably be in dictionary.
if (!isInDictionary && (looksLikeTypo || looksLikeGrammarError)) {
@@ -393,7 +404,6 @@
// Valid word -- isInDictionary || !looksLikeTypo
// Allow the spell checker to remove existing misspelled span by
// overwriting the span over the same place
- final int spellCheckSpanStart = editable.getSpanStart(spellCheckSpan);
final int spellCheckSpanEnd = editable.getSpanEnd(spellCheckSpan);
final int start;
final int end;
@@ -461,7 +471,6 @@
@Override
public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results) {
final Editable editable = (Editable) mTextView.getText();
- final int sentenceLength = editable.length();
for (int i = 0; i < results.length; ++i) {
final SentenceSuggestionsInfo ssi = results[i];
if (ssi == null) {
@@ -475,9 +484,6 @@
}
final int offset = ssi.getOffsetAt(j);
final int length = ssi.getLengthAt(j);
- if (offset < 0 || offset + length > sentenceLength) {
- continue;
- }
final SpellCheckSpan scs = onGetSuggestionsInternal(
suggestionsInfo, offset, length);
if (spellCheckSpan == null && scs != null) {
@@ -821,7 +827,7 @@
// The offset should be rounded up to word boundary.
int uncheckedLength = sentenceEnd - textChangeStart;
if (uncheckedLength > MAX_SENTENCE_LENGTH) {
- sentenceEnd = findSeparator(sequence, sentenceStart + MAX_SENTENCE_LENGTH,
+ sentenceEnd = findSeparator(sequence, textChangeStart + MAX_SENTENCE_LENGTH,
sentenceEnd);
sentenceStart = roundUpToWordStart(sequence, textChangeStart, sentenceStart);
} else {
@@ -829,7 +835,7 @@
sentenceStart);
}
}
- return new Range(sentenceStart, sentenceEnd);
+ return new Range<>(sentenceStart, Math.max(sentenceStart, sentenceEnd));
}
private int roundUpToWordStart(CharSequence sequence, int position, int frontBoundary) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index e0238b9..3c4fd5e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -740,7 +740,6 @@
private MovementMethod mMovement;
private TransformationMethod mTransformation;
- private TextViewTranslationCallback mDefaultTranslationCallback;
@UnsupportedAppUsage
private boolean mAllowTransformationLengthChange;
@UnsupportedAppUsage
@@ -2376,11 +2375,16 @@
@ViewDebug.CapturedViewProperty
@InspectableProperty
public CharSequence getText() {
- if (mUseTextPaddingForUiTranslation
- && mDefaultTranslationCallback != null
- && mDefaultTranslationCallback.isTextPaddingEnabled()
- && mDefaultTranslationCallback.isShowingTranslation()) {
- return mDefaultTranslationCallback.getPaddedText(mText, mTransformed);
+ if (mUseTextPaddingForUiTranslation) {
+ ViewTranslationCallback callback = getViewTranslationCallback();
+ if (callback != null && callback instanceof TextViewTranslationCallback) {
+ TextViewTranslationCallback defaultCallback =
+ (TextViewTranslationCallback) callback;
+ if (defaultCallback.isTextPaddingEnabled()
+ && defaultCallback.isShowingTranslation()) {
+ return defaultCallback.getPaddedText(mText, mTransformed);
+ }
+ }
}
return mText;
}
@@ -10746,12 +10750,15 @@
Editable text = (Editable) mText;
T[] spans = text.getSpans(start, end, type);
- final int length = spans.length;
- for (int i = 0; i < length; i++) {
- final int spanStart = text.getSpanStart(spans[i]);
- final int spanEnd = text.getSpanEnd(spans[i]);
- if (spanEnd == start || spanStart == end) break;
- text.removeSpan(spans[i]);
+ ArrayList<T> spansToRemove = new ArrayList<>();
+ for (T span : spans) {
+ final int spanStart = text.getSpanStart(span);
+ final int spanEnd = text.getSpanEnd(span);
+ if (spanEnd == start || spanStart == end) continue;
+ spansToRemove.add(span);
+ }
+ for (T span : spansToRemove) {
+ text.removeSpan(span);
}
}
@@ -13933,30 +13940,6 @@
}
/**
- * Returns a {@link ViewTranslationCallback} that is used to display the translated information.
- * The default implementation will use a {@link TransformationMethod} that allow to replace the
- * current {@link TransformationMethod} to transform the original text to the translated text
- * display.
- *
- * @return a {@link ViewTranslationCallback} that is used to control how to display the
- * translated information or {@code null} if this View doesn't support translation.
- *
- * @hide
- */
- @Nullable
- @Override
- public ViewTranslationCallback getViewTranslationCallback() {
- return getDefaultViewTranslationCallback();
- }
-
- private ViewTranslationCallback getDefaultViewTranslationCallback() {
- if (mDefaultTranslationCallback == null) {
- mDefaultTranslationCallback = new TextViewTranslationCallback();
- }
- return mDefaultTranslationCallback;
- }
-
- /**
*
* Called when the content from {@link #onCreateViewTranslationRequest} had been translated by
* the TranslationService. The default implementation will replace the current
@@ -13969,17 +13952,19 @@
public void onViewTranslationResponse(@NonNull ViewTranslationResponse response) {
// set ViewTranslationResponse
super.onViewTranslationResponse(response);
- // TODO(b/183467275): Use the overridden ViewTranslationCallback instead of our default
- // implementation if the view has overridden getViewTranslationCallback.
- TextViewTranslationCallback callback =
- (TextViewTranslationCallback) getDefaultViewTranslationCallback();
- TranslationTransformationMethod oldTranslationMethod =
- callback.getTranslationTransformation();
- TransformationMethod originalTranslationMethod = oldTranslationMethod != null
- ? oldTranslationMethod.getOriginalTransformationMethod() : mTransformation;
- TranslationTransformationMethod newTranslationMethod =
- new TranslationTransformationMethod(response, originalTranslationMethod);
- // TODO(b/178353965): well-handle setTransformationMethod.
- callback.setTranslationTransformation(newTranslationMethod);
+ // TODO(b/178353965): move to ViewTranslationCallback.onShow()
+ ViewTranslationCallback callback = getViewTranslationCallback();
+ if (callback instanceof TextViewTranslationCallback) {
+ TextViewTranslationCallback textViewDefaultCallback =
+ (TextViewTranslationCallback) callback;
+ TranslationTransformationMethod oldTranslationMethod =
+ textViewDefaultCallback.getTranslationTransformation();
+ TransformationMethod originalTranslationMethod = oldTranslationMethod != null
+ ? oldTranslationMethod.getOriginalTransformationMethod() : mTransformation;
+ TranslationTransformationMethod newTranslationMethod =
+ new TranslationTransformationMethod(response, originalTranslationMethod);
+ // TODO(b/178353965): well-handle setTransformationMethod.
+ textViewDefaultCallback.setTranslationTransformation(newTranslationMethod);
+ }
}
}
diff --git a/core/java/android/widget/TextViewOnReceiveContentListener.java b/core/java/android/widget/TextViewOnReceiveContentListener.java
index 6a966e0..66e25b0 100644
--- a/core/java/android/widget/TextViewOnReceiveContentListener.java
+++ b/core/java/android/widget/TextViewOnReceiveContentListener.java
@@ -183,15 +183,9 @@
*/
private static boolean isUsageOfImeCommitContentEnabled(@NonNull View view) {
if (view.getReceiveContentMimeTypes() != null) {
- if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
- Log.v(LOG_TAG, "Fallback to commitContent disabled (custom callback is set)");
- }
return false;
}
if (Compatibility.isChangeEnabled(AUTOFILL_NON_TEXT_REQUIRES_ON_RECEIVE_CONTENT_LISTENER)) {
- if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
- Log.v(LOG_TAG, "Fallback to commitContent disabled (target SDK is above S)");
- }
return false;
}
return true;
@@ -222,10 +216,6 @@
*/
void setInputConnectionInfo(@NonNull TextView view, @NonNull InputConnection ic,
@NonNull EditorInfo editorInfo) {
- if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
- Log.v(LOG_TAG, "setInputConnectionInfo: "
- + Arrays.toString(editorInfo.contentMimeTypes));
- }
if (!isUsageOfImeCommitContentEnabled(view)) {
mInputConnectionInfo = null;
return;
@@ -243,9 +233,6 @@
* callback instance.
*/
void clearInputConnectionInfo() {
- if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
- Log.v(LOG_TAG, "clearInputConnectionInfo: " + mInputConnectionInfo);
- }
mInputConnectionInfo = null;
}
@@ -265,17 +252,9 @@
}
final InputConnectionInfo icInfo = mInputConnectionInfo;
if (icInfo == null) {
- if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
- Log.v(LOG_TAG, "getEditorInfoMimeTypes: No usable EditorInfo");
- }
return null;
}
- final String[] editorInfoContentMimeTypes = icInfo.mEditorInfoContentMimeTypes;
- if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
- Log.v(LOG_TAG, "getEditorInfoMimeTypes: "
- + Arrays.toString(editorInfoContentMimeTypes));
- }
- return editorInfoContentMimeTypes;
+ return icInfo.mEditorInfoContentMimeTypes;
}
/**
diff --git a/core/java/android/widget/WidgetFlags.java b/core/java/android/widget/WidgetFlags.java
index 1a49365..0971268 100644
--- a/core/java/android/widget/WidgetFlags.java
+++ b/core/java/android/widget/WidgetFlags.java
@@ -199,6 +199,17 @@
*/
public static final float MAGNIFIER_ASPECT_RATIO_DEFAULT = 5.5f;
+ /** The flag of the fps of the analog clock seconds hand. */
+ public static final String ANALOG_CLOCK_SECONDS_HAND_FPS =
+ "AnalogClockFeature__analog_clock_seconds_hand_fps";
+
+ /** The key name used in app core settings for {@link #ANALOG_CLOCK_SECONDS_HAND_FPS}. */
+ public static final String KEY_ANALOG_CLOCK_SECONDS_HAND_FPS =
+ "widget__analog_clock_seconds_hand_fps";
+
+ /** Default value for the flag {@link #ANALOG_CLOCK_SECONDS_HAND_FPS}. */
+ public static final int ANALOG_CLOCK_SECONDS_HAND_FPS_DEFAULT = 1;
+
private WidgetFlags() {
}
}
diff --git a/core/java/android/window/SplashScreen.java b/core/java/android/window/SplashScreen.java
index 7d222db..42a58fb 100644
--- a/core/java/android/window/SplashScreen.java
+++ b/core/java/android/window/SplashScreen.java
@@ -220,7 +220,13 @@
}
}
- public void dispatchOnExitAnimation(IBinder token, SplashScreenView view) {
+ public void handOverSplashScreenView(@NonNull IBinder token,
+ @NonNull SplashScreenView splashScreenView) {
+ transferSurface(splashScreenView);
+ dispatchOnExitAnimation(token, splashScreenView);
+ }
+
+ private void dispatchOnExitAnimation(IBinder token, SplashScreenView view) {
synchronized (mGlobalLock) {
final SplashScreenImpl impl = findImpl(token);
if (impl == null) {
@@ -240,5 +246,9 @@
return impl != null && impl.mExitAnimationListener != null;
}
}
+
+ private void transferSurface(@NonNull SplashScreenView splashScreenView) {
+ splashScreenView.transferSurface();
+ }
}
}
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index 6d71639..000dfb2 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -30,6 +30,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@@ -38,13 +39,17 @@
import android.os.Trace;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.Gravity;
import android.view.LayoutInflater;
+import android.view.SurfaceControlViewHost;
+import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowInsetsController;
import android.view.WindowManager;
import android.widget.FrameLayout;
+import android.widget.ImageView;
import com.android.internal.R;
import com.android.internal.policy.DecorView;
@@ -92,6 +97,14 @@
// The host activity when transfer view to it.
private Activity mHostActivity;
+
+ @Nullable
+ private SurfaceControlViewHost.SurfacePackage mSurfacePackageCopy;
+ @Nullable
+ private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
+ @Nullable
+ private SurfaceView mSurfaceView;
+
// cache original window and status
private Window mWindow;
private int mAppWindowFlags;
@@ -114,6 +127,7 @@
private @ColorInt int mIconBackground;
private Bitmap mParceledIconBitmap;
private Drawable mIconDrawable;
+ private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
private int mBrandingImageWidth;
private int mBrandingImageHeight;
private Drawable mBrandingDrawable;
@@ -133,7 +147,10 @@
mIconSize = parcelable.getIconSize();
mBackgroundColor = parcelable.getBackgroundColor();
mIconBackground = parcelable.getIconBackground();
- if (parcelable.mIconBitmap != null) {
+ mSurfacePackage = parcelable.mSurfacePackage;
+ if (mSurfacePackage == null && parcelable.mIconBitmap != null) {
+ // We only create a Bitmap copies of immobile icons since animated icon are using
+ // a surface view
mIconDrawable = new BitmapDrawable(mContext.getResources(), parcelable.mIconBitmap);
mParceledIconBitmap = parcelable.mIconBitmap;
}
@@ -145,6 +162,9 @@
}
mIconAnimationStart = Instant.ofEpochMilli(parcelable.mIconAnimationStartMillis);
mIconAnimationDuration = Duration.ofMillis(parcelable.mIconAnimationDurationMillis);
+ if (DEBUG) {
+ Log.d(TAG, String.format("Building from parcel drawable: %s", mIconDrawable));
+ }
return this;
}
@@ -167,7 +187,7 @@
/**
* Set the Drawable object to fill the center view.
*/
- public Builder setCenterViewDrawable(Drawable drawable) {
+ public Builder setCenterViewDrawable(@Nullable Drawable drawable) {
mIconDrawable = drawable;
return this;
}
@@ -191,7 +211,7 @@
/**
* Set the Drawable object and size for the branding view.
*/
- public Builder setBrandingDrawable(Drawable branding, int width, int height) {
+ public Builder setBrandingDrawable(@Nullable Drawable branding, int width, int height) {
mBrandingDrawable = branding;
mBrandingImageWidth = width;
mBrandingImageHeight = height;
@@ -209,22 +229,30 @@
view.mInitBackgroundColor = mBackgroundColor;
view.mInitIconBackgroundColor = mIconBackground;
view.setBackgroundColor(mBackgroundColor);
- view.mIconView = view.findViewById(R.id.splashscreen_icon_view);
+
view.mBrandingImageView = view.findViewById(R.id.splashscreen_branding_view);
+
// center icon
- if (mIconSize != 0) {
- final ViewGroup.LayoutParams params = view.mIconView.getLayoutParams();
- params.width = mIconSize;
- params.height = mIconSize;
- view.mIconView.setLayoutParams(params);
- }
- if (mIconDrawable != null) {
- view.mIconView.setBackground(mIconDrawable);
+ if (mIconDrawable instanceof SplashScreenView.IconAnimateListener
+ || mSurfacePackage != null) {
+ view.mIconView = createSurfaceView(view);
view.initIconAnimation(mIconDrawable,
mIconAnimationDuration != null ? mIconAnimationDuration.toMillis() : 0);
+ view.mIconAnimationStart = mIconAnimationStart;
+ view.mIconAnimationDuration = mIconAnimationDuration;
+ } else {
+ view.mIconView = view.findViewById(R.id.splashscreen_icon_view);
+ if (mIconSize != 0) {
+ final ViewGroup.LayoutParams params = view.mIconView.getLayoutParams();
+ params.width = mIconSize;
+ params.height = mIconSize;
+ view.mIconView.setLayoutParams(params);
+ if (mIconDrawable != null) {
+ view.mIconView.setBackground(mIconDrawable);
+ }
+ }
}
- view.mIconAnimationStart = mIconAnimationStart;
- view.mIconAnimationDuration = mIconAnimationDuration;
+
if (mParceledIconBitmap != null) {
view.mParceledIconBitmap = mParceledIconBitmap;
}
@@ -242,14 +270,60 @@
view.mParceledBrandingBitmap = mParceledBrandingBitmap;
}
if (DEBUG) {
- Log.d(TAG, " build " + view + " Icon: view: " + view.mIconView + " drawable: "
- + mIconDrawable + " size: " + mIconSize + "\n Branding: view: "
- + view.mBrandingImageView + " drawable: " + mBrandingDrawable
- + " size w: " + mBrandingImageWidth + " h: " + mBrandingImageHeight);
+ Log.d(TAG, "Build " + view
+ + "\nIcon: view: " + view.mIconView + " drawable: "
+ + mIconDrawable + " size: " + mIconSize
+ + "\nBranding: view: " + view.mBrandingImageView + " drawable: "
+ + mBrandingDrawable + " size w: " + mBrandingImageWidth + " h: "
+ + mBrandingImageHeight);
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return view;
}
+
+ private SurfaceView createSurfaceView(@NonNull SplashScreenView view) {
+ final SurfaceView surfaceView = new SurfaceView(view.getContext());
+ if (mSurfacePackage == null) {
+ if (DEBUG) {
+ Log.d(TAG,
+ "Creating Original SurfacePackage. SurfaceView: " + surfaceView);
+ }
+
+ SurfaceControlViewHost viewHost = new SurfaceControlViewHost(mContext,
+ mContext.getDisplay(),
+ surfaceView.getHostToken());
+ ImageView imageView = new ImageView(mContext);
+ imageView.setBackground(mIconDrawable);
+ viewHost.setView(imageView, mIconSize, mIconSize);
+ SurfaceControlViewHost.SurfacePackage surfacePackage = viewHost.getSurfacePackage();
+ surfaceView.setChildSurfacePackage(surfacePackage);
+ view.mSurfacePackage = surfacePackage;
+ view.mSurfacePackageCopy = new SurfaceControlViewHost.SurfacePackage(
+ surfacePackage);
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "Using copy of SurfacePackage in the client");
+ }
+ view.mSurfacePackage = mSurfacePackage;
+ }
+ if (mIconSize != 0) {
+ LayoutParams lp = new FrameLayout.LayoutParams(mIconSize, mIconSize);
+ lp.gravity = Gravity.CENTER;
+ surfaceView.setLayoutParams(lp);
+ if (DEBUG) {
+ Log.d(TAG, "Icon size " + mIconSize);
+ }
+ }
+
+ // We ensure that we can blend the alpha of the surface view with the SplashScreenView
+ surfaceView.setUseAlpha();
+ surfaceView.setZOrderOnTop(true);
+ surfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
+
+ view.addView(surfaceView);
+ view.mSurfaceView = surfaceView;
+ return surfaceView;
+ }
}
/** @hide */
@@ -298,6 +372,35 @@
}
/**
+ * Called when this {@link SplashScreenView} has been copied to be transferred to the client.
+ *
+ * @hide
+ */
+ public void onCopied() {
+ if (mSurfaceView == null) {
+ return;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Setting SurfaceView's SurfacePackage to null.");
+ }
+ // If we don't release the surface package, the surface will be reparented to this
+ // surface view. So once it's copied into the client process, we release it.
+ mSurfacePackage.release();
+ mSurfacePackage = null;
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ super.setAlpha(alpha);
+
+ // The surface view's alpha is not multiplied with the containing view's alpha, so we
+ // manually do it here
+ if (mSurfaceView != null) {
+ mSurfaceView.setAlpha(mSurfaceView.getAlpha() * alpha);
+ }
+ }
+
+ /**
* Returns the duration of the icon animation if icon is animatable.
*
* @see android.R.attr#windowSplashScreenAnimatedIcon
@@ -316,6 +419,22 @@
return mIconAnimationStart;
}
+
+ void transferSurface() {
+ if (mSurfacePackage == null) {
+ return;
+ }
+ if (DEBUG) {
+ mSurfacePackage.getSurfaceControl().addOnReparentListener(
+ (transaction, parent) -> Log.e(TAG,
+ String.format("SurfacePackage'surface reparented.\n Parent: %s",
+ parent), new Throwable()));
+ Log.d(TAG, "Transferring surface " + mSurfaceView.toString());
+ }
+ mSurfaceView.setChildSurfacePackage(mSurfacePackage);
+
+ }
+
void initIconAnimation(Drawable iconDrawable, long duration) {
if (!(iconDrawable instanceof IconAnimateListener)) {
return;
@@ -477,7 +596,7 @@
private int mBackgroundColor;
private int mIconBackground;
- private Bitmap mIconBitmap;
+ private Bitmap mIconBitmap = null;
private int mBrandingWidth;
private int mBrandingHeight;
private Bitmap mBrandingBitmap;
@@ -485,14 +604,20 @@
private long mIconAnimationStartMillis;
private long mIconAnimationDurationMillis;
+ private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
+
public SplashScreenViewParcelable(SplashScreenView view) {
- ViewGroup.LayoutParams params = view.getIconView().getLayoutParams();
- mIconSize = params.height;
+ mIconSize = view.mIconView.getWidth();
mBackgroundColor = view.getInitBackgroundColor();
mIconBackground = view.getIconBackgroundColor();
- mIconBitmap = copyDrawable(view.getIconView().getBackground());
+ mSurfacePackage = view.mSurfacePackageCopy;
+ if (mSurfacePackage == null) {
+ // We only need to copy the drawable if we are not using a SurfaceView
+ mIconBitmap = copyDrawable(view.getIconView().getBackground());
+ }
mBrandingBitmap = copyDrawable(view.getBrandingView().getBackground());
- params = view.getBrandingView().getLayoutParams();
+
+ ViewGroup.LayoutParams params = view.getBrandingView().getLayoutParams();
mBrandingWidth = params.width;
mBrandingHeight = params.height;
@@ -535,6 +660,7 @@
mIconAnimationStartMillis = source.readLong();
mIconAnimationDurationMillis = source.readLong();
mIconBackground = source.readInt();
+ mSurfacePackage = source.readTypedObject(SurfaceControlViewHost.SurfacePackage.CREATOR);
}
@Override
@@ -553,6 +679,7 @@
dest.writeLong(mIconAnimationStartMillis);
dest.writeLong(mIconAnimationDurationMillis);
dest.writeInt(mIconBackground);
+ dest.writeTypedObject(mSurfacePackage, flags);
}
public static final @NonNull Parcelable.Creator<SplashScreenViewParcelable> CREATOR =
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 862c900..28c2774 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1093,6 +1093,7 @@
"",
-1);
+ setResult(RESULT_OK);
finish();
}
}
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 3cf4621..c112d09 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -23,6 +23,7 @@
import android.content.AttributionSource;
import android.content.pm.ParceledListSlice;
import android.os.Bundle;
+import android.os.PackageTagsList;
import android.os.RemoteCallback;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsActiveCallback;
@@ -92,7 +93,7 @@
void setAudioRestriction(int code, int usage, int uid, int mode, in String[] exceptionPackages);
void setUserRestrictions(in Bundle restrictions, IBinder token, int userHandle);
- void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, in Map<String, String[]> excludedPackageTags);
+ void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, in PackageTagsList excludedPackageTags);
void removeUser(int userHandle);
void startWatchingActive(in int[] ops, IAppOpsActiveCallback callback);
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
index d418770e..707286e 100644
--- a/core/java/com/android/internal/app/LocaleHelper.java
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -18,6 +18,7 @@
import android.annotation.IntRange;
import android.compat.annotation.UnsupportedAppUsage;
+import android.icu.text.CaseMap;
import android.icu.text.ListFormatter;
import android.icu.util.ULocale;
import android.os.LocaleList;
@@ -35,43 +36,13 @@
/**
* Sentence-case (first character uppercased).
*
- * <p>There is no good API available for this, not even in ICU.
- * We can revisit this if we get some ICU support later.</p>
- *
- * <p>There are currently several tickets requesting this feature:</p>
- * <ul>
- * <li>ICU needs to provide an easy way to titlecase only one first letter
- * http://bugs.icu-project.org/trac/ticket/11729</li>
- * <li>Add "initial case"
- * http://bugs.icu-project.org/trac/ticket/8394</li>
- * <li>Add code for initialCase, toTitlecase don't modify after Lt,
- * avoid 49Ers, low-level language-specific casing
- * http://bugs.icu-project.org/trac/ticket/10410</li>
- * <li>BreakIterator.getFirstInstance: Often you need to titlecase just the first
- * word, and leave the rest of the string alone. (closed as duplicate)
- * http://bugs.icu-project.org/trac/ticket/8946</li>
- * </ul>
- *
- * <p>A (clunky) option with the current ICU API is:</p>
- * {{
- * BreakIterator breakIterator = BreakIterator.getSentenceInstance(locale);
- * String result = UCharacter.toTitleCase(locale,
- * source, breakIterator, UCharacter.TITLECASE_NO_LOWERCASE);
- * }}
- *
- * <p>That also means creating a BreakIterator for each locale. Expensive...</p>
- *
* @param str the string to sentence-case.
* @param locale the locale used for the case conversion.
* @return the string converted to sentence-case.
*/
public static String toSentenceCase(String str, Locale locale) {
- if (str.isEmpty()) {
- return str;
- }
- final int firstCodePointLen = str.offsetByCodePoints(0, 1);
- return str.substring(0, firstCodePointLen).toUpperCase(locale)
- + str.substring(firstCodePointLen);
+ // Titlecases only the character at index 0, don't touch anything else
+ return CaseMap.toTitle().wholeString().noLowercase().apply(locale, null, str);
}
/**
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index b7170d8..6e1d3ce 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -30,7 +30,10 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.ProxyUtils;
+import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
@@ -74,6 +77,9 @@
private static final String ENCODED_NULL_PROXY_INFO = "\0\0\0\0";
+ /** Default URL encoding. */
+ private static final String DEFAULT_ENCODING = StandardCharsets.UTF_8.name();
+
// Entity fields.
@UnsupportedAppUsage
public final String key; // -1
@@ -129,9 +135,6 @@
/**
* The list of allowable algorithms.
- *
- * <p>This list is validated in the setter to ensure that encoding characters (list, value
- * delimiters) are not present in the algorithm names. See {@link #validateAllowedAlgorithms()}
*/
private List<String> mAllowedAlgorithms = new ArrayList<>(); // 19
public boolean isBypassable = false; // 20
@@ -196,11 +199,8 @@
*
* @param allowedAlgorithms the list of allowable algorithms, as listed in {@link
* IpSecAlgorithm}.
- * @throws IllegalArgumentException if any delimiters are used in algorithm names. See {@link
- * #VALUE_DELIMITER} and {@link LIST_DELIMITER}.
*/
public void setAllowedAlgorithms(List<String> allowedAlgorithms) {
- validateAllowedAlgorithms(allowedAlgorithms);
mAllowedAlgorithms = allowedAlgorithms;
}
@@ -297,7 +297,11 @@
// Either all must be present, or none must be.
if (values.length >= 24) {
- profile.mAllowedAlgorithms = Arrays.asList(values[19].split(LIST_DELIMITER));
+ profile.mAllowedAlgorithms = new ArrayList<>();
+ for (String algo : Arrays.asList(values[19].split(LIST_DELIMITER))) {
+ profile.mAllowedAlgorithms.add(URLDecoder.decode(algo, DEFAULT_ENCODING));
+ }
+
profile.isBypassable = Boolean.parseBoolean(values[20]);
profile.isMetered = Boolean.parseBoolean(values[21]);
profile.maxMtu = Integer.parseInt(values[22]);
@@ -348,7 +352,19 @@
builder.append(ENCODED_NULL_PROXY_INFO);
}
- builder.append(VALUE_DELIMITER).append(String.join(LIST_DELIMITER, mAllowedAlgorithms));
+ final List<String> encodedAlgoNames = new ArrayList<>();
+
+ try {
+ for (String algo : mAllowedAlgorithms) {
+ encodedAlgoNames.add(URLEncoder.encode(algo, DEFAULT_ENCODING));
+ }
+ } catch (UnsupportedEncodingException e) {
+ // Unexpected error
+ throw new IllegalStateException("Failed to encode algorithms.", e);
+ }
+
+ builder.append(VALUE_DELIMITER).append(String.join(LIST_DELIMITER, encodedAlgoNames));
+
builder.append(VALUE_DELIMITER).append(isBypassable);
builder.append(VALUE_DELIMITER).append(isMetered);
builder.append(VALUE_DELIMITER).append(maxMtu);
@@ -425,20 +441,6 @@
return true;
}
- /**
- * Validates that the provided list of algorithms does not contain illegal characters.
- *
- * @param allowedAlgorithms The list to be validated
- */
- public static void validateAllowedAlgorithms(List<String> allowedAlgorithms) {
- for (final String alg : allowedAlgorithms) {
- if (alg.contains(VALUE_DELIMITER) || alg.contains(LIST_DELIMITER)) {
- throw new IllegalArgumentException(
- "Algorithm contained illegal ('\0' or ',') character");
- }
- }
- }
-
/** Generates a hashcode over the VpnProfile. */
@Override
public int hashCode() {
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index d4d6125..3aaccdd 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -180,29 +180,28 @@
}
private long getProcessForegroundTimeMs(BatteryStats.Uid uid, long realtimeUs) {
- final long topStateDurationMs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_TOP,
- realtimeUs, BatteryStats.STATS_SINCE_CHARGED) / 1000;
-
- long foregroundActivityDurationMs = 0;
+ final long topStateDurationUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_TOP,
+ realtimeUs, BatteryStats.STATS_SINCE_CHARGED);
+ long foregroundActivityDurationUs = 0;
final BatteryStats.Timer foregroundActivityTimer = uid.getForegroundActivityTimer();
if (foregroundActivityTimer != null) {
- foregroundActivityDurationMs = foregroundActivityTimer.getTotalTimeLocked(realtimeUs,
- BatteryStats.STATS_SINCE_CHARGED) / 1000;
+ foregroundActivityDurationUs = foregroundActivityTimer.getTotalTimeLocked(realtimeUs,
+ BatteryStats.STATS_SINCE_CHARGED);
}
// Use the min value of STATE_TOP time and foreground activity time, since both of these
// times are imprecise
- final long foregroundDurationMs = Math.min(topStateDurationMs,
- foregroundActivityDurationMs);
+ long totalForegroundDurationUs = Math.min(topStateDurationUs, foregroundActivityDurationUs);
- long foregroundServiceDurationMs = 0;
- final BatteryStats.Timer foregroundServiceTimer = uid.getForegroundServiceTimer();
- if (foregroundServiceTimer != null) {
- foregroundServiceDurationMs = foregroundServiceTimer.getTotalTimeLocked(realtimeUs,
- BatteryStats.STATS_SINCE_CHARGED) / 1000;
- }
+ totalForegroundDurationUs += uid.getProcessStateTime(
+ BatteryStats.Uid.PROCESS_STATE_FOREGROUND, realtimeUs,
+ BatteryStats.STATS_SINCE_CHARGED);
- return foregroundDurationMs + foregroundServiceDurationMs;
+ totalForegroundDurationUs += uid.getProcessStateTime(
+ BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE, realtimeUs,
+ BatteryStats.STATS_SINCE_CHARGED);
+
+ return totalForegroundDurationUs / 1000;
}
private long getProcessBackgroundTimeMs(BatteryStats.Uid uid, long realtimeUs) {
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index 57e1bf7..6f911cb 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -66,6 +66,7 @@
public static final boolean DEFAULT_IGNORE_BATTERY_STATUS = false;
public static final boolean DEFAULT_COLLECT_LATENCY_DATA = true;
public static final int MAX_BINDER_CALL_STATS_COUNT_DEFAULT = 1500;
+ public static final int SHARDING_MODULO_DEFAULT = 1;
private static final String DEBUG_ENTRY_PREFIX = "__DEBUG_";
private static class OverflowBinder extends Binder {}
@@ -107,6 +108,12 @@
private boolean mIgnoreBatteryStatus = DEFAULT_IGNORE_BATTERY_STATUS;
private boolean mCollectLatencyData = DEFAULT_COLLECT_LATENCY_DATA;
+ // Controls how many APIs will be collected per device. 1 means all APIs, 10 means every 10th
+ // API will be collected.
+ private int mShardingModulo = SHARDING_MODULO_DEFAULT;
+ // Controls which shards will be collected on this device.
+ private int mShardingOffset;
+
private CachedDeviceState.Readonly mDeviceState;
private CachedDeviceState.TimeInStateStopwatch mBatteryStopwatch;
@@ -178,6 +185,7 @@
this.mRandom = injector.getRandomGenerator();
this.mCallStatsObserverHandler = injector.getHandler();
this.mLatencyObserver = injector.getLatencyObserver(processSource);
+ this.mShardingOffset = mRandom.nextInt(mShardingModulo);
}
public void setDeviceState(@NonNull CachedDeviceState.Readonly deviceState) {
@@ -343,6 +351,19 @@
}
}
+ private boolean shouldExport(ExportedCallStat e, boolean applySharding) {
+ if (!applySharding) {
+ return true;
+ }
+
+ int hash = e.binderClass.hashCode();
+ hash = 31 * hash + e.transactionCode;
+ hash = 31 * hash + e.callingUid;
+ hash = 31 * hash + (e.screenInteractive ? 1231 : 1237);
+
+ return (hash + mShardingOffset) % mShardingModulo == 0;
+ }
+
private UidEntry getUidEntry(int uid) {
UidEntry uidEntry = mUidEntries.get(uid);
if (uidEntry == null) {
@@ -424,6 +445,15 @@
* This method is expensive to call.
*/
public ArrayList<ExportedCallStat> getExportedCallStats() {
+ return getExportedCallStats(false);
+ }
+
+ /**
+ * This method is expensive to call.
+ * Exports call stats and applies sharding if requested.
+ */
+ @VisibleForTesting
+ public ArrayList<ExportedCallStat> getExportedCallStats(boolean applySharding) {
// We do not collect all the data if detailed tracking is off.
if (!mDetailedTracking) {
return new ArrayList<>();
@@ -435,7 +465,10 @@
for (int entryIdx = 0; entryIdx < uidEntriesSize; entryIdx++) {
final UidEntry entry = mUidEntries.valueAt(entryIdx);
for (CallStat stat : entry.getCallStatsList()) {
- resultCallStats.add(getExportedCallStat(entry.workSourceUid, stat));
+ ExportedCallStat e = getExportedCallStat(entry.workSourceUid, stat);
+ if (shouldExport(e, applySharding)) {
+ resultCallStats.add(e);
+ }
}
}
}
@@ -450,6 +483,7 @@
resultCallStats.add(
createDebugEntry("battery_time_millis", mBatteryStopwatch.getMillis()));
resultCallStats.add(createDebugEntry("sampling_interval", mPeriodicSamplingInterval));
+ resultCallStats.add(createDebugEntry("sharding_modulo", mShardingModulo));
}
return resultCallStats;
@@ -459,11 +493,24 @@
* This method is expensive to call.
*/
public ArrayList<ExportedCallStat> getExportedCallStats(int workSourceUid) {
+ return getExportedCallStats(workSourceUid, false);
+ }
+
+ /**
+ * This method is expensive to call.
+ * Exports call stats and applies sharding if requested.
+ */
+ @VisibleForTesting
+ public ArrayList<ExportedCallStat> getExportedCallStats(
+ int workSourceUid, boolean applySharding) {
ArrayList<ExportedCallStat> resultCallStats = new ArrayList<>();
synchronized (mLock) {
final UidEntry entry = getUidEntry(workSourceUid);
for (CallStat stat : entry.getCallStatsList()) {
- resultCallStats.add(getExportedCallStat(workSourceUid, stat));
+ ExportedCallStat e = getExportedCallStat(workSourceUid, stat);
+ if (shouldExport(e, applySharding)) {
+ resultCallStats.add(e);
+ }
}
}
@@ -555,6 +602,7 @@
pw.print("On battery time (ms): ");
pw.println(mBatteryStopwatch != null ? mBatteryStopwatch.getMillis() : 0);
pw.println("Sampling interval period: " + mPeriodicSamplingInterval);
+ pw.println("Sharding modulo: " + mShardingModulo);
final String datasetSizeDesc = verbose ? "" : "(top 90% by cpu time) ";
final StringBuilder sb = new StringBuilder();
@@ -566,9 +614,9 @@
+ "call_count):");
final List<ExportedCallStat> exportedCallStats;
if (workSourceUid != Process.INVALID_UID) {
- exportedCallStats = getExportedCallStats(workSourceUid);
+ exportedCallStats = getExportedCallStats(workSourceUid, true);
} else {
- exportedCallStats = getExportedCallStats();
+ exportedCallStats = getExportedCallStats(true);
}
exportedCallStats.sort(BinderCallsStats::compareByCpuDesc);
for (ExportedCallStat e : exportedCallStats) {
@@ -784,6 +832,23 @@
}
}
+ /** Updates the sharding modulo. */
+ public void setShardingModulo(int shardingModulo) {
+ if (shardingModulo <= 0) {
+ Slog.w(TAG, "Ignored invalid sharding modulo (value must be positive): "
+ + shardingModulo);
+ return;
+ }
+
+ synchronized (mLock) {
+ if (shardingModulo != mShardingModulo) {
+ mShardingModulo = shardingModulo;
+ mShardingOffset = mRandom.nextInt(shardingModulo);
+ reset();
+ }
+ }
+ }
+
/** Whether to collect latency histograms. */
public void setCollectLatencyData(boolean collectLatencyData) {
mCollectLatencyData = collectLatencyData;
@@ -1104,6 +1169,7 @@
public static final String SETTINGS_TRACK_DIRECT_CALLING_UID_KEY = "track_calling_uid";
public static final String SETTINGS_MAX_CALL_STATS_KEY = "max_call_stats_count";
public static final String SETTINGS_IGNORE_BATTERY_STATUS_KEY = "ignore_battery_status";
+ public static final String SETTINGS_SHARDING_MODULO_KEY = "sharding_modulo";
// Settings for BinderLatencyObserver.
public static final String SETTINGS_COLLECT_LATENCY_DATA_KEY = "collect_latency_data";
public static final String SETTINGS_LATENCY_OBSERVER_SAMPLING_INTERVAL_KEY =
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index 0d041c4..e693d9d 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -201,7 +201,10 @@
result.packageWithHighestDrain = packageWithHighestDrain;
}
- private double calculateUidModeledPowerMah(BatteryStats.Uid u, int statsType) {
+ /**
+ * Calculates CPU power consumed by the specified app, using the PowerProfile model.
+ */
+ public double calculateUidModeledPowerMah(BatteryStats.Uid u, int statsType) {
// Constant battery drain when CPU is active
double powerMah = calculateActiveCpuPowerMah(u.getCpuActiveTime());
diff --git a/core/java/com/android/internal/os/SystemServicePowerCalculator.java b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
index a26abc2..b4a2b63 100644
--- a/core/java/com/android/internal/os/SystemServicePowerCalculator.java
+++ b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
@@ -40,8 +40,10 @@
// to this layout:
// {cluster1-speed1, cluster1-speed2, ..., cluster2-speed1, cluster2-speed2, ...}
private final UsageBasedPowerEstimator[] mPowerEstimators;
+ private final CpuPowerCalculator mCpuPowerCalculator;
public SystemServicePowerCalculator(PowerProfile powerProfile) {
+ mCpuPowerCalculator = new CpuPowerCalculator(powerProfile);
int numFreqs = 0;
final int numCpuClusters = powerProfile.getNumCpuClusters();
for (int cluster = 0; cluster < numCpuClusters; cluster++) {
@@ -62,7 +64,22 @@
@Override
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
- double systemServicePowerMah = calculateSystemServicePower(batteryStats);
+ final BatteryStats.Uid systemUid = batteryStats.getUidStats().get(Process.SYSTEM_UID);
+ if (systemUid == null) {
+ return;
+ }
+
+ final long consumptionUC = systemUid.getCpuMeasuredBatteryConsumptionUC();
+ final int powerModel = getPowerModel(consumptionUC, query);
+
+ double systemServicePowerMah;
+ if (powerModel == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) {
+ systemServicePowerMah = calculatePowerUsingMeasuredConsumption(batteryStats,
+ systemUid, consumptionUC);
+ } else {
+ systemServicePowerMah = calculatePowerUsingPowerProfile(batteryStats);
+ }
+
final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
builder.getUidBatteryConsumerBuilders();
final UidBatteryConsumer.Builder systemServerConsumer = uidBatteryConsumerBuilders.get(
@@ -76,7 +93,7 @@
// distributed to applications
systemServerConsumer.setConsumedPower(
BatteryConsumer.POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS,
- -systemServicePowerMah);
+ -systemServicePowerMah, powerModel);
}
for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
@@ -84,7 +101,8 @@
if (app != systemServerConsumer) {
final BatteryStats.Uid uid = app.getBatteryStatsUid();
app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES,
- systemServicePowerMah * uid.getProportionalSystemServiceUsage());
+ systemServicePowerMah * uid.getProportionalSystemServiceUsage(),
+ powerModel);
}
}
@@ -102,7 +120,20 @@
public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
long rawRealtimeUs, long rawUptimeUs, int statsType,
SparseArray<UserHandle> asUsers) {
- double systemServicePowerMah = calculateSystemServicePower(batteryStats);
+ final BatteryStats.Uid systemUid = batteryStats.getUidStats().get(Process.SYSTEM_UID);
+ if (systemUid == null) {
+ return;
+ }
+
+ final long consumptionUC = systemUid.getCpuMeasuredBatteryConsumptionUC();
+ double systemServicePowerMah;
+ if (getPowerModel(consumptionUC) == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) {
+ systemServicePowerMah = calculatePowerUsingMeasuredConsumption(batteryStats,
+ systemUid, consumptionUC);
+ } else {
+ systemServicePowerMah = calculatePowerUsingPowerProfile(batteryStats);
+ }
+
BatterySipper systemServerSipper = null;
for (int i = sippers.size() - 1; i >= 0; i--) {
final BatterySipper app = sippers.get(i);
@@ -134,7 +165,21 @@
}
}
- private double calculateSystemServicePower(BatteryStats batteryStats) {
+ private double calculatePowerUsingMeasuredConsumption(BatteryStats batteryStats,
+ BatteryStats.Uid systemUid, long consumptionUC) {
+ // Use the PowerProfile based model to estimate the ratio between the power consumed
+ // while handling incoming binder calls and the entire System UID power consumption.
+ // Apply that ratio to the _measured_ system UID power consumption to get a more
+ // accurate estimate of the power consumed by incoming binder calls.
+ final double systemServiceModeledPowerMah = calculatePowerUsingPowerProfile(batteryStats);
+ final double systemUidModeledPowerMah = mCpuPowerCalculator.calculateUidModeledPowerMah(
+ systemUid, BatteryStats.STATS_SINCE_CHARGED);
+
+ return uCtoMah(consumptionUC) * systemServiceModeledPowerMah
+ / systemUidModeledPowerMah;
+ }
+
+ private double calculatePowerUsingPowerProfile(BatteryStats batteryStats) {
final long[] systemServiceTimeAtCpuSpeeds = batteryStats.getSystemServiceTimeAtCpuSpeeds();
if (systemServiceTimeAtCpuSpeeds == null) {
return 0;
@@ -145,13 +190,12 @@
double powerMah = 0;
final int size = Math.min(mPowerEstimators.length, systemServiceTimeAtCpuSpeeds.length);
for (int i = 0; i < size; i++) {
- powerMah += mPowerEstimators[i].calculatePower(systemServiceTimeAtCpuSpeeds[i]);
+ powerMah += mPowerEstimators[i].calculatePower(systemServiceTimeAtCpuSpeeds[i] / 1000);
}
if (DEBUG) {
Log.d(TAG, "System service power:" + powerMah);
}
-
return powerMah;
}
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 5ba1928..4d7139c 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -146,7 +146,7 @@
// Used to show the authentication dialog (Biometrics, Device Credential)
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId,
- String opPackageName, long operationId);
+ String opPackageName, long operationId, int multiSensorConfig);
// Used to notify the authentication dialog that a biometric has been authenticated
void onBiometricAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index c8a91d8..6a8d983 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -110,7 +110,7 @@
// Used to show the authentication dialog (Biometrics, Device Credential)
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
- int userId, String opPackageName,long operationId);
+ int userId, String opPackageName, long operationId, int multiSensorConfig);
// Used to notify the authentication dialog that a biometric has been authenticated
void onBiometricAuthenticated();
diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java
index 8508a8d..8b3c133 100644
--- a/core/java/com/android/internal/util/ContrastColorUtil.java
+++ b/core/java/com/android/internal/util/ContrastColorUtil.java
@@ -595,7 +595,9 @@
if (backgroundColor == Notification.COLOR_DEFAULT) {
return !defaultBackgroundIsDark;
}
- return ColorUtilsFromCompat.calculateLuminance(backgroundColor) > 0.5;
+ // Color contrast ratio luminance midpoint, X: 1.05 / (X + 0.05) = (X + 0.05) / 0.05
+ // Solved as X = sqrt(.05 * 1.05) - 0.05 = 0.17912878474
+ return ColorUtilsFromCompat.calculateLuminance(backgroundColor) > 0.17912878474;
}
public static double calculateLuminance(int backgroundColor) {
@@ -619,6 +621,7 @@
}
public static boolean isColorLight(int backgroundColor) {
+ // TODO(b/188947832): Use 0.17912878474 instead of 0.5 to ensure better contrast
return calculateLuminance(backgroundColor) > 0.5f;
}
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index a61e86b..f5c2a2a 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -28,7 +28,6 @@
void setActive(boolean active, boolean fullscreen, boolean reportToImeController);
void scheduleStartInputIfNecessary(boolean fullscreen);
void reportFullscreenMode(boolean fullscreen);
- void updateActivityViewToScreenMatrix(int bindSequence, in float[] matrixValues);
void setImeTraceEnabled(boolean enabled);
void throwExceptionFromSystem(String message);
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index e9efca3..4891ce9 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -88,9 +88,6 @@
// TODO(Bug 113914148): Consider removing this.
oneway void getInputMethodWindowVisibleHeight(IIntResultCallback resultCallback);
- oneway void reportActivityViewAsync(in IInputMethodClient parentClient, int childDisplayId,
- in float[] matrixValues);
-
oneway void reportPerceptibleAsync(in IBinder windowToken, boolean perceptible);
/** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */
oneway void removeImeSurface(in IVoidResultCallback resultCallback);
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java
index c9755a3..df371ce 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/view/InputBindResult.java
@@ -19,12 +19,10 @@
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
-import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.graphics.Matrix;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -201,40 +199,16 @@
*/
public final int sequence;
- @Nullable
- private final float[] mActivityViewToScreenMatrixValues;
-
public final boolean isInputMethodSuppressingSpellChecker;
- /**
- * @return {@link Matrix} that corresponds to {@link #mActivityViewToScreenMatrixValues}.
- * {@code null} if {@link #mActivityViewToScreenMatrixValues} is {@code null}.
- */
- @Nullable
- public Matrix getActivityViewToScreenMatrix() {
- if (mActivityViewToScreenMatrixValues == null) {
- return null;
- }
- final Matrix matrix = new Matrix();
- matrix.setValues(mActivityViewToScreenMatrixValues);
- return matrix;
- }
-
public InputBindResult(@ResultCode int _result,
IInputMethodSession _method, InputChannel _channel, String _id, int _sequence,
- @Nullable Matrix activityViewToScreenMatrix,
boolean isInputMethodSuppressingSpellChecker) {
result = _result;
method = _method;
channel = _channel;
id = _id;
sequence = _sequence;
- if (activityViewToScreenMatrix == null) {
- mActivityViewToScreenMatrixValues = null;
- } else {
- mActivityViewToScreenMatrixValues = new float[9];
- activityViewToScreenMatrix.getValues(mActivityViewToScreenMatrixValues);
- }
this.isInputMethodSuppressingSpellChecker = isInputMethodSuppressingSpellChecker;
}
@@ -248,7 +222,6 @@
}
id = source.readString();
sequence = source.readInt();
- mActivityViewToScreenMatrixValues = source.createFloatArray();
isInputMethodSuppressingSpellChecker = source.readBoolean();
}
@@ -256,7 +229,6 @@
public String toString() {
return "InputBindResult{result=" + getResultString() + " method="+ method + " id=" + id
+ " sequence=" + sequence
- + " activityViewToScreenMatrix=" + getActivityViewToScreenMatrix()
+ " isInputMethodSuppressingSpellChecker=" + isInputMethodSuppressingSpellChecker
+ "}";
}
@@ -279,7 +251,6 @@
}
dest.writeString(id);
dest.writeInt(sequence);
- dest.writeFloatArray(mActivityViewToScreenMatrixValues);
dest.writeBoolean(isInputMethodSuppressingSpellChecker);
}
@@ -347,7 +318,7 @@
}
private static InputBindResult error(@ResultCode int result) {
- return new InputBindResult(result, null, null, null, -1, null, false);
+ return new InputBindResult(result, null, null, null, -1, false);
}
/**
diff --git a/core/java/com/android/server/OWNERS b/core/java/com/android/server/OWNERS
index 12629254..554e278 100644
--- a/core/java/com/android/server/OWNERS
+++ b/core/java/com/android/server/OWNERS
@@ -1 +1 @@
-per-file SystemConfig.java = toddke@google.com
+per-file SystemConfig.java = toddke@google.com,patb@google.com
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index a9b47aa..bd0de29 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -169,7 +169,7 @@
// These are the packages that are white-listed to be able to retrieve location even when user
// location settings are off, for emergency purposes, as read from the configuration files.
- final ArraySet<String> mAllowIgnoreLocationSettings = new ArraySet<>();
+ final ArrayMap<String, ArraySet<String>> mAllowIgnoreLocationSettings = new ArrayMap<>();
// These are the action strings of broadcasts which are whitelisted to
// be delivered anonymously even to apps which target O+.
@@ -313,7 +313,7 @@
return mAllowUnthrottledLocation;
}
- public ArraySet<String> getAllowIgnoreLocationSettings() {
+ public ArrayMap<String, ArraySet<String>> getAllowIgnoreLocationSettings() {
return mAllowIgnoreLocationSettings;
}
@@ -867,11 +867,25 @@
case "allow-ignore-location-settings": {
if (allowOverrideAppRestrictions) {
String pkgname = parser.getAttributeValue(null, "package");
+ String attributionTag = parser.getAttributeValue(null,
+ "attributionTag");
if (pkgname == null) {
Slog.w(TAG, "<" + name + "> without package in "
+ permFile + " at " + parser.getPositionDescription());
} else {
- mAllowIgnoreLocationSettings.add(pkgname);
+ ArraySet<String> tags = mAllowIgnoreLocationSettings.get(pkgname);
+ if (tags == null || !tags.isEmpty()) {
+ if (tags == null) {
+ tags = new ArraySet<>(1);
+ mAllowIgnoreLocationSettings.put(pkgname, tags);
+ }
+ if (!"*".equals(attributionTag)) {
+ if ("null".equals(attributionTag)) {
+ attributionTag = null;
+ }
+ tags.add(attributionTag);
+ }
+ }
}
} else {
logNotAllowedInPartition(name, permFile, parser);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 1f805c9..1468633 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -128,6 +128,7 @@
"android_graphics_BLASTBufferQueue.cpp",
"android_view_SurfaceSession.cpp",
"android_view_TextureView.cpp",
+ "android_view_TunnelModeEnabledListener.cpp",
"android_view_VelocityTracker.cpp",
"android_view_VerifiedKeyEvent.cpp",
"android_view_VerifiedMotionEvent.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f76cccb..7e8fc7e 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -127,6 +127,7 @@
extern int register_android_view_SurfaceSession(JNIEnv* env);
extern int register_android_view_CompositionSamplingListener(JNIEnv* env);
extern int register_android_view_TextureView(JNIEnv* env);
+extern int register_android_view_TunnelModeEnabledListener(JNIEnv* env);
extern int register_android_database_CursorWindow(JNIEnv* env);
extern int register_android_database_SQLiteConnection(JNIEnv* env);
extern int register_android_database_SQLiteGlobal(JNIEnv* env);
@@ -1521,6 +1522,7 @@
REG_JNI(register_android_view_SurfaceSession),
REG_JNI(register_android_view_CompositionSamplingListener),
REG_JNI(register_android_view_TextureView),
+ REG_JNI(register_android_view_TunnelModeEnabledListener),
REG_JNI(register_com_google_android_gles_jni_EGLImpl),
REG_JNI(register_com_google_android_gles_jni_GLImpl),
REG_JNI(register_android_opengl_jni_EGL14),
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 3acbd1e..787d348 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -36,7 +36,6 @@
#include <utils/List.h>
#include <utils/KeyedVector.h>
#include <binder/Parcel.h>
-#include <binder/ParcelRef.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/threads.h>
@@ -516,9 +515,8 @@
static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
- sp<ParcelRef> parcelRef = ParcelRef::create();
- parcelRef->incStrong(reinterpret_cast<const void*>(android_os_Parcel_create));
- return reinterpret_cast<jlong>(static_cast<Parcel *>(parcelRef.get()));
+ Parcel* parcel = new Parcel();
+ return reinterpret_cast<jlong>(parcel);
}
static void android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
@@ -531,8 +529,8 @@
static void android_os_Parcel_destroy(JNIEnv* env, jclass clazz, jlong nativePtr)
{
- ParcelRef* derivative = static_cast<ParcelRef*>(reinterpret_cast<Parcel*>(nativePtr));
- derivative->decStrong(reinterpret_cast<const void*>(android_os_Parcel_create));
+ Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
+ delete parcel;
}
static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jlong nativePtr)
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 29f8ccf..793b4eb 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -35,7 +35,6 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
-#include <binder/ParcelRef.h>
#include <binder/ProcessState.h>
#include <binder/Stability.h>
#include <binderthreadstate/CallerUtils.h>
@@ -1381,8 +1380,7 @@
}
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
- jint code, jobject dataObj, jobject replyObj, jboolean replyObjOwnsNativeParcel,
- jint flags) // throws RemoteException
+ jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
if (dataObj == NULL) {
jniThrowNullPointerException(env, NULL);
@@ -1424,21 +1422,6 @@
status_t err = target->transact(code, *data, reply, flags);
//if (reply) printf("Transact from Java code to %p received: ", target); reply->print();
- if (reply) {
- if (replyObjOwnsNativeParcel) {
- // as per Parcel java class constructor, here, "reply" MUST be a "ParcelRef"
- // only for Parcel that contained Binder objects
- if (reply->objectsCount() > 0) {
- IPCThreadState::self()->createTransactionReference(static_cast<ParcelRef*>(reply));
- }
- } else {
- // as per Parcel.java, if Parcel java object NOT owning native Parcel object, it will
- // NOT destroy the native Parcel object upon GC(finalize()), so, there will be no race
- // condtion in this case. Please refer to the java class methods: Parcel.finalize(),
- // Parcel.destroy().
- }
- }
-
if (kEnableBinderSample) {
if (time_binder_calls) {
conditionally_log_binder_call(start_millis, target, code);
@@ -1567,7 +1550,7 @@
{"pingBinder", "()Z", (void*)android_os_BinderProxy_pingBinder},
{"isBinderAlive", "()Z", (void*)android_os_BinderProxy_isBinderAlive},
{"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor},
- {"transactNative", "(ILandroid/os/Parcel;Landroid/os/Parcel;ZI)Z", (void*)android_os_BinderProxy_transact},
+ {"transactNative", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
{"linkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
{"unlinkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
{"getNativeFinalizer", "()J", (void*)android_os_BinderProxy_getNativeFinalizer},
diff --git a/core/jni/android_view_TunnelModeEnabledListener.cpp b/core/jni/android_view_TunnelModeEnabledListener.cpp
new file mode 100644
index 0000000..af7bae8
--- /dev/null
+++ b/core/jni/android_view_TunnelModeEnabledListener.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "TunnelModeEnabledListener"
+
+#include "android_util_Binder.h"
+#include "core_jni_helpers.h"
+
+#include <nativehelper/JNIHelp.h>
+
+#include <android/gui/BnTunnelModeEnabledListener.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <utils/Log.h>
+
+#include <gui/SurfaceComposerClient.h>
+#include <ui/Rect.h>
+
+namespace android {
+
+namespace {
+
+struct {
+ jclass mClass;
+ jmethodID mDispatchOnTunnelModeEnabledChanged;
+} gListenerClassInfo;
+
+struct TunnelModeEnabledListener : public gui::BnTunnelModeEnabledListener {
+ TunnelModeEnabledListener(JNIEnv* env, jobject listener)
+ : mListener(env->NewWeakGlobalRef(listener)) {}
+
+ binder::Status onTunnelModeEnabledChanged(bool tunnelModeEnabled) override {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ LOG_ALWAYS_FATAL_IF(env == nullptr,
+ "Unable to retrieve JNIEnv in onTunnelModeEnabledChanged.");
+
+ jobject listener = env->NewGlobalRef(mListener);
+ if (listener == NULL) {
+ // Weak reference went out of scope
+ return binder::Status::ok();
+ }
+ env->CallStaticVoidMethod(gListenerClassInfo.mClass,
+ gListenerClassInfo.mDispatchOnTunnelModeEnabledChanged, listener,
+ static_cast<jboolean>(tunnelModeEnabled));
+ env->DeleteGlobalRef(listener);
+
+ if (env->ExceptionCheck()) {
+ ALOGE("TunnelModeEnabledListener.onTunnelModeEnabledChanged() failed.");
+ LOGE_EX(env);
+ env->ExceptionClear();
+ }
+ return binder::Status::ok();
+ }
+
+protected:
+ virtual ~TunnelModeEnabledListener() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->DeleteWeakGlobalRef(mListener);
+ }
+
+private:
+ jweak mListener;
+};
+
+jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) {
+ TunnelModeEnabledListener* listener = new TunnelModeEnabledListener(env, obj);
+ listener->incStrong((void*)nativeCreate);
+ return reinterpret_cast<jlong>(listener);
+}
+
+void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
+ TunnelModeEnabledListener* listener = reinterpret_cast<TunnelModeEnabledListener*>(ptr);
+ listener->decStrong((void*)nativeCreate);
+}
+
+void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr) {
+ sp<TunnelModeEnabledListener> listener = reinterpret_cast<TunnelModeEnabledListener*>(ptr);
+ if (SurfaceComposerClient::addTunnelModeEnabledListener(listener) != OK) {
+ constexpr auto error_msg = "Couldn't addTunnelModeEnabledListener";
+ ALOGE(error_msg);
+ jniThrowRuntimeException(env, error_msg);
+ }
+}
+
+void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
+ sp<TunnelModeEnabledListener> listener = reinterpret_cast<TunnelModeEnabledListener*>(ptr);
+
+ if (SurfaceComposerClient::removeTunnelModeEnabledListener(listener) != OK) {
+ constexpr auto error_msg = "Couldn't removeTunnelModeEnabledListener";
+ ALOGE(error_msg);
+ jniThrowRuntimeException(env, error_msg);
+ }
+}
+
+const JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ {"nativeCreate", "(Landroid/view/TunnelModeEnabledListener;)J", (void*)nativeCreate},
+ {"nativeDestroy", "(J)V", (void*)nativeDestroy},
+ {"nativeRegister", "(J)V", (void*)nativeRegister},
+ {"nativeUnregister", "(J)V", (void*)nativeUnregister}};
+
+} // namespace
+
+int register_android_view_TunnelModeEnabledListener(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "android/view/TunnelModeEnabledListener", gMethods,
+ NELEM(gMethods));
+ LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
+
+ jclass clazz = env->FindClass("android/view/TunnelModeEnabledListener");
+ gListenerClassInfo.mClass = MakeGlobalRefOrDie(env, clazz);
+ gListenerClassInfo.mDispatchOnTunnelModeEnabledChanged =
+ env->GetStaticMethodID(clazz, "dispatchOnTunnelModeEnabledChanged",
+ "(Landroid/view/TunnelModeEnabledListener;Z)V");
+ return 0;
+}
+
+} // namespace android
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index ea5e7f72..44ea23f 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -16,7 +16,7 @@
jjaggi@google.com
kwekua@google.com
roosa@google.com
-per-file package_item_info.proto = toddke@google.com
+per-file package_item_info.proto = toddke@google.com,patb@google.com
per-file usagestatsservice.proto, usagestatsservice_v2.proto = file:/core/java/android/app/usage/OWNERS
per-file apphibernationservice.proto = file:/core/java/android/apphibernation/OWNERS
diff --git a/core/proto/android/server/biometrics.proto b/core/proto/android/server/biometrics.proto
index ac9e3e0..fc9da90 100644
--- a/core/proto/android/server/biometrics.proto
+++ b/core/proto/android/server/biometrics.proto
@@ -91,9 +91,23 @@
STATE_CLIENT_DIED_CANCELLING = 10;
}
+ enum MultiSensorState {
+ // Initializing or not yet started.
+ MULTI_SENSOR_STATE_UNKNOWN = 0;
+ // Sensors are in the process of being transitioned and there is no active sensor.
+ MULTI_SENSOR_STATE_SWITCHING = 1;
+ // Face sensor is being used as the primary input.
+ MULTI_SENSOR_STATE_FACE_SCANNING = 2;
+ // Fingerprint sensor is being used as the primary input.
+ MULTI_SENSOR_STATE_FP_SCANNING = 3;
+ }
+
repeated SensorServiceStateProto sensor_service_states = 1;
optional AuthSessionState auth_session_state = 2;
+
+ // Additional session state information, when the device has multiple sensors.
+ optional MultiSensorState auth_session_multi_sensor_state = 3;
}
// Overall state for an instance of a <Biometric>Service, for example FingerprintService or
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 084d4d1..f457c56 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2890,7 +2890,13 @@
<permission android:name="android.permission.SET_DISPLAY_OFFSET"
android:protectionLevel="signature|privileged" />
- <!-- Allows a companion app to run in the background.
+ <!-- Allows a companion app to run in the background. This permission implies
+ {@link android.Manifest.permission#REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND},
+ and allows to start a foreground service from the background.
+ If an app does not have to run in the background, but only needs to start a foreground
+ service from the background, consider using
+ {@link android.Manifest.permission#REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND},
+ which is less powerful.
<p>Protection level: normal
-->
<permission android:name="android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND"
@@ -2900,6 +2906,7 @@
<!-- Allows a companion app to start a foreground service from the background.
{@see android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND}
+ <p>Protection level: normal
-->
<permission android:name="android.permission.REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND"
android:protectionLevel="normal"/>
diff --git a/core/res/res/color/text_color_on_accent_device_default.xml b/core/res/res/color/text_color_on_accent_device_default.xml
new file mode 100644
index 0000000..1379523
--- /dev/null
+++ b/core/res/res/color/text_color_on_accent_device_default.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<!-- Please see primary_text_material_light.xml -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:color="@color/system_neutral1_400"/>
+ <item android:color="@color/system_neutral1_900"/>
+</selector>
diff --git a/core/res/res/drawable/notification_material_media_action_background.xml b/core/res/res/drawable/notification_material_media_action_background.xml
index 4f50f15..b4ec7fd 100644
--- a/core/res/res/drawable/notification_material_media_action_background.xml
+++ b/core/res/res/drawable/notification_material_media_action_background.xml
@@ -16,4 +16,10 @@
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@color/ripple_material_light" />
+ android:color="@color/ripple_material_light">
+ <item android:id="@id/mask">
+ <shape android:shape="oval">
+ <solid android:color="#333" />
+ </shape>
+ </item>
+</ripple>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index c970188..03e32a8 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Vingerafdrukikoon"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"bestuur Gesigslothardeware"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Laat program toe om metodes te benut om gesigtemplate vir gebruik by te voeg en uit te vee."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"gebruik Gesigslothardeware"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Laat die program toe om Gesigslothardeware vir stawing te gebruik"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Gesigslot"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Skryf jou gesig weer in"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Skryf asseblief jou gesig weer in om herkenning te verbeter"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Stel Gesigslot op"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Ontsluit jou foon deur daarna te kyk"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Stel meer maniere op om te ontsluit"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tik om \'n vingerafdruk by te voeg"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Kan nie gesig verifieer nie. Hardeware nie beskikbaar nie."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Probeer Gesigslot weer."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Kan nie nuwe gesigdata berg nie. Vee eers \'n ou een uit."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Gesighandeling is gekanselleer."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Gebruiker het Gesigslot gekanselleer."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Te veel pogings. Probeer later weer."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Te veel pogings. Gesigslot is gedeaktiveer."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Kan nie gesig verifieer nie. Probeer weer."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Jy het nie Gesigslot opgestel nie."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Gesigslot word nie op hierdie toestel gesteun nie."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor is tydelik gedeaktiveer."</string>
<string name="face_name_template" msgid="3877037340223318119">"Gesig <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Gebruik Gesigslot"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Gebruik Gesigslot of Skermslot"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Gebruik jou gesig om voort te gaan"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gebruik jou gesig of skermslot om voort te gaan"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Vou ontsluitruimte uit."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Sleep-ontsluit."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Patroon ontsluit."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Gesigslot."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PIN ontsluit."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM-PIN-ontsluiting."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM-PUK-ontsluiting."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Skakel af"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Kom meer te wete"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Verbeterde kennisgewings het Android se aanpasbare kennisgewings in Android 12 vervang. Hierdie kenmerk wys voorgestelde handelinge en antwoorde en organiseer jou kennisgewings.\n\nVerbeterde kennisgewings het toegang tot kennisgewinginhoud, insluitend persoonlike inligting soos kontakname en boodskappe. Hierdie kenmerk kan ook kennisgewings toemaak of daarop antwoord, soos om foonoproepe te beantwoord en Moenie Steur Nie te beheer."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Roetinemodus-inligtingkennisgewing"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery kan afloop voordat dit normaalweg gelaai word"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterybespaarder is geaktiveer om batterylewe te verleng"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index cb9423e..0c1d456 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"የጣት አሻራ አዶ"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"በመልክ መክፈቻ ሃርድዌርን ማስተዳደር"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"መተግበሪያው ጥቅም ላይ እንዲውሉ የፊት ቅንብር ደንቦችን ለማከል እና ለመሰረዝ የሚያስችሉ ስልቶችን እንዲያስጀምር ያስችለዋል።"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"በመልክ መክፈት ሃርድዌርን መጠቀም"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"መተግበሪያው የመልክ መክፈቻ ሃርድዌርን ለማረጋገጥ እንዲጠቀም ያስችለዋል"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"በመልክ መክፈት"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"የእርስዎን ፊት ዳግመኛ ያስመዝግቡ"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"ማንነትን ለይቶ ማወቅን ለማሻሻል፣ እባክዎ የእርስዎን ፊት ዳግም ያስመዝግቡ"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"በመልክ መክፈቻን ያቀናብሩ"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"ስልክዎን በመመልከት ያስከፍቱት"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"የሚከፍቱባቸው ተጨማሪ መንገዶችን ያቀናብሩ"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"የጣት አሻራን ለማከል መታ ያድርጉ"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"መልክን ማረጋገጥ አይቻልም። ሃርድዌር የለም።"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"በመልክ መክፈትን እንደገና ይሞክሩ።"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"አዲስ የመልክ ውውሂብ ማስቀመጥ አልተቻለም። መጀመሪያ የድሮውን ይሰርዙት።"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"የፊት ሥርዓተ ክወና ተሰርዟል።"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"በመልክ መክፈት በተጠቃሚ ተሰርዟል።"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"ከልክ በላይ ብዙ ሙከራዎች። በኋላ ላይ እንደገና ይሞክሩ።"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"በጣም ብዙ ሙከራዎች። በመልክ መክፈት ተሰናክሏል።"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"ፊትን ማረጋገጥ አይቻልም። እንደገና ይሞክሩ።"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"በመልክ መክፈትን አላቀናበሩም።"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"በመልክ መክፈት መስጫ በዚህ መሣሪያ ላይ አይደገፍም።"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"ዳሳሽ ለጊዜው ተሰናክሏል።"</string>
<string name="face_name_template" msgid="3877037340223318119">"ፊት <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"በመልክ መክፈትን ይጠቀሙ"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"የመልክ ወይም የማያ ገጽ መቆለፊያን ይጠቀሙ"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"ለመቀጠል መልክዎን ይጠቀሙ"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ለመቀጠል መልክዎን ወይም የማያ ገጽዎን መቆለፊያ ይጠቀሙ"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"የመክፈቻ አካባቢውን አስፋፋ።"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"በማንሸራተት ክፈት።"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"በስርዓተ-ጥለት መክፈት።"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"በመልክ መክፈት።"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"በፒን መክፈት።"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"የሲም ፒን ክፈት።"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"የሲም PUK ክፈት።"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"እሺ"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"አጥፋ"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"የበለጠ ለመረዳት"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"የተሻሻሉ ማሳወቂያዎች በAndroid 12 ውስጥ Android ራስ-አስማሚ ማሳወቂያዎችን ተክተዋል። ይህ ባህሪ የተጠቆሙ እርምጃዎችን እና ምላሾችን ያሳያል እንዲሁም ማሳወቂያዎችዎን ያደራጃል።\n\nየተሻሻሉ ማሳወቂያዎች እንደ የእውቂያ ስሞች እና መልዕክቶች ያሉ የግል መረጃዎችን ጨምሮ የማሳወቂያ ይዘቶችን መድረስ ይችላሉ። ይህ ባህሪ እንደ የስልክ ጥሪዎችን መመለስ እና አትረብሽን መቆጣጠርን ያሉ ማሳወቂያዎችን ማሰናበት ወይም ምላሽ መስጠት ይችላል።"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"የዕለት ተዕለት ሁነታ መረጃ ማሳወቂያዎች"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ባትሪ ከተለመደው ኃይል መሙላት በፊት ሊያልቅ ይችላል"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"የባትሪ ቆጣቢ የባትሪ ዕድሜን ለማራዘም ገብሯል።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index b658b10..88ad4b3 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -621,14 +621,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"رمز بصمة الإصبع"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"إدارة أجهزة ميزة \"فتح الجهاز بالتعرف على الوجه\""</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"السماح للتطبيق باستدعاء طرق لإضافة نماذج من الوجوه وحذفها"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"استخدام أجهزة ميزة \"فتح الجهاز بالتعرف على الوجه\""</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"السماح للتطبيق باستخدام أجهزة ميزة \"فتح الجهاز بالتعرف على الوجه\" لإجراء المصادقة"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"فتح الجهاز بالتعرف على الوجه"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"إعادة تسجيل وجهك"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"لتحسين قدرة الجهاز على معرفة وجهك، يُرجى إعادة تسجيل الوجه."</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"إعداد ميزة \"فتح الجهاز بالتعرف على الوجه\""</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"يمكنك فتح قفل هاتفك بمجرّد النظر إلى الشاشة."</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"إعداد المزيد من الطرق لفتح قفل الجهاز"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"انقر لإضافة بصمة إصبع."</string>
@@ -655,18 +653,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"يتعذّر التحقُّق من الوجه. الجهاز غير مُتاح."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"جرِّب استخدام ميزة \"فتح الجهاز بالتعرف على الوجه\" مرة أخرى."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"يتعذَّر تخزين بيانات الوجه الجديد. احذف الوجه القديم أولاً."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"تمّ إلغاء عملية مصادقة الوجه."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"ألغى المستخدم ميزة \"فتح الجهاز بالتعرف على الوجه\"."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"تمّ إجراء محاولات كثيرة. أعِد المحاولة لاحقًا."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"تم إجراء محاولات كثيرة، ولذا تم إيقاف ميزة \"فتح الجهاز بالتعرف على الوجه\"."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"يتعذّر التحقق من الوجه. حاول مرة أخرى."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"لم يسبق لك إعداد ميزة \"فتح الجهاز بالتعرف على الوجه\"."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"ميزة \"فتح الجهاز بالتعرف على الوجه\" غير متوفرة بهذا الجهاز."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"تم إيقاف جهاز الاستشعار مؤقتًا."</string>
<string name="face_name_template" msgid="3877037340223318119">"الوجه <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"فتح الجهاز بالتعرف على الوجه"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"استخدام ميزة \"فتح الجهاز بالتعرف على الوجه\" أو ميزة \"قفل الشاشة\""</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"استخدِم الوجه للمتابعة"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"استخدام ميزة \"فتح القفل بالوجه\" أو ميزة \"قفل الشاشة\" للمتابعة"</string>
@@ -969,7 +975,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"توسيع منطقة فتح القفل."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"فتح القفل باستخدام التمرير."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"فتح القفل باستخدام النقش."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"استخدام ميزة \"فتح الجهاز بالتعرف على الوجه\""</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"فتح القفل باستخدام رمز PIN."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"فتح قفل رقم التعريف الشخصي لشريحة SIM."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"فتح قفل مفتاح PUK لشريحة SIM."</string>
@@ -2208,9 +2215,9 @@
<string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"سيتم كتم صوت الهاتف عند تلقي المكالمات والإشعارات"</string>
<string name="notification_channel_system_changes" msgid="2462010596920209678">"تغييرات النظام"</string>
<string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"عدم الإزعاج"</string>
- <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"جديد: يؤدي تفعيل وضع \"الرجاء عدم الإزعاج\" إلى إخفاء الإشعارات."</string>
+ <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"جديد: يؤدي تفعيل ميزة \"عدم الإزعاج\" إلى إخفاء الإشعارات."</string>
<string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"انقر لمعرفة مزيد من المعلومات وإجراء التغيير."</string>
- <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"تم تغيير وضع \"الرجاء عدم الإزعاج\"."</string>
+ <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"تم تغيير ميزة \"عدم الإزعاج\""</string>
<string name="zen_upgrade_notification_content" msgid="5228458567180124005">"انقر للاطّلاع على ما تم حظره."</string>
<string name="notification_app_name_system" msgid="3045196791746735601">"النظام"</string>
<string name="notification_app_name_settings" msgid="9088548800899952531">"الإعدادات"</string>
@@ -2227,8 +2234,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"حسنًا"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"إيقاف"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"مزيد من المعلومات"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"تم إبدال الإشعارات التكيُّفية لنظام التشغيل Android في الإصدار 12 منه بالإشعارات المحسّنة. تعرض هذه الميزة إجراءات وردودًا مقترحة وتنظِّم الإشعارات.\n\nيمكن للإشعارات المحسّنة الوصول إلى محتوى الإشعارات، بما في المعلومات الشخصية، مثلاً أسماء جهات الاتصال والرسائل. يمكن لهذه الميزة أيضًا إغلاق الإشعارات أو الاستجابة لها، مثلاً الردّ على مكالمات الهاتف والتحكّم في ميزة \"عدم الإزعاج\"."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"إشعار معلومات \"وضع سلسلة الإجراءات\""</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"قد تنفد طاقة البطارية قبل الشحن المعتاد"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"تم تفعيل \"توفير شحن البطارية\" لإطالة عمرها."</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 68c270e..9299289 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ফিংগাৰপ্ৰিণ্ট আইকন"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"ফেচ আনলক হার্ডৱেৰ পৰিচালনা কৰক"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"মুখমণ্ডলৰ টেম্প্লেট যোগ কৰাৰ বা মচাৰ পদ্ধতি কামত লগাবলৈ আহ্বান কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ফেচ আনলক হার্ডৱেৰ ব্যৱহাৰ কৰক"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"বিশ্বাসযোগ্যতা প্ৰমাণীকৰণৰ বাবে এপ্ক ফেচ আনলক কৰা হাৰ্ডৱেৰ ব্যৱহাৰ কৰিবলৈ দিয়ে"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ফেচ আনলক কৰা সুবিধা"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"আপোনাৰ মুখমণ্ডল পুনৰ পঞ্জীয়ণ কৰক"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"চিনাক্তকৰণৰ সুবিধাটো উন্নত কৰিবলৈ, অনুগ্ৰহ কৰি আপোনাৰ মুখমণ্ডল পুনৰ পঞ্জীয়ন কৰক"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"ফেচ আনলক সুবিধাটো ছেট আপ কৰক"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"আপোনাৰ ফ’নটোলৈ চাই সেইটো আনলক কৰক"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"আনলক কৰাৰ অধিক উপায় ছেট আপ কৰক"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"এটা ফিংগাৰপ্ৰিণ্ট যোগ দিবলৈ টিপক"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"মুখমণ্ডল সত্যাপন কৰিব পৰা নগ’ল। হাৰ্ডৱেৰ নাই।"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"পুনৰ ফেচ আনলক কৰি চাওক।"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"নতুন মুখমণ্ডলৰ ডেটা জমা কৰিব পৰা নাই। প্ৰথমে পুৰণি এখন মচক।"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"মুখমণ্ডলৰ প্ৰক্ৰিয়া বাতিল কৰা হ’ল।"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"ব্যৱহাৰকাৰীয়ে ফেচ আনলক কৰাটো বাতিল কৰিছে।"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"অত্যধিক ভুল প্ৰয়াস। কিছুসময়ৰ পাছত আকৌ চেষ্টা কৰক।"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"অতি বেছি প্ৰয়াস। ফেচ আনলক কৰাটো অক্ষম কৰা হৈছে।"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"মুখমণ্ডল সত্যাপন কৰিব পৰা নগ’ল। আকৌ চেষ্টা কৰক।"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"আপুনি ফেচ আনলক ছেট আপ কৰা নাই।"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"এই ডিভাইচটোত ফেচ আনলক কৰা সুবিধাটো নচলে।"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"ছেন্সৰটো সাময়িকভাৱে অক্ষম হৈ আছে।"</string>
<string name="face_name_template" msgid="3877037340223318119">"মুখমণ্ডল <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"ফেচ আনলক ব্যৱহাৰ কৰক"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ফেচ আনলক অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"অব্যাহত ৰাখিবলৈ নিজৰ মুখাৱয়ব ব্যৱহাৰ কৰক"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"অব্যাহত ৰাখিবলৈ আপোনাৰ মুখাৱয়ব অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"আনলক ক্ষেত্ৰ বিস্তাৰ কৰক।"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"শ্লাইডৰদ্বাৰা আনলক।"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"আৰ্হিৰদ্বাৰা আনলক।"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"ফেচ আনলক।"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"পিনৰদ্বাৰা আনলক।"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"ছিম পিন আনলক।"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"ছিম পিইউকে আনলক।"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index b53a3d9..23127a4 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Barmaq izi ikonası"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"Üz ilə kiliddən açma avadanlığını idarə edin"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Proqramdan istifadə üçün barmaq izi şablonlarını əlavə etmək və silmək məqsədilə üsullara müraciət etməyə imkan verir."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"üz ilə kiliddən açma işlədin"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"İdentifikasiya üçün tətbiqin Üz ilə Kiliddən Açmasına icazə verir"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Üz ilə Kiliddən Açma"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Üzünüzü yenidən qeydiyyatdan keçirin"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Tanınmanı təkmilləşdirmək üçün üzünüzü yenidən qeydiyyatdan keçirin"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Üz ilə kiliddən çıxarmanı ayarlayın"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Telefona baxaraq onu kiliddən çıxarın"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Kiliddən çıxarmağın daha çox yolunu ayarlayın"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Barmaq izi əlavə etmək üçün toxunun"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Üz doğrulanmadı. Avadanlıq əlçatan deyil."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Üz ilə Kiliddən Açmanı yenidən sınayın."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Yeni üz datası saxlanmadı. Əvvəlcə köhnə olanı silin."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Üz əməliyyatı ləğv edildi."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"İstifadəçi Üz ilə Kiliddən Açmanı ləğv edib."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Həddindən çox cəhd. Sonraya saxlayın."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Həddindən çox cəhd. Üz ilə Kiliddən Açma deaktiv edildi."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Üz doğrulanmadı. Yenidən cəhd edin."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Üz ilə Kiliddən Açmanı quraşdırmamısınız."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Üz ilə Kiliddən Açma bu cihazda dəstəklənmir."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor müvəqqəti deaktivdir."</string>
<string name="face_name_template" msgid="3877037340223318119">"Üz <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Üz ilə kiliddən çıxarmadan istifadə edin"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Üz və ya ekran kilidindən istifadə edin"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Davam etmək üçün üzünüzdən istifadə edin"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Davam etmək üçün üz və ya ekran kilidinizdən istifadə edin"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Kilidi açma sahəsini genişləndir."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Sürüşdürmə kilidi."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Kild açma modeli."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Üz ilə Kiliddən Açma"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin kilid açması."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Sim Pin kilidini açın."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Sim Puk kilidini açın."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Deaktiv edin"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Ətraflı məlumat"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Genişləndirilmiş bildirişlər Android 12-də Android Adaptiv Bildirişləri əvəz etdi. Bu funksiya təklif olunan əməliyyatları və cavabları göstərir və bildirişlərinizi təşkil edir.\n\nGenişləndirilmiş bildirişlər, kontakt adları və mesajlar kimi şəxsi məlumatlar daxil olmaqla bütün bildiriş məzmununa giriş edə bilər. Bu funksiya telefon zənglərinə cavab vermək və Narahat Etməyin rejimini idarə etmək kimi bildirişləri qapada və ya cavablandıra bilər."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rejim üçün məlumat bildirişi"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batareya həmişəki vaxtdan əvvəl bitə bilər"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Enerjiyə Qənaət rejimi batareya istifadəsinin müddətini artırmaq üçün aktiv edilir"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index bcb7139..00a2233 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -612,14 +612,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona otiska prsta"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"upravljanje hardv. za otključavanje licem"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Dozvoljava da aplikacija aktivira metode za dodavanje i brisanje šablona lica radi korišćenja."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"korišćenje hardvera za otključavanje licem"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Dozvoljava da aplikacija koristi hardver za otključavanje licem radi potvrde identiteta"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Otključavanje licem"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Ponovo registrujte lice"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Da biste poboljšali prepoznavanje, ponovo registrujte lice"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Podesite otključavanje licem"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Otključajte telefon tako što ćete ga pogledati"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Podesite još načina za otključavanje"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Dodirnite da biste dodali otisak prsta"</string>
@@ -646,18 +644,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Provera lica nije uspela. Hardver nije dostupan."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Probajte ponovo otključavanje licem."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Novi podaci o licu nisu sačuvani. Prvo izbrišete prethodne."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Obrada lica je otkazana."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Korisnik je otkazao otključavanje licem"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Previše pokušaja. Probajte ponovo kasnije."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Previše pokušaja. Otključavanje licem je onemogućeno."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Provera lica nije uspela. Probajte ponovo."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Niste podesili otključavanje licem"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Otključavanje licem nije podržano na ovom uređaju"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je privremeno onemogućen."</string>
<string name="face_name_template" msgid="3877037340223318119">"Lice <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Koristite otključavanje licem"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Koristite zaključavanje licem ili zaključavanje ekrana"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Potvrdite identitet licem da biste nastavili"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Koristite lice ili zaključavanje ekrana da biste nastavili"</string>
@@ -960,7 +966,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Proširi oblast otključavanja."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Otključavanje prevlačenjem."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Otključavanje šablonom."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Otključavanje licem."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Otključavanje PIN-om."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Otključava SIM karticu PIN-om."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Otključava SIM karticu PUK-om."</string>
@@ -2128,8 +2135,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Potvrdi"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Isključi"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saznajte više"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Poboljšana obaveštenja su zamenila Android prilagodljiva obaveštenja u Android-u 12. Ova funkcija pokazuje predložene radnje i odgovore i organizuje obaveštenja.\n\nPoboljšana obaveštenja mogu da pristupaju sadržaju obaveštenja, uključujući lične podatke poput imena kontakata i poruka. Ova funkcija može i da odbacuje obaveštenja ili da odgovara na njih, na primer, da se javlja na telefonske pozive i kontroliše režim Ne uznemiravaj."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Obaveštenje o informacijama Rutinskog režima"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterija će se možda isprazniti pre uobičajenog punjenja"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Ušteda baterije je aktivirana da bi se produžilo trajanje baterije"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index bd206cf..b1a1f8e 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -615,14 +615,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок адбіткаў пальцаў"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"кіраваць апаратным забеспячэннем для распазнавання твару"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Праграма зможа дадаваць і выдаляць шаблоны твару."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"выкарыстоўваць апаратнае забеспячэнне для распазнавання твару"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Для аўтэнтыфікацыі праграма зможа ўжываць апаратнае забеспячэнне для распазнавання твару"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Распазнаванне твару"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Паўтарыце рэгістрацыю твару"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Каб палепшыць распазнавальнасць, яшчэ раз выканайце рэгістрацыю твару"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Наладзьце распазнаванне твару"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Разблакіруйце свой тэлефон, паглядзеўшы на яго"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Наладзьце дадатковыя спосабы разблакіроўкі"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Націсніце, каб дадаць адбітак пальца"</string>
@@ -649,18 +647,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Твар не спраўджаны. Абсталяванне недаступнае."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Выканайце распазнаванне твару паўторна."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Новыя даныя пра твар не захаваны. Спачатку выдаліце старыя."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Распазнаванне твару скасавана."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Распазнаванне твару скасавана карыстальнікам."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Занадта шмат спроб. Паўтарыце спробу пазней."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Занадта шмат спроб. Распазнаванне твару выключана."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Не ўдалося спраўдзіць твар. Паўтарыце спробу."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Вы не наладзілі распазнаванне твару."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"На гэтай прыладзе распазнаванне твару не падтрымліваецца."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Датчык часова выключаны."</string>
<string name="face_name_template" msgid="3877037340223318119">"Твар <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Ужываць распазнаванне твару"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Выкарыстоўваць распазнаванне твару ці блакіроўку экрана"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Каб працягнуць, скарыстайце распазнаванне твару"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Каб працягнуць, скарыстайце распазнаванне твару ці сродак разблакіроўкі экрана"</string>
@@ -963,7 +969,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Разгарнуць вобласць разблакіроўкі."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Разблакiроўка слайда."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Узор разблакiроўкі."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Распазнаванне твару"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PIN-код разблакiроўкі."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Разблакіроўка SIM-карты з дапамогай PIN-кода."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Разблакіроўка SIM-карты з дапамогай PUK-кода."</string>
@@ -2161,8 +2168,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ОК"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Выключыць"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Даведацца больш"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"У версіі Android 12 Адаптыўныя апавяшчэнні Android заменены Палепшанымі апавяшчэннямі. Гэта функцыя ўпарадкоўвае вашы апавяшчэнні і паказвае прапановы дзеянняў і адказаў.\n\nПалепшаныя апавяшчэнні маюць доступ да змесціва ўсіх апавяшчэнняў, у тым ліку да асабістай інфармацыі – імён кантактаў і паведамленняў. Яшчэ гэта функцыя можа адхіляць апавяшчэнні ці адказваць на іх, напрыклад рэагаваць на тэлефонныя выклікі і кіраваць функцыяй \"Не турбаваць\"."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Апавяшчэнне з інфармацыяй пра ўсталяваны рэжым"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Акумулятар можа разрадзіцца хутчэй, чым прыйдзе час звычайнай зарадкі"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Каб павялічыць тэрмін работы акумулятара, уключаны рэжым эканоміі зараду"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 5f3bd7e..b30dd1b 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Икона за отпечатък"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"управление на хардуера за отключване с лице"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Разрешава на прил. да извиква методи за добавяне и изтриване на лицеви шаблони за ползване"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"използване на хардуера за отключване с лице"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Разрешава на приложението да използва хардуера за отключване с лице с цел удостоверяване"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Отключване с лице"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Регистрирайте отново лицето си"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"С цел подобряване на разпознаването регистрирайте отново лицето си"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Настройване на отключването с лице"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Отключвайте телефона си, като го погледнете"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Настройване на още начини за отключване на телефона"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Докоснете, за да добавите отпечатък"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Лицето не може да се потвърди. Хардуерът не е налице."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Опитайте отново да отключите с лице."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Не може да се запази ново лице. Първо изтрийте старо."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Операцията с лице е анулирана."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Отключването с лице е анулирано от потребителя."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Твърде много опити. Опитайте отново по-късно."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Твърде много опити. Отключването с лице е деактивирано."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Лицето не може да се потвърди. Опитайте отново."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Не сте настроили отключването с лице."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Отключването с лице не се поддържа на това устройство."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Сензорът е временно деактивиран."</string>
<string name="face_name_template" msgid="3877037340223318119">"Лице <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Използване на отключв. с лице"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Използване на отключването с лице или опцията за заключване на екрана"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Използвайте лицето си, за да продължите"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Използвайте лицето си или опцията за заключване на екрана, за да продължите"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Разгъване на областта за отключване."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Отключване с плъзгане."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Отключване с фигура."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Отключване с лице."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Отключване с ПИН код."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Отключване на SIM картата с ПИН код."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Отключване на SIM картата с PUK код."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Изключване"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Научете повече"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Адаптивните известия бяха заменени от функцията за подобрени известия в Android 12. Тя показва предложени действия и отговори и организира известията ви.\n\nФункцията може да осъществява достъп до съдържанието в известията, включително личната информация, като например имената на контактите и текстовите съобщения. Тя има възможност да отхвърля известията или да предприема действия в тях, като например приемане на телефонни обаждания или контролиране на режима „Не безпокойте“."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Известие с информация за режима на поредица"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батерията може да се изтощи преди обичайното зареждане"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Режимът за запазване на батерията е активиран с цел удължаване на живота на батерията"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index ab58e84..bca1b85 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"আঙ্গুলের ছাপ আইকন"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"ফেস আনলক হার্ডওয়্যার ম্যানেজ করা"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"ব্যবহার করার জন্য ফেস টেম্পলেট যোগ করা এবং মোছার পদ্ধতি গ্রহণ করতে অ্যাপটিকে অনুমতি দেয়৷"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ফেস আনলক হার্ডওয়্যার ব্যবহার করা"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"অ্যাপকে যাচাইকরণের জন্য ফেস আনলক হার্ডওয়্যার ব্যবহার করতে দেয়"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ফেস আনলক"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"আপনার ফেস আবার এনরোল করুন"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"শনাক্তকরণের উন্নতি করতে আপনার ফেস আবার এনরোল করুন"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"ফেস আনলক ফিচার সেট-আপ করুন"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"আপনার ফোনের দিকে তাকিয়ে এটিকে আনলক করুন"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"আনলক করার জন্য বিভিন্ন উপায়ে সেট আপ করুন"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"একটি আঙ্গুলের ছাপ যোগ করতে ট্যাপ করুন"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ফেস যাচাই করা যায়নি। হার্ডওয়্যার উপলভ্য নেই।"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"আবার ফেস আনলকের মাধ্যমে চেষ্টা করুন।"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"নতুন ফেস ডেটা স্টোর করা যায়নি। প্রথমে পুরনোটি মুছে ফেলুন।"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"ফেস অপারেশন বাতিল করা হয়েছে৷"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"ব্যবহারকারী ফেস আনলক বাতিল করে দিয়েছেন।"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"অনেকবার চেষ্টা করা হয়েছে। পরে আবার চেষ্টা করুন।"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"অনেকবার চেষ্টা করেছেন। ফেস আনলক বন্ধ করা হয়েছে।"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"আপনার মুখ যাচাই করা যাচ্ছে না। আবার চেষ্টা করুন।"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"এখনও ফেস আনলক সেট-আপ করেননি।"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"এই ডিভাইসে ফেস আনলক সুবিধাটি কাজ করে না।"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"সেন্সর অস্থায়ীভাবে বন্ধ করা আছে।"</string>
<string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> ফেস"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"ফেস আনলক ব্যবহার করুন"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ফেস অথবা স্ক্রিন লক ব্যবহার করুন"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"চালিয়ে যেতে আপনার মুখ ব্যবহার করুন"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"চালিয়ে যেতে আপনার ফেস বা স্ক্রিন লক ব্যবহার করুন"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"আনলক এলাকা প্রসারিত করুন৷"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"স্লাইড দিয়ে আনলক৷"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"প্যাটার্ন দিয়ে আনলক৷"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"ফেস আনলক৷"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"পিন দিয়ে আনলক৷"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"সিম পিন আনলক।"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"সিম পিইউকে আনলক।"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 90e6fbc..4a38db0 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -612,14 +612,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona za otisak prsta"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"upravljanje hardverom za otključavanje licem"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Omogućava aplikaciji korištenje metoda za dodavanje i brisanje šablona lica za upotrebu."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"korištenje hardvera za otključavanje licem"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Omogućava aplikaciji da za autentifikaciju koristi hardver za otključavanje licem"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Otključavanje licem"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Ponovo registrirajte lice"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Ponovo registrirajte lice da poboljšate prepoznavanje"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Postavite otključavanje licem"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Otključajte telefon gledajući u njega"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Postavite više načina otključavanja"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Dodirnite da dodate otisak prsta"</string>
@@ -646,18 +644,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Nije moguće potvrditi lice. Hardver nije dostupan."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Pokušajte ponovo s otključavanjem licem."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Nije moguće sačuvati nove podatke o licu. Prvo izbrišite stare."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Prepoznavanje lica je otkazano."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Korisnik je otkazao otključavanje licem."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Previše pokušaja. Otključavanje licem je onemogućeno."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Nije moguće potvrditi lice. Pokušajte ponovo."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Niste postavili otključavanje licem."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Otključavanje licem nije podržano na ovom uređaju."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je privremeno onemogućen."</string>
<string name="face_name_template" msgid="3877037340223318119">"Lice <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Koristi otključavanje licem"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Koristi otključavanje licem ili zaključavanje ekrana"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Koristite lice da nastavite"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Koristite lice ili zaključavanje ekrana da nastavite"</string>
@@ -960,7 +966,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Proširi oblast za otključavanje."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Otključavanje pomoću klizača."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Otključavanje uzorkom."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Otključavanje licem."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Otključavanje pinom."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Otključavanje Pin-om za Sim."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Otključavanje SIM-a PUK-om"</string>
@@ -2128,8 +2135,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Uredu"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Isključi"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saznajte više"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Poboljšana obavještenja su zamijenila Prilagodljiva obavještenja Androida u verziji Android 12. Ova funkcija prikazuje predložene radnje i odgovore te organizira vaša obavještenja.\n\nPoboljšana obavještenja mogu pristupiti sadržaju obavještenja, uključujući lične informacije kao što su imena kontakata i poruke. Ova funkcija također može odbacivati obavještenja ili odgovarati na njih, npr. može odgovarati na telefonske pozive i kontrolirati funkciju Ne ometaj."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Obavještenje za informacije Rutinskog načina"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Moguće je da će se baterija isprazniti prije uobičajenog punjenja"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Ušteda baterije je aktivirana da bi se produžio vijek trajanja baterije"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 4e5964a..2528c1b 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icona d\'empremta digital"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"gestiona el maquinari de Desbloqueig facial"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Permet que l\'aplicació afegeixi i suprimeixi plantilles de cares que es puguin fer servir."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"utilitza el maquinari de Desbloqueig facial"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Permet que l\'aplicació faci servir el maquinari de Desbloqueig facial per a l\'autenticació"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Desbloqueig facial"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Torna a registrar la cara"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Per millorar el reconeixement, torna a registrar la cara"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Configura el desbloqueig facial"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Mira el telèfon per desbloquejar-lo"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configura més maneres de desbloquejar el dispositiu"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Toca per afegir una empremta digital"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"No es pot verificar la cara. Maquinari no disponible."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Torna a provar el desbloqueig facial."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"No es poden desar dades facials noves. Suprimeix-ne d\'antigues."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"S\'ha cancel·lat el reconeixement facial."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"L\'usuari ha cancel·lat el desbloqueig facial."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Massa intents. Torna-ho a provar més tard."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Massa intents. S\'ha desactivat Desbloqueig facial."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"No es pot verificar la cara. Torna-ho a provar."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"No has configurat el desbloqueig facial"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"El desbloqueig facial no és compatible amb el dispositiu."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"El sensor està desactivat temporalment."</string>
<string name="face_name_template" msgid="3877037340223318119">"Cara <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Utilitza el desbloqueig facial"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Utilitza el desbloqueig facial o de pantalla"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Utilitza la teva cara per continuar"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilitza la cara o el bloqueig de pantalla per continuar"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Desplega l\'àrea de desbloqueig."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Desbloqueig lliscant"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Desbloqueig mitjançant patró"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Desbloqueig facial"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Desbloqueig mitjançant PIN"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Desbloqueja la SIM amb el PIN."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Desbloqueja la SIM amb el PUK."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"D\'acord"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desactiva"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Més informació"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Les notificacions millorades han substituït les notificacions adaptatives d\'Android a Android 12. Aquesta funció mostra les accions i respostes suggerides, i organitza les teves notificacions.\n\nLes notificacions millorades poden accedir al contingut de les notificacions, inclosa la informació personal com els noms dels contactes i els missatges. Aquesta funció també pot ignorar les notificacions o respondre-hi, com ara contestar a trucades, i controlar el mode No molestis."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificació d\'informació del mode de rutina"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"És possible que la bateria s\'esgoti abans de la càrrega habitual"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"S\'ha activat l\'estalvi de bateria per prolongar-ne la durada"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 86056a7..37b4c8c 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -615,14 +615,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona otisku prstů"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"správa hardwaru k odemknutí obličejem"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Umožňuje aplikaci volat metody k přidání a smazání šablon obličeje, které budou použity."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"použití hardwaru k odemknutí obličejem"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Umožňuje aplikaci provést ověření pomocí hardwaru k odemknutí obličejem"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Odemknutí obličejem"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Zaznamenejte obličej znovu"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Chcete-li rozpoznání zdokonalit, zaznamenejte obličej znovu"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Nastavte odemknutí obličejem"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Telefon odemknete pohledem"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Nastavte si více způsobů odemykání"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Klepnutím přidáte otisk prstu"</string>
@@ -649,18 +647,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Obličej nelze ověřit. Hardware není dostupný."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Zopakujte odemknutí obličejem."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Údaje o novém obličeji nelze uložit. Nejdřív vymažte starý."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Operace snímání obličeje byla zrušena."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Odemknutí obličejem zrušil uživatel."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Příliš mnoho pokusů. Zkuste to později."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Příliš mnoho pokusů. Odemknutí obličejem bylo deaktivováno."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Obličej se nepodařilo ověřit. Zkuste to znovu."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Odemknutí obličejem nemáte nastavené."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Odemknutí obličejem na tomto zařízení není podporováno."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je dočasně deaktivován."</string>
<string name="face_name_template" msgid="3877037340223318119">"Obličej <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Použít odemknutí obličejem"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Použít odemknutí obličejem nebo zámek obrazovky"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Pokračujte ověřením obličeje"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Pokračujte ověřením pomocí obličeje nebo zámku obrazovky"</string>
@@ -963,7 +969,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Rozšířit oblast odemknutí"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Odemknutí přejetím prstem."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Odemknutí gestem."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Odemknutí obličejem."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Odemknutí kódem PIN."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Odemknutí SIM karty kódem PIN."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Odemknutí SIM karty kódem PUK."</string>
@@ -2161,8 +2168,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Vypnout"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Další informace"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Adaptivní oznámení pro Android byla v systému Android 12 nahrazena vylepšenými oznámeními. Tato funkce ukazuje navrhované akce a odpovědi a uspořádává oznámení.\n\nVylepšená oznámení mají přístup k obsahu oznámení, včetně osobních údajů, jako jsou jména kontaktů a zprávy. Tato funkce také může zavírat oznámení nebo na ně odpovídat, například přijímat telefonní hovory a ovládat režim Nerušit."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Informační oznámení režimu sledu činností"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterie se možná vybije před obvyklým časem nabití"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Byl aktivován spořič baterie za účelem prodloužení výdrže"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 438cb0c..b20665e 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon for fingeraftryk"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"administrere hardware til ansigtslås"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Tillader, at appen kan bruge metoder til at tilføje og slette ansigtsskabeloner."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"bruge hardware til ansigtslås"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Tillader, at appen bruger hardware til ansigtslås til godkendelse"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Ansigtslås"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Registrer dit ansigt igen"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Registrer dit ansigt igen for at forbedre genkendelsen af det"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Konfigurer ansigtslås"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Lås din telefon op ved at kigge på den"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Konfigurer flere måder at låse op på"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tryk for at tilføje et fingeraftryk"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Ansigt ikke bekræftet. Hardware ikke tilgængelig."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Prøv ansigtslås igen."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Der kan ikke gemmes nye ansigtsdata. Slet et gammelt først."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Ansigtshandlingen blev annulleret."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Ansigtslås blev annulleret af brugeren."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Du har prøvet for mange gange. Prøv igen senere."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Du har brugt for mange forsøg. Ansigtslås er deaktiveret."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Ansigtet kan ikke genkendes. Prøv igen."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Du har ikke konfigureret ansigtslås."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Ansigtslås understøttes ikke på denne enhed."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensoren er midlertidigt deaktiveret."</string>
<string name="face_name_template" msgid="3877037340223318119">"Ansigt <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Brug ansigtslås"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Brug ansigts- eller skærmlås"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Brug dit ansigt for at fortsætte"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Brug din ansigts- eller skærmlås for at fortsætte"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Udvid oplåsningsområdet."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Lås op ved at stryge."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Lås op med mønster."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Ansigtslås."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Lås op med pinkode."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Lås op ved hjælp af pinkoden til SIM-kortet."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Lås op ved hjælp af PUK-koden til SIM-kortet."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Deaktiver"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Få flere oplysninger"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Tilpassede Android-notifikationer blev erstattet af forbedrede notifikationer i Android 12. Denne funktion viser foreslåede handlinger og svar samt organiserer dine notifikationer.\n\nForbedrede notifikationer kan få adgang til indhold i notifikationer, bl.a. personlige oplysninger såsom beskeder og navne på kontakter. Funktionen kan også afvise eller svare på notifikationer, f.eks. ved at besvare telefonopkald og justere Forstyr ikke."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notifikation med oplysninger om rutinetilstand"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Enheden løber muligvis tør for batteri, inden du normalt oplader den"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterisparefunktion er aktiveret for at forlænge batteritiden"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 4db4a5e..f8cc42d 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerabdruck-Symbol"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"Hardware für Gesichtsentsperrung verwalten"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Ermöglicht der App, Gesichtsvorlagen hinzuzufügen oder zu entfernen."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"Hardware für Gesichtsentsperrung verwenden"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Ermöglicht der App, zur Authentifizierung Hardware für Gesichtsentsperrung zu verwenden"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Gesichtsentsperrung"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Gesicht neu scannen lassen"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Für bessere Erkennung Gesicht neu scannen lassen"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Gesichtsentsperrung einrichten"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Entsperre dein Smartphone, indem du es ansiehst"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Weitere Möglichkeiten zum Entsperren einrichten"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tippe, um einen Fingerabdruck hinzuzufügen"</string>
@@ -643,19 +641,27 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Gesicht nicht erkannt. Hardware nicht verfügbar."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Gesichtsentsperrung noch einmal versuchen."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Kein Speicherplatz frei. Bitte erst ein Gesicht löschen."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Gesichtserkennung abgebrochen."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Gesichtsentsperrung vom Nutzer abgebrochen."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Zu viele Versuche, bitte später noch einmal versuchen"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Zu viele Versuche. Gesichtsentsperrung wurde deaktiviert."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Gesichtsprüfung nicht möglich. Noch mal versuchen."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Gesichtsentsperrung ist nicht eingerichtet."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Gesichtsentsperrung wird auf diesem Gerät nicht unterstützt."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Der Sensor ist vorübergehend deaktiviert."</string>
<string name="face_name_template" msgid="3877037340223318119">"Gesicht <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Gesichtsentsperrung verwenden"</string>
- <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Gesichtsentsperrung oder Displaysperre verwenden"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
+ <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Entsperrung per Gesichtserkennung oder Displaysperre verwenden"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Gesichtserkennung verwenden, um fortzufahren"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Verwende die Gesichtserkennung oder deine Display-Entsperrmethode, um fortzufahren"</string>
<string-array name="face_error_vendor">
@@ -887,7 +893,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Erneut versuchen"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Erneut versuchen"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"Entsperren, um alle Funktionen und Daten zu nutzen"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Die maximal zulässige Anzahl an Versuchen zur Gesichtsentsperrung wurde überschritten."</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Die maximal zulässige Anzahl an Versuchen zur Entsperrung per Gesichtserkennung wurde überschritten."</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"Keine SIM-Karte"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"Keine SIM-Karte im Tablet"</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"Keine SIM-Karte in deinem Android TV-Gerät."</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Entsperr-Bereich maximieren"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Entsperrung mit Fingerbewegung"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Entsperrung mit Muster"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Gesichtsentsperrung"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Entsperrung mit PIN"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM durch PIN-Eingabe entsperren."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM durch PUK-Eingabe entsperren."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Ausschalten"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Weitere Informationen"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Die adaptiven Benachrichtigungen wurden in Android 12 durch die Funktion „Erweiterte Benachrichtigungen“ ersetzt. Diese Funktion zeigt Vorschläge für Aktionen und Antworten an und sortiert Benachrichtigungen.\n\nSie kann alle Benachrichtigungen lesen, darunter auch personenbezogene Daten wie Kontaktnamen und Nachrichten. Außerdem kann sie auf Benachrichtigungen antworten oder diese schließen und so beispielsweise Anrufe entgegennehmen oder „Bitte nicht stören“ steuern."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Infomitteilung zum Ablaufmodus"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Dein Akku könnte vor der gewöhnlichen Ladezeit leer sein"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Energiesparmodus aktiviert, um die Akkulaufzeit zu verlängern"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 09e9397..9474505 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Εικονίδιο δακτυλικών αποτυπωμάτων"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"διαχείριση εξοπλισμού για ξεκλείδωμα με το πρόσωπο"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Επιτρέπει στην εφαρμογή να επικαλείται μεθόδους προσθήκης/διαγραφής προτύπων για χρήση."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"χρήση εξοπλισμού για ξεκλείδωμα με το πρόσωπο"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Επιτρέπει στην εφαρμογή έλεγχο ταυτότητας με χρήση εξοπλισμού για ξεκλείδωμα με το πρόσωπο"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Ξεκλείδωμα με το πρόσωπο"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Εγγράψτε ξανά το πρόσωπό σας"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Για να βελτιώσετε την αναγνώριση, εγγράψτε ξανά το πρόσωπό σας"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Ρυθμίστε το ξεκλείδωμα με το πρόσωπο"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Ξεκλειδώστε το τηλέφωνό σας απλώς κοιτώντας το"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Ρυθμίστε περισσότερους τρόπους ξεκλειδώματος"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Πατήστε για να προσθέσετε δακτυλικό αποτύπωμα"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Αδύν. επαλήθ. προσώπου. Μη διαθέσιμος εξοπλισμός."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Δοκιμάστε ξανά για ξεκλείδωμα με το πρόσωπο."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Η αποθήκ. νέων δεδομ. προσώπ. είναι αδύν. Διαγρ. ένα παλιό."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Η ενέργεια προσώπου ακυρώθηκε."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Το ξεκλείδωμα με το πρόσωπο ακυρώθηκε από τον χρήστη."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Πάρα πολλές προσπάθειες. Δοκιμάστε ξανά αργότερα."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Υπερβολικά πολλές προσπάθειες. Το ξεκλείδωμα με το πρόσωπο απενεργοποιήθηκε."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Αδύνατη επαλήθευση του προσώπου. Επανάληψη."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Δεν έχετε ρυθμίσει το ξεκλείδωμα με το πρόσωπο."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Το Ξεκλείδωμα με το πρόσωπο δεν υποστηρίζεται σε αυτήν τη συσκευή."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Ο αισθητήρας απενεργοποιήθηκε προσωρινά."</string>
<string name="face_name_template" msgid="3877037340223318119">"Πρόσωπο <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Χρήση ξεκλειδώματος με το πρόσωπο"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Χρήση προσώπου ή κλειδώματος οθόνης"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Χρησιμοποιήστε το πρόσωπό σας για να συνεχίσετε"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Χρησιμοποιήστε το πρόσωπό σας ή το κλείδωμα οθόνης για συνέχεια"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Ανάπτυξη περιοχής ξεκλειδώματος."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Ξεκλείδωμα ολίσθησης."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Ξεκλείδωμα μοτίβου."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Ξεκλείδωμα με το πρόσωπο."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Ξεκλείδωμα κωδικού ασφαλείας"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Ξεκλείδωμα αριθμού PIN κάρτας SIM."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Ξεκλείδωμα αριθμού PUK κάρτας SIM."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ΟΚ"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Απενεργοποίηση"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Μάθετε περισσότερα"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Στο Android 12, οι Βελτιωμένες ειδοποιήσεις αντικατέστησαν τις Προσαρμοστικές ειδοποιήσεις Android. Αυτή η λειτουργία εμφανίζει προτεινόμενες ενέργειες και απαντήσεις και οργανώνει τις ειδοποιήσεις σας.\n\nΟι Βελτιωμένες ειδοποιήσεις μπορούν να αποκτήσουν πρόσβαση σε περιεχόμενο ειδοποιήσεων, συμπεριλαμβανομένων προσωπικών στοιχείων, όπως ονομάτων επαφών και μηνυμάτων Αυτή η λειτουργία παρέχει επίσης τη δυνατότητα παράβλεψης ειδοποιήσεων ή απάντησης σε αυτές, όπως η απάντηση σε τηλεφωνικές κλήσεις και ο έλεγχος της λειτουργίας Μην ενοχλείτε."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ειδοποίηση πληροφοριών λειτουργίας Ρουτίνας"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Η μπαταρία μπορεί να εξαντληθεί πριν από τη συνηθισμένη φόρτιση"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Η Εξοικονόμηση μπαταρίας ενεργοποιήθηκε για την επέκταση της διάρκειας ζωής της μπαταρίας"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 2e4c84b..580a402 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"manage Face Unlock hardware"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Allows the app to invoke methods to add and delete facial templates for use."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"use Face Unlock hardware"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Allows the app to use Face Unlock hardware for authentication"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face Unlock"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Re-enrol your face"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"To improve recognition, please re-enrol your face"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Set up Face Unlock"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Unlock your phone by looking at it"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Set up more ways to unlock"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tap to add a fingerprint"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Can’t verify face. Hardware not available."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Try Face Unlock again."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Can’t store new face data. Delete an old one first."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Face operation cancelled."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Face Unlock cancelled by user."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Too many attempts. Try again later."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Too many attempts. Face Unlock disabled."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Can’t verify face. Try again."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"You haven’t set up Face Unlock."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face Unlock is not supported on this device."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string>
<string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Use Face Unlock"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Use face or screen lock"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Use your face to continue"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Expand unlock area."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Slide unlock."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Pattern unlock."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Face Unlock."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin unlock."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM PIN unlock."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM PUK unlock."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Turn off"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Learn more"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Enhanced notifications replaced Android adaptive notifications in Android 12. This feature shows suggested actions and replies, and organises your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls, and control Do Not Disturb."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery may run out before usual charge"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Battery Saver activated to extend battery life"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index e5bea10..bfbdeed 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"manage Face Unlock hardware"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Allows the app to invoke methods to add and delete facial templates for use."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"use Face Unlock hardware"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Allows the app to use Face Unlock hardware for authentication"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face Unlock"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Re-enrol your face"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"To improve recognition, please re-enrol your face"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Set up Face Unlock"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Unlock your phone by looking at it"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Set up more ways to unlock"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tap to add a fingerprint"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Can’t verify face. Hardware not available."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Try Face Unlock again."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Can’t store new face data. Delete an old one first."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Face operation cancelled."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Face Unlock cancelled by user."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Too many attempts. Try again later."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Too many attempts. Face Unlock disabled."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Can’t verify face. Try again."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"You haven’t set up Face Unlock."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face Unlock is not supported on this device."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string>
<string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Use Face Unlock"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Use face or screen lock"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Use your face to continue"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Expand unlock area."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Slide unlock."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Pattern unlock."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Face Unlock."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin unlock."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM PIN unlock."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM PUK unlock."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Turn off"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Learn more"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Enhanced notifications replaced Android adaptive notifications in Android 12. This feature shows suggested actions and replies, and organises your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls, and control Do Not Disturb."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery may run out before usual charge"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Battery Saver activated to extend battery life"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index d54e25a..3cba841 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"manage Face Unlock hardware"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Allows the app to invoke methods to add and delete facial templates for use."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"use Face Unlock hardware"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Allows the app to use Face Unlock hardware for authentication"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face Unlock"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Re-enrol your face"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"To improve recognition, please re-enrol your face"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Set up Face Unlock"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Unlock your phone by looking at it"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Set up more ways to unlock"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tap to add a fingerprint"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Can’t verify face. Hardware not available."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Try Face Unlock again."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Can’t store new face data. Delete an old one first."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Face operation cancelled."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Face Unlock cancelled by user."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Too many attempts. Try again later."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Too many attempts. Face Unlock disabled."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Can’t verify face. Try again."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"You haven’t set up Face Unlock."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face Unlock is not supported on this device."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string>
<string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Use Face Unlock"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Use face or screen lock"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Use your face to continue"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Expand unlock area."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Slide unlock."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Pattern unlock."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Face Unlock."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin unlock."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM PIN unlock."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM PUK unlock."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Turn off"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Learn more"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Enhanced notifications replaced Android adaptive notifications in Android 12. This feature shows suggested actions and replies, and organises your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls, and control Do Not Disturb."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery may run out before usual charge"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Battery Saver activated to extend battery life"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 812c1eb4..f5b1ec5 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"manage Face Unlock hardware"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Allows the app to invoke methods to add and delete facial templates for use."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"use Face Unlock hardware"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Allows the app to use Face Unlock hardware for authentication"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face Unlock"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Re-enrol your face"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"To improve recognition, please re-enrol your face"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Set up Face Unlock"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Unlock your phone by looking at it"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Set up more ways to unlock"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tap to add a fingerprint"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Can’t verify face. Hardware not available."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Try Face Unlock again."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Can’t store new face data. Delete an old one first."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Face operation cancelled."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Face Unlock cancelled by user."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Too many attempts. Try again later."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Too many attempts. Face Unlock disabled."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Can’t verify face. Try again."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"You haven’t set up Face Unlock."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face Unlock is not supported on this device."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string>
<string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Use Face Unlock"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Use face or screen lock"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Use your face to continue"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Expand unlock area."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Slide unlock."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Pattern unlock."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Face Unlock."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin unlock."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM PIN unlock."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM PUK unlock."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Turn off"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Learn more"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Enhanced notifications replaced Android adaptive notifications in Android 12. This feature shows suggested actions and replies, and organises your notifications.\n\nEnhanced notifications can access notification content, including personal information like contact names and messages. This feature can also dismiss or respond to notifications, such as answering phone calls, and control Do Not Disturb."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Routine Mode info notification"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Battery may run out before usual charge"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Battery Saver activated to extend battery life"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 41c4d49..eaa6071 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -609,14 +609,10 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"manage face unlock hardware"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Allows the app to invoke methods to add and delete facial templates for use."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"use face unlock hardware"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Allows the app to use face unlock hardware for authentication"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face unlock"</string>
+ <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string>
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Re-enroll your face"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"To improve recognition, please re-enroll your face"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Set up face unlock"</string>
+ <string name="face_setup_notification_title" msgid="8843461561970741790">"Set up Face Unlock"</string>
<string name="face_setup_notification_content" msgid="5463999831057751676">"Unlock your phone by looking at it"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Set up more ways to unlock"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tap to add a fingerprint"</string>
@@ -643,18 +639,19 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Can’t verify face. Hardware not available."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Try face unlock again."</string>
+ <string name="face_error_timeout" msgid="2598544068593889762">"Try Face Unlock again"</string>
<string name="face_error_no_space" msgid="5649264057026021723">"Can’t store new face data. Delete an old one first."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Face operation canceled."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Face unlock canceled by user."</string>
+ <string name="face_error_user_canceled" msgid="5766472033202928373">"Face Unlock canceled by user"</string>
<string name="face_error_lockout" msgid="7864408714994529437">"Too many attempts. Try again later."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Too many attempts. Face unlock disabled."</string>
+ <string name="face_error_lockout_permanent" msgid="3277134834042995260">"Too many attempts. Face Unlock disabled."</string>
+ <string name="face_error_lockout_screen_lock" msgid="5062609811636860928">"Too many attempts. Enter screen lock instead."</string>
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Can’t verify face. Try again."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"You haven’t set up face unlock."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock is not supported on this device."</string>
+ <string name="face_error_not_enrolled" msgid="1134739108536328412">"You haven’t set up Face Unlock"</string>
+ <string name="face_error_hw_not_present" msgid="7940978724978763011">"Face Unlock isn’t supported on this device"</string>
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporarily disabled."</string>
<string name="face_name_template" msgid="3877037340223318119">"Face <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Use face unlock"</string>
+ <string name="face_app_setting_name" msgid="5854024256907828015">"Use Face Unlock"</string>
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Use face or screen lock"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Use your face to continue"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
@@ -957,7 +954,7 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Expand unlock area."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Slide unlock."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Pattern unlock."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Face unlock."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4533832120787386728">"Face Unlock."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin unlock."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Sim Pin unlock."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Sim Puk unlock."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index b223cdd..000ee98 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícono de huella dactilar"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"administrar el hardware de desbloqueo facial"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Permite que la app emplee métodos para agregar y borrar plantillas de rostros para su uso."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"usar el hardware de desbloqueo facial"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Permite que la app use el hardware de desbloqueo facial con fines de autenticación"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Desbloqueo facial"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Vuelve a registrar tu rostro"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Para mejorar el reconocimiento, vuelve a registrar tu rostro"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Configura Desbloqueo facial"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Desbloquea el teléfono con solo mirarlo"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configura más formas de desbloquear el dispositivo"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Presiona para agregar una huella dactilar"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"No se verificó el rostro. Hardware no disponible."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Vuelve a probar el desbloqueo facial."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"No hay espacio para datos faciales nuevos. Borra uno viejo."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Se canceló el reconocimiento facial."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"El usuario canceló el desbloqueo facial."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Demasiados intentos. Inténtalo de nuevo más tarde."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Demasiados intentos. Se inhabilitó el desbloqueo facial."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"No se pudo verificar el rostro. Vuelve a intentarlo."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"No configuraste el desbloqueo facial."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"No se admite el desbloqueo facial en este dispositivo."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Se inhabilitó temporalmente el sensor."</string>
<string name="face_name_template" msgid="3877037340223318119">"Rostro <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Usar desbloqueo facial"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Usar desbloqueo facial o de pantalla"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Usa el rostro para continuar"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Usa tu rostro o bloqueo de pantalla para continuar"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Expandir el área desbloqueada"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Desbloqueo por deslizamiento"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Desbloqueo por patrón"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Desbloqueo facial"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Desbloqueo por PIN"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"PIN de desbloqueo de SIM"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"PUK de desbloqueo de SIM"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Aceptar"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desactivar"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Más información"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Las notificaciones mejoradas reemplazaron a las notificaciones adaptables en Android 12. Esta función muestra respuestas y acciones sugeridas, y organiza tus notificaciones.\n\nLas notificaciones mejoradas pueden acceder a todo el contenido de notificaciones, lo que incluye información personal, como nombres de contactos y mensajes. También puede descartar o responder notificaciones (como atender llamadas) y controlar la función No interrumpir."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificación de información del modo de Rutinas"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Es posible que la batería se agote antes de la carga habitual"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Se activó el Ahorro de batería para extender la duración de la batería"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index ae1e8a6..4b9dda0 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icono de huella digital"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"gestionar el hardware de Desbloqueo facial"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Permite que la app use métodos para añadir y suprimir plantillas de caras para su uso."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"utilizar hardware de Desbloqueo facial"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Permite que la aplicación utilice el hardware de Desbloqueo facial para autenticarte"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Desbloqueo facial"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Volver a registrar la cara"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Para mejorar el reconocimiento, vuelve a registrar tu cara"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Configura Desbloqueo facial"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Desbloquea el teléfono con solo mirarlo"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configura más formas de desbloqueo"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Toca para añadir una huella digital"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"No se puede verificar. Hardware no disponible."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Vuelve a probar Desbloqueo facial."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Para guardar nuevos datos faciales, borra otros antiguos."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Se ha cancelado el reconocimiento facial."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"El usuario ha cancelado Desbloqueo facial."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Demasiados intentos. Inténtalo de nuevo más tarde."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Muchos intentos. Se ha inhabilitado Desbloqueo facial."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"No se ha verificado tu cara. Vuelve a intentarlo."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"No has configurado Desbloqueo facial."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Desbloqueo facial no está disponible en este dispositivo."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"El sensor está inhabilitado en estos momentos."</string>
<string name="face_name_template" msgid="3877037340223318119">"Cara <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Usar Desbloqueo facial"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Usar Desbloqueo facial o Bloqueo de pantalla"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Usa tu cara para continuar"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Usa tu cara o tu bloqueo de pantalla para continuar"</string>
@@ -731,13 +737,13 @@
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Comprueba cuántas veces se han introducido contraseñas incorrectas para desbloquear la pantalla y, si te parece que han sido demasiadas, bloquea tu dispositivo Android TV o borra todos los datos de este usuario."</string>
<string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"Controla el número de contraseñas incorrectas introducidas para desbloquear la pantalla y bloquea el teléfono o borra todos los datos del usuario si se introducen demasiadas contraseñas incorrectas."</string>
<string name="policylab_resetPassword" msgid="214556238645096520">"Cambiar el bloqueo de pantalla"</string>
- <string name="policydesc_resetPassword" msgid="4626419138439341851">"Cambiar el bloqueo de pantalla"</string>
+ <string name="policydesc_resetPassword" msgid="4626419138439341851">"Cambia el bloqueo de pantalla"</string>
<string name="policylab_forceLock" msgid="7360335502968476434">"Bloquear la pantalla"</string>
- <string name="policydesc_forceLock" msgid="1008844760853899693">"Controlar cómo y cuándo se bloquea la pantalla"</string>
+ <string name="policydesc_forceLock" msgid="1008844760853899693">"Controla cómo y cuándo se bloquea la pantalla"</string>
<string name="policylab_wipeData" msgid="1359485247727537311">"Borrar todos los datos"</string>
<string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Borrar los datos del tablet sin avisar restableciendo el estado de fábrica"</string>
<string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Restablece los datos de fábrica de tu dispositivo Android TV, eliminando sin previo aviso los datos que tuviera."</string>
- <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Borrar los datos del teléfono sin avisar restableciendo el estado de fábrica"</string>
+ <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Borra los datos del teléfono sin avisar restableciendo el estado de fábrica"</string>
<string name="policylab_wipeData_secondaryUser" msgid="413813645323433166">"Borrar datos del usuario"</string>
<string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"Borra los datos del usuario en este tablet sin avisar."</string>
<string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"Eliminar los datos de este usuario del dispositivo Android TV sin previo aviso."</string>
@@ -751,7 +757,7 @@
<string name="policylab_disableCamera" msgid="5749486347810162018">"Inhabilitar cámaras"</string>
<string name="policydesc_disableCamera" msgid="3204405908799676104">"Evita el uso de las cámaras del dispositivo"</string>
<string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Desactivar algunas funciones del bloqueo de pantalla"</string>
- <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Evitar el uso de algunas funciones del bloqueo de pantalla"</string>
+ <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Evita el uso de algunas funciones del bloqueo de pantalla"</string>
<string-array name="phoneTypes">
<item msgid="8996339953292723951">"Casa"</item>
<item msgid="7740243458912727194">"Móvil"</item>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Ampliar área de desbloqueo"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Desbloqueo deslizando el dedo"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Desbloqueo por patrón"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Desbloqueo facial"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Desbloqueo por PIN"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Desbloqueo con PIN de la SIM."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Desbloqueo con PUK de la SIM."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Aceptar"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desactivar"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Más información"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Las notificaciones mejoradas sustituyen a las notificaciones adaptativas en Android 12. Esta nueva función te sugiere acciones y respuestas, y organiza tus notificaciones.\n\nLa función puede acceder al contenido de tus notificaciones, incluida información personal, como nombres de contactos y mensajes. También puede cerrar o responder a notificaciones; por ejemplo, puede contestar llamadas telefónicas y controlar No molestar."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificación sobre el modo rutina"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Quizás se agote la batería antes de lo habitual"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Se ha activado el modo Ahorro de batería para aumentar la duración de la batería"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 5044376..2df762f 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Sõrmejälje ikoon"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"hallata näoga avamise riistvara"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Lubab rakendusel tühistada meetodid kasutatavate näomallide lisamiseks ja kustutamiseks."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"kasutada näoga avamise riistvara"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Võimaldab rakendusel autentimiseks kasutada näoga avamise riistvara"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Näoga avamine"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Registreerige oma nägu uuesti"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Tuvastamise parandamiseks registreerige oma nägu uuesti"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Seadistage näoga avamine"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Avage telefon seda vaadates"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Seadistage rohkem viise avamiseks"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Puudutage sõrmejälje lisamiseks"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Nägu ei saa kinnitada. Riistvara pole saadaval."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Proovige näoga avamist uuesti."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Uue näo andmeid ei saa salvestada. Kustutage enne vanad."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Näotuvastuse toiming tühistati."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Kasutaja tühistas näoga avamise."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Liiga palju katseid. Proovige hiljem uuesti."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Liiga palju katseid. Näoga avamine on keelatud."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Nägu ei saa kinnitada. Proovige uuesti."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Näoga avamine ei ole seadistatud."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Seade ei toeta näoga avamist."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Andur on ajutiselt keelatud."</string>
<string name="face_name_template" msgid="3877037340223318119">"Nägu <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Näoga avamise kasutamine"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Näoga avamise või ekraaniluku kasutamine"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Jätkamiseks kasutage oma nägu"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Jätkamiseks kasutage oma nägu või ekraanilukku"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Avamisala laiendamine."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Lohistamisega avamine."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Mustriga avamine."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Näoga avamine."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PIN-koodiga avamine."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM-kaardi PIN-koodiga avamine."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM-kaardi PUK-koodiga avamine."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Lülita välja"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Lisateave"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Androidi versioonis 12 asendasid täiustatud märguanded Androidi kohanduvad märguanded. See funktsioon näitab soovitatud toiminguid ja vastuseid ning korrastab teie märguandeid.\n\nTäiustatud märguanded pääsevad juurde märguande sisule, sh isiklikule teabele, nagu kontaktide nimed ja sõnumid. Samuti saab selle funktsiooni abil märguannetest loobuda või neile vastata (nt vastata telefonikõnedele ja juhtida funktsiooni Mitte segada)."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rutiinirežiimi teabe märguanne"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Aku võib enne tavapärast laadimist tühjaks saada"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Akusäästja aktiveeriti aku tööea pikendamiseks"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 0007d19..eb82aa8 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Hatz-markaren ikonoa"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"kudeatu aurpegiaren bidez desblokeatzeko hardwarea"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Aurpegi-txantiloiak gehitu eta ezabatzeko metodoei dei egitea baimentzen dio aplikazioari."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"erabili aurpegiaren bidez desblokeatzeko hardwarea"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Autentifikaziorako aurpegiaren bidez desblokeatzeko hardwarea erabiltzeko baimena ematen die aplikazioei"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Aurpegiaren bidez desblokeatzeko eginbidea"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Erregistratu aurpegia berriro"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Ezagutzea hobetzeko, erregistratu aurpegia berriro"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Konfiguratu aurpegiaren bidez desblokeatzeko eginbidea"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Telefonoa desblokeatzeko, begira iezaiozu"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Konfiguratu telefonoa desblokeatzeko modu gehiago"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Sakatu hau hatz-marka bat gehitzeko"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Ezin da egiaztatu aurpegia. Hardwarea ez dago erabilgarri."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Saiatu berriro aurpegiaren bidez desblokeatzen."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Ezin dira gorde aurpegiaren datu berriak. Ezabatu zaharrak."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Utzi da aurpegiaren bidezko eragiketa."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Erabiltzaileak aurpegiaren bidez desblokeatzeko aukera utzi du"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Saiakera gehiegi egin dituzu. Saiatu berriro geroago."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Saiakera gehiegi egin dira. Aurpegiaren bidez desblokeatzeko eginbidea desgaitu egin da."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Ezin da egiaztatu aurpegia. Saiatu berriro."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Ez duzu konfiguratu aurpegiaren bidez desblokeatzeko eginbidea."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Gailu honek ez du onartzen aurpegiaren bidez desblokeatzea."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sentsorea aldi baterako desgaitu da."</string>
<string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> aurpegia"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Erabili aurpegiaren bidez desblokeatzeko eginbidea"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Erabili aurpegia edo pantailaren blokeoa"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Aurrera egiteko, erabili aurpegia"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Aurrera egiteko, erabili aurpegia edo pantailaren blokeoa"</string>
@@ -867,9 +873,9 @@
<string name="sipAddressTypeOther" msgid="6317012577345187275">"Beste bat"</string>
<string name="quick_contacts_not_available" msgid="1262709196045052223">"Ez da kontaktua ikusteko aplikaziorik aurkitu."</string>
<string name="keyguard_password_enter_pin_code" msgid="6401406801060956153">"Idatzi PIN kodea"</string>
- <string name="keyguard_password_enter_puk_code" msgid="3112256684547584093">"Idatzi PUK kodea eta PIN kode berria"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="3112256684547584093">"Idatzi PUKa eta PIN berria"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="2825313071899938305">"PUK kodea"</string>
- <string name="keyguard_password_enter_pin_prompt" msgid="5505434724229581207">"PIN kode berria"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="5505434724229581207">"PIN berria"</string>
<string name="keyguard_password_entry_touch_hint" msgid="4032288032993261520"><font size="17">"Sakatu pasahitza idazteko"</font></string>
<string name="keyguard_password_enter_password_code" msgid="2751130557661643482">"Idatzi desblokeatzeko pasahitza"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7792964196473964340">"Idatzi desblokeatzeko PIN kodea"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Zabaldu desblokeatzeko eremua."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Hatza lerratuta desblokeatzea."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Ereduaren bidez desblokeatzea."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Aurpegiaren bidez desblokeatzeko eginbidea."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PIN kodearen bidez desblokeatzea."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM txartela desblokeatzeko PIN kodea."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM txartela desblokeatzeko PUK kodea."</string>
@@ -1655,7 +1662,7 @@
<string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"Idatzi erabili nahi duzun PIN kodea"</string>
<string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"Berretsi erabili nahi duzun PIN kodea"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8871937892678885545">"SIM txartela desblokeatzen…"</string>
- <string name="kg_password_wrong_pin_code" msgid="9013856346870572451">"PIN kode okerra."</string>
+ <string name="kg_password_wrong_pin_code" msgid="9013856346870572451">"PIN okerra."</string>
<string name="kg_invalid_sim_pin_hint" msgid="4821601451222564077">"Idatzi 4 eta 8 zenbaki arteko PINa."</string>
<string name="kg_invalid_sim_puk_hint" msgid="2539364558870734339">"PUK kodeak 8 zenbaki izan behar ditu."</string>
<string name="kg_invalid_puk" msgid="4809502818518963344">"Idatzi berriro PUK kode zuzena. Hainbat saiakera oker eginez gero, betiko desgaituko da SIMa."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Ados"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desaktibatu"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Lortu informazio gehiago"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12-n, jakinarazpen hobetuek ordeztu dituzte Android-eko jakinarazpen egokituak. Eginbide horrek, iradokitako ekintzak eta erantzunak erakusten, eta zure jakinarazpenak antolatzen ditu.\n\nJakinarazpen hobetuek jakinarazpenen eduki osoa atzi dezakete, informazio pertsonala barne (esaterako, kontaktuen izenak eta mezuak). Halaber, eginbideak jakinarazpenak baztertu ditzake edo haiei erantzun diezaieke; adibidez, telefono-deiei erantzun diezaieke eta ez molestatzeko modua kontrola dezake."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ohitura moduaren informazio-jakinarazpena"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baliteke bateria ohi baino lehenago agortzea"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Bateria-aurrezlea aktibatuta dago bateriaren iraupena luzatzeko"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 3a89b9a..e41c4fe 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"نماد اثر انگشت"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"مدیریت سختافزار «قفلگشایی با چهره»"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"به برنامه امکان میدهد روشهایی را برای افزودن و حذف الگوهای چهره جهت استفاده فرابخواند."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"استفاده از سختافزار «قفلگشایی با چهره»"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"به برنامه امکان میدهد از سختافزار «قفلگشایی با چهره» برای اصالتسنجی استفاده کند"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"قفلگشایی با چهره"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"ثبت مجدد چهره"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"برای بهبود تشخیص، لطفاً چهرهتان را دوباره ثبت کنید"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"راهاندازی «قفلگشایی با چهره»"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"برای باز کردن قفل تلفن خود به آن نگاه کنید"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"راهاندازی روشهای بیشتر برای باز کردن قفل"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"برای افزودن اثر انگشت، ضربه بزنید"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"چهره تأیید نشد. سختافزار در دسترس نیست."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"«قفلگشایی با چهره» را دوباره امتحان کنید."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"داده چهره جدید ذخیره نشد. اول داده چهره قدیمی را حذف کنید."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"عملیات شناسایی چهره لغو شد."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"کاربر «قفلگشایی با چهره» را لغو کرد."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"تعداد زیادی تلاش ناموفق. بعداً دوباره امتحان کنید."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"تعداد تلاشها بیشازحد مجاز است. «قفلگشایی با چهره» غیرفعال است."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"چهره تأیید نشد. دوباره امتحان کنید."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"«قفلگشایی با چهره» را راهاندازی نکردهاید."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"«قفلگشایی با چهره» در این دستگاه پشتیبانی نمیشود."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"حسگر بهطور موقت غیرفعال است."</string>
<string name="face_name_template" msgid="3877037340223318119">"چهره <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"استفاده از «قفلگشایی با چهره»"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"استفاده از قفل صفحه یا چهره"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"برای ادامه، از چهرهتان استفاده کنید"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"برای ادامه، از تشخیص چهره یا قفل صفحه استفاده کنید"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"گسترده کردن منطقه بازگشایی شده."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"باز کردن قفل با کشیدن انگشت روی صفحه."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"باز کردن قفل با الگو."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"قفلگشایی با چهره."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"باز کردن قفل با پین."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"قفل پین سیمکارت باز شد."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"قفل Puk سیمکارت باز شد."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"تأیید"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"خاموش کردن"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"بیشتر بدانید"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"در Android نسخه ۱۲، اعلانهای بهبودیافته جایگزین «اعلانهای تطبیقی» شده است. این ویژگی پاسخها و کنشهای پیشنهادی را نمایش میدهد و اعلانهایتان را سازماندهی میکند.\n\nاعلانهای بهبودیافته میتوانند به محتوای اعلان، ازجمله اطلاعات شخصی مثل نامها و پیامهای مخاطبین دسترسی داشته باشند. این ویژگی همچنین میتواند اعلانها را رد کند یا به آنها پاسخ دهد؛ مثلاً پاسخ به تماسهای تلفنی و کنترل کردن «مزاحم نشوید»."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"اعلان اطلاعات حالت روال معمول"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ممکن است شارژ باتری قبل از شارژ معمول تمام شود"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"جهت افزایش عمر باتری، «بهینهسازی باتری» فعال شد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index b80c8fc..1a96de6 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -277,7 +277,7 @@
<string name="notification_hidden_text" msgid="2835519769868187223">"Uusi ilmoitus"</string>
<string name="notification_channel_virtual_keyboard" msgid="6465975799223304567">"Virtuaalinen näppäimistö"</string>
<string name="notification_channel_physical_keyboard" msgid="5417306456125988096">"Fyysinen näppäimistö"</string>
- <string name="notification_channel_security" msgid="8516754650348238057">"Tietosuoja"</string>
+ <string name="notification_channel_security" msgid="8516754650348238057">"Turvallisuus"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"Autotila"</string>
<string name="notification_channel_account" msgid="6436294521740148173">"Tilin tila"</string>
<string name="notification_channel_developer" msgid="1691059964407549150">"Kehittäjien viestit"</string>
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Sormenjälkikuvake"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"hallinnoida kasvojentunnistusavauksen laitteistoa"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Sallii sovelluksen käyttää menetelmiä, joilla voidaan lisätä tai poistaa kasvomalleja."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"käyttää kasvojentunnistusavauksen laitteistoa"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Sallii sovelluksen käyttää kasvojentunnistusavauksen laitteistoa todennukseen"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Kasvojentunnistusavaus"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Lisää kasvot uudelleen"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Lisää kasvosi uudelleen tunnistamisen parantamiseksi"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Ota kasvojentunnistusavaus käyttöön"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Avaa puhelimesi lukitus katsomalla laitetta"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Ota käyttöön lisää tapoja avata lukitus"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Napauta lisätäksesi sormenjälki"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Kasvoja ei voi vahvistaa. Laitteisto ei käytettäv."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Yritä käyttää kasvojentunnistusavausta uudelleen."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Uutta kasvodataa ei voi tallentaa. Poista ensin vanhaa."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Kasvotoiminto peruutettu"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Käyttäjä peruutti kasvojentunnistusavauksen."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Liian monta yritystä. Yritä myöhemmin uudelleen."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Liian monta yritystä. Kasvojentunnistusavaus poistettu käytöstä."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Kasvoja ei voi vahvistaa. Yritä uudelleen."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Et ole määrittänyt kasvojentunnistusavausta."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Tämä laite ei tue kasvojentunnistusavausta."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Tunnistin poistettu väliaikaisesti käytöstä."</string>
<string name="face_name_template" msgid="3877037340223318119">"Kasvot <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Käytä kasvojentunnistusavausta"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Käytä kasvojentunnistusavausta tai näytön lukitusta"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Jatka kasvojesi avulla"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Jatka kasvojentunnistuksen tai näytön lukituksen avulla"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Laajenna lukituksen poiston aluetta."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Lukituksen poisto liu\'uttamalla."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Lukituksen poisto salasanalla."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Kasvojentunnistusavaus"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Lukituksen poisto PIN-koodilla."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM-kortin PIN-koodin lukituksen avaus"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM-kortin PUK-koodin lukituksen avaus"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Laita pois päältä"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Lue lisää"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Parannetut ilmoitukset korvasivat Androidin mukautuvat ilmoitukset Android 12:ssa. Tämä ominaisuus näyttää toiminto- ja vastausehdotuksia ja järjestää ilmoituksesi.\n\nParannetuilla ilmoituksilla on pääsy kaikkeen ilmoitussisältöön, myös henkilökohtaisiin tietoihin (esim. kontaktien nimet ja viestit). Ominaisuus voi myös ohittaa ilmoituksia tai vastata niihin, esim. vastata puheluihin ja ohjata Älä häiritse ‑tilaa."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ohjelmatilan tietoilmoitus"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Akku saattaa loppua ennen normaalia latausaikaa"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Virransäästö otettu käyttöön akunkeston pidentämiseksi"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index aea7a62..bcdf829 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icône d\'empreinte digitale"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"gérer le matériel de déverrouillage par reconnaissance faciale"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Permet à l\'appli d\'employer des méthodes d\'aj. et de suppr. de modèles de reconn. visage."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"utiliser le matériel de déverrouillage par reconnaissance faciale"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Permet à l\'appli d\'utiliser du matériel de déverr. par reconn. faciale pour l\'authentific."</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Déverrouillage par reconnaissance faciale"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Inscrivez votre visage à nouveau"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Pour améliorer la reconnaissance, veuillez enregistrer à nouveau votre visage"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Configurer le déverrouillage par reconnaissance faciale"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Déverrouillez votre téléphone en le regardant"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configurer d\'autres méthodes de déverrouillage"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Touchez pour ajouter une empreinte digitale"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Imposs. de vérif. visage. Matériel non accessible."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Réessayez le déverr. par reconnaissance faciale."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Impossible de stocker de nouveaux visages. Supprimez-en un."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Opération de reconnaissance du visage annulée."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Déverr. par reconn. faciale annulé par l\'utilisateur."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Trop de tentatives. Veuillez réessayer plus tard."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Trop de tentatives. Le déverr. par reconnaissance faciale est désactivé."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Impossible de vérifier le visage. Réessayez."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Vous n\'avez pas config. le déverr. par reconn. faciale."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Cet appar. ne prend pas en charge le déverr. par reconn. faciale."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Le capteur a été désactivé temporairement."</string>
<string name="face_name_template" msgid="3877037340223318119">"Visage <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Utiliser le déverrouillage par reconnaissance faciale"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Utiliser la reconnaissance faciale ou le verrouillage de l\'écran"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Utilisez votre visage pour continuer"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilisez votre visage ou le verrouillage de l\'écran pour continuer"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Développer la zone de déverrouillage"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Déverrouillage en faisant glisser votre doigt sur l\'écran"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Déverrouillage par schéma"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Déverrouillage par reconnaissance faciale"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Déverrouillage par NIP"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Déverrouillage du NIP de la carte SIM."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Déverrouillage du code PUK de la carte SIM."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Désactiver"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"En savoir plus"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Les notifications améliorées ont remplacé les notifications adaptatives Android sous Android 12. Cette fonctionnalité vous présente des suggestions d\'actions et de réponse, et organise vos notifications.\n\nLes notifications améliorées peuvent accéder au contenu de toutes les notifications, y compris les renseignements personnels comme le nom des contacts et les messages. Cette fonctionnalité peut aussi fermer des notifications ou interagir avec elles, comme répondre aux appels téléphoniques et gérer le mode Ne pas déranger."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notification d\'information du mode Routine"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"La pile pourrait s\'épuiser avant la charge habituelle"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Le mode Économiseur de pile est activé afin de prolonger l\'autonomie"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 9864ecc..374e144 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icône d\'empreinte digitale"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"gérer le matériel de déverrouillage par authentification faciale"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Autorise l\'appli à invoquer des méthodes pour ajouter et supprimer des modèles de visages."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"utiliser le matériel de déverrouillage par authentification faciale"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Autorise l\'appli à utiliser le matériel de déverrouillage par authentification faciale"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Déverrouillage par authentification faciale"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Enregistrer à nouveau votre visage"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Pour améliorer la reconnaissance, veuillez enregistrer à nouveau votre visage"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Configurer le déverrouillage par authentification faciale"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Déverrouillez votre téléphone en le regardant"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configurer d\'autres méthodes de déverrouillage"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Appuyez pour ajouter une empreinte digitale"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Imposs. valider visage. Matériel non disponible."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Réessayez d\'activer le déverrouillage."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Impossible stocker nouv. visages. Veuillez en supprimer un."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Opération de reconnaissance faciale annulée."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Déverrouillage par authentification faciale annulé par l\'utilisateur"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Trop de tentatives. Réessayez plus tard."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Trop de tentatives. Déverrouillage par authentification faciale désactivé."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Impossible de valider votre visage. Réessayez."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Déverrouillage par authentification faciale non configuré"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Déverrouillage par authentification faciale non compatible"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Capteur temporairement désactivé."</string>
<string name="face_name_template" msgid="3877037340223318119">"Visage <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Utiliser déverrouillage facial"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Utiliser déverrouillage par authent. faciale ou verrouillage écran"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Utilisez la reconnaissance faciale pour continuer"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilisez la reconnaissance faciale ou le verrouillage de l\'écran pour continuer"</string>
@@ -887,7 +893,7 @@
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Veuillez réessayer."</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Veuillez réessayer."</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"Déverr. pour autres fonctionnalités et données"</string>
- <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Nombre maximal de tentatives de déverrouillage par authentification faciale atteint"</string>
+ <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Nombre maximal de tentatives de déverrouillage par reconnaissance faciale atteint"</string>
<string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"Pas de carte SIM"</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"Aucune carte SIM n\'est insérée dans la tablette."</string>
<string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"Aucune carte SIM n\'est installée dans votre appareil Android TV."</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Développer la zone de déverrouillage"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Déverrouillage en faisant glisser votre doigt sur l\'écran"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Déverrouillage par schéma"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Déverrouillage par authentification faciale"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Déverrouillage par code PIN"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Déverrouillage de la carte SIM à l\'aide d\'un code."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Déverrouillage de la carte SIM à l\'aide d\'une clé PUK."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Désactiver"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"En savoir plus"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Les notifications améliorées remplacent les notifications intelligentes dans Android 12. Cette fonctionnalité affiche les actions et réponses suggérées, et organise vos notifications.\n\nElle a accès au contenu des notifications, y compris aux informations personnelles comme le nom des contacts et les messages. Elle peut aussi fermer les notifications ou effectuer des actions comme répondre à un appel téléphonique et contrôler Ne pas déranger."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notification d\'information du mode Routine"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Vous risquez d\'être à court de batterie plus tôt que prévu"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Économiseur de batterie activé pour prolonger l\'autonomie"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 163437f11..e2d65ed 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icona de impresión dixital"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"xestionar o hardware de desbloqueo facial"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Permite que a aplicación invoque métodos para engadir e eliminar modelos faciais de uso."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"utilizar o hardware de desbloqueo facial"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Permite que a aplicación utilice o hardware de desbloqueo facial para a autenticación"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Desbloqueo facial"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Volve inscribir a túa cara"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Para mellorar o recoñecemento, inscribe de novo a túa cara"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Configura o desbloqueo facial"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Mira o teléfono para desbloquealo"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configura máis maneiras de desbloquear o dispositivo"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Toca para engadir unha impresión dixital"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Sen verificar a cara. Hardware non dispoñible."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Tenta utilizar o desbloqueo facial de novo."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Para gardar novos datos faciais, elimina os antigos."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Cancelouse a operación relacionada coa cara"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"O usuario cancelou o desbloqueo facial."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Demasiados intentos. Téntao de novo máis tarde."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Demasiados intentos. Desactivouse o desbloqueo facial."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Non se puido verificar a cara. Téntao de novo."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Non configuraches o desbloqueo facial."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Este dispositivo non admite o desbloqueo facial."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Desactivouse o sensor temporalmente."</string>
<string name="face_name_template" msgid="3877037340223318119">"Cara <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Utilizar desbloqueo facial"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Utilizar desbloqueo facial ou credencial do dispositivo"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Usa a cara para continuar"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Para continuar, utiliza o desbloqueo facial ou a credencial do dispositivo"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Ampliar zona de desbloqueo."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Desbloqueo pasando o dedo."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Desbloqueo mediante padrón"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Desbloqueo facial"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Desbloqueo mediante PIN"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Desbloqueo da SIM co PIN."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Desbloqueo da SIM co PUK."</string>
@@ -1862,9 +1869,9 @@
<string name="managed_profile_label_badge" msgid="6762559569999499495">"<xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
<string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2.º <xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
<string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3.º <xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
- <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Solicitar PIN para deixar de fixar"</string>
- <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Solicitar un padrón de desbloqueo antes de deixar de fixar a pantalla"</string>
- <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Solicitar un contrasinal para deixar de fixar a pantalla"</string>
+ <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Pedir PIN antes de soltar a fixación"</string>
+ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir padrón de desbloqueo antes de soltar a fixación"</string>
+ <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pedir contrasinal antes de soltar a fixación"</string>
<string name="package_installed_device_owner" msgid="7035926868974878525">"Instalado polo teu administrador"</string>
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado polo teu administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado polo teu administrador"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Aceptar"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desactivar"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Máis información"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"En Android 12, as notificacións melloradas substitúen as notificacións intelixentes. Esta función ofréceche suxestións de accións e respostas, ademais de organizar as notificacións.\n\nEste servizo pode acceder ao contido das notificacións, mesmo á información persoal, como os nomes dos contactos e as mensaxes. Ademais, esta función pode ignorar ou responder as notificacións (por exemplo, coller chamadas telefónicas e controlar o modo Non molestar)."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificación da información do modo de rutina"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"A batería pode esgotarse antes do habitual"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Para ampliar a duración da batería activouse a función Aforro de batería"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index ff431a5..68ab0c5 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ફિંગરપ્રિન્ટ આયકન"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"ફેસ અનલૉકના હાર્ડવેરને મેનેજ કરો"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"ઍપને ઉપયોગ માટે ચહેરાના નમૂના ઉમેરવા અને ડિલીટ કરવાની પદ્ધતિને રદ કરવાની મંજૂરી આપે છે."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ફેસ અનલૉક હાર્ડવેરનો ઉપયોગ કરો"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"ઍપને પ્રમાણીકરણ માટે ફેસ અનલૉકના હાર્ડવેરનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ફેસ અનલૉક"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"તમારા ચહેરાની ફરી નોંધણી કરાવો"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"ઓળખવાની પ્રક્રિયાને બહેતર બનાવવા માટે કૃપા કરીને તમારા ચહેરાની ફરી નોંધણી કરાવો"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"ફેસ અનલૉક સુવિધાનું સેટઅપ કરો"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"તમારા ફોનની તરફ જોઈને તેને અનલૉક કરો"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"અનલૉક કરવાની બીજી રીતોનું સેટઅપ કરો"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"ફિંગરપ્રિન્ટ ઉમેરવા માટે ટૅપ કરો"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ચહેરો ચકાસી શકાતો નથી. હાર્ડવેર ઉપલબ્ધ નથી."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"ફેસ અનલૉકને ફરી અજમાવો."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"ચહેરાનો નવો ડેટા સ્ટોર કરી શકતાં નથી. પહેલા જૂનો ડિલીટ કરો."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"ચહેરા સંબંધિત કાર્યવાહી રદ કરવામાં આવી છે."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"વપરાશકર્તાએ ફેસ અનલૉક રદ કર્યું."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"ઘણા બધા પ્રયત્નો. થોડા સમય પછી ફરી પ્રયાસ કરો."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"ઘણા બધા પ્રયાસો. ફેસ અનલૉક બંધ કર્યું."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"ચહેરો ચકાસી શકાતો નથી. ફરી પ્રયાસ કરો."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"તમે ફેસ અનલૉકનું સેટઅપ કર્યું નથી."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"આ ડિવાઇસ પર ફેસ અનલૉક કરવાની સુવિધા નથી."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"સેન્સર હંગામી રૂપે બંધ કર્યું છે."</string>
<string name="face_name_template" msgid="3877037340223318119">"ચહેરાનું <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"ફેસ અનલૉકનો ઉપયોગ કરો"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ફેસ લૉક અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"આગળ વધવા માટે તમારા ચહેરાનો ઉપયોગ કરો"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ચાલુ રાખવા માટે તમારા ફેસ લૉક અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"અનલૉક ક્ષેત્ર વિસ્તૃત કરો."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"સ્લાઇડ અનલૉક કરો."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"પૅટર્ન અનલૉક."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"ફેસ અનલૉક"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"પિન અનલૉક."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"પિનથી સિમને અનલૉક કરો."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Pukથી સિમને અનલૉક કરો."</string>
@@ -1869,10 +1876,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"તમારા વ્યવસ્થાપક દ્વારા અપડેટ કરવામાં આવેલ છે"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"તમારા વ્યવસ્થાપક દ્વારા કાઢી નાખવામાં આવેલ છે"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ઓકે"</string>
- <!-- no translation found for battery_saver_description_with_learn_more (4877297130366222145) -->
- <skip />
- <!-- no translation found for battery_saver_description (8518809702138617167) -->
- <skip />
+ <string name="battery_saver_description_with_learn_more" msgid="4877297130366222145">"બૅટરી સેવર ઘેરી થીમની સુવિધા ચાલુ કરે છે અને બૅકગ્રાઉન્ડ પ્રવૃત્તિ, અમુક વિઝ્યુઅલ ઇફેક્ટ, અમુક સુવિધાઓ અને કેટલાક નેટવર્ક કનેક્શન મર્યાદિત કે બંધ કરે છે.\n\n"<annotation id="url">"વધુ જાણો"</annotation></string>
+ <string name="battery_saver_description" msgid="8518809702138617167">"બૅટરી સેવર ઘેરી થીમની સુવિધા ચાલુ કરે છે અને બૅકગ્રાઉન્ડ પ્રવૃત્તિ, અમુક વિઝ્યુઅલ ઇફેક્ટ, અમુક સુવિધાઓ અને કેટલાક નેટવર્ક કનેક્શન મર્યાદિત કે બંધ કરે છે."</string>
<string name="data_saver_description" msgid="4995164271550590517">"ડેટા વપરાશને ઘટાડવામાં સહાય માટે, ડેટા સેવર કેટલીક ઍપને બૅકગ્રાઉન્ડમાં ડેટા મોકલવા અથવા પ્રાપ્ત કરવાથી અટકાવે છે. તમે હાલમાં ઉપયોગ કરી રહ્યાં છો તે ઍપ ડેટાને ઍક્સેસ કરી શકે છે, પરંતુ તે આ ક્યારેક જ કરી શકે છે. આનો અર્થ એ હોઈ શકે છે, ઉદાહરણ તરીકે, છબીઓ ત્યાં સુધી પ્રદર્શિત થશે નહીં જ્યાં સુધી તમે તેને ટૅપ નહીં કરો."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ડેટા સેવર ચાલુ કરીએ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ચાલુ કરો"</string>
@@ -1975,10 +1980,8 @@
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> હમણાં ઉપલબ્ધ નથી. આને <xliff:g id="APP_NAME_1">%2$s</xliff:g> દ્વારા મેનેજ કરવામાં આવે છે."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"વધુ જાણો"</string>
<string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ઍપ ફરી શરૂ કરો"</string>
- <!-- no translation found for work_mode_off_title (961171256005852058) -->
- <skip />
- <!-- no translation found for work_mode_off_message (7319580997683623309) -->
- <skip />
+ <string name="work_mode_off_title" msgid="961171256005852058">"શું ઑફિસ માટેની ઍપ ચાલુ કરીએ?"</string>
+ <string name="work_mode_off_message" msgid="7319580997683623309">"તમારી ઑફિસ માટેની ઍપ અને નોટિફિકેશનનો ઍક્સેસ મેળવો"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ચાલુ કરો"</string>
<string name="app_blocked_title" msgid="7353262160455028160">"ઍપ ઉપલબ્ધ નથી"</string>
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> હાલમાં ઉપલબ્ધ નથી."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 05d0845..e7a2218 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"फ़िंगरप्रिंट आइकॉन"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"\'मालिक का चेहरा पहचानकर अनलॉक\' वाला हार्डवेयर प्रबंधित करें"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"ऐप्लिकेशन को चेहरे के टेम्पलेट इस्तेमाल के तरीके जोड़ने और मिटाने की मंज़ूरी मिलती है."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"फ़ेस अनलॉक हार्डवेयर इस्तेमाल करें"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"फ़ेस अनलॉक हार्डवेयर के इस्तेमाल की मंज़ूरी देता है"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"फ़ेस अनलॉक"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"अपना चेहरा फिर से दर्ज करें"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"कृपया अपना चेहरा फिर से दर्ज करें ताकि आपको बेहतर तरीके से पहचाना जा सके"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"फ़ेस अनलॉक की सुविधा सेट अप करें"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"अपने फ़ोन की तरफ़ देखकर उसे अनलॉक करें"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"फ़ोन को अनलॉक करने के दूसरे तरीके सेट अप करें"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"फ़िंगरप्रिंट जोड़ने के लिए टैप करें"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"चेहरा नहीं पहचान पा रहे. हार्डवेयर उपलब्ध नहीं है."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"फ़ेस अनलॉक की सुविधा फिर से आज़माएं."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"चेहरे का नया डेटा सेव नहीं हो सकता. कोई पुराना डेटा मिटाएं."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"चेहरा पहचानने की कार्रवाई रद्द की गई."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"उपयोगकर्ता ने \'मालिक का चेहरा पहचानकर अनलॉक\' रद्द की."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"कई बार कोशिश की गई. बाद में कोशिश करें."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"कई बार कोशिश की जा चुकी है. \'मालिक का चेहरा पहचानकर अनलॉक\' बंद है."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"चेहरा नहीं पहचान पा रहे. फिर से कोशिश करें."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"आपने \'मालिक का चेहरा पहचानकर अनलॉक\' सेट नहीं की है."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"इस डिवाइस पर फ़ेस अनलॉक की सुविधा काम नहीं करती है."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"सेंसर कुछ समय के लिए बंद कर दिया गया है."</string>
<string name="face_name_template" msgid="3877037340223318119">"चेहरा <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"\'फ़ेस अनलॉक\' इस्तेमाल करें"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"\'फ़ेस अनलॉक\' या स्क्रीन लॉक का क्रेडेंशियल इस्तेमाल करें"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"जारी रखने के लिए, अपने चेहरे की मदद से पुष्टि करें"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"जारी रखने के लिए, अपना चेहरा दिखाकर या स्क्रीन लॉक क्रेडेंशियल डालकर पुष्टि करें"</string>
@@ -731,13 +737,13 @@
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"स्क्रीन को अनलॉक करते समय ध्यान रखें कि कितनी बार गलत पासवर्ड डाला गया है. अगर बहुत ज़्यादा बार गलत पासवर्ड डाला गया है, तो अपने Android TV डिवाइस को तुरंत लॉक करें या इस उपयोगकर्ता का सभी डेटा मिटाएं."</string>
<string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"स्क्रीनका लॉक खोलते समय गलत तरीके से लिखे गए पासवर्ड पर नज़र रखें, और अगर बार-बार गलत पासवर्ड लिखा जाता है तो फ़ोन को लॉक करें या इस उपयोगकर्ता का सभी डेटा मिटा दें."</string>
<string name="policylab_resetPassword" msgid="214556238645096520">"स्क्रीन लॉक बदलना"</string>
- <string name="policydesc_resetPassword" msgid="4626419138439341851">"स्क्रीन लॉक बदलना."</string>
+ <string name="policydesc_resetPassword" msgid="4626419138439341851">"इससे स्क्रीन लॉक बदला जाता है."</string>
<string name="policylab_forceLock" msgid="7360335502968476434">"स्क्रीन लॉक करना"</string>
- <string name="policydesc_forceLock" msgid="1008844760853899693">"इससे नियंत्रित होगा कि स्क्रीन कैसे और कब लॉक हो."</string>
+ <string name="policydesc_forceLock" msgid="1008844760853899693">"इससे यह कंट्रोल होता है कि स्क्रीन कैसे और कब लॉक हो."</string>
<string name="policylab_wipeData" msgid="1359485247727537311">"सारा डेटा मिटाना"</string>
<string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"फ़ैक्टरी डेटा रीसेट करके चेतावनी दिए बिना फ़ोन का डेटा मिटाना."</string>
<string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"फ़ैक्ट्री डेटा रीसेट करके अपने Android TV डिवाइस का डेटा बिना चेतावनी दिए मिटाएं."</string>
- <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"फ़ैक्टरी डेटा रीसेट करके चेतावनी दिए बिना फ़ोन का डेटा मिटाना."</string>
+ <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"इससे फ़ैक्टरी डेटा रीसेट करके, चेतावनी दिए बिना फ़ोन का डेटा मिट जाता है."</string>
<string name="policylab_wipeData_secondaryUser" msgid="413813645323433166">"उपयोगकर्ता डेटा मिटाएं"</string>
<string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"इस टैबलेट पर मौजूद इस उपयोगकर्ता का डेटा बिना चेतावनी के मिटा दें."</string>
<string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"बिना चेतावनी दिए, इस Android TV डिवाइस से उपयोगकर्ता का डेटा मिटाएं."</string>
@@ -751,7 +757,7 @@
<string name="policylab_disableCamera" msgid="5749486347810162018">"कैमरों को अक्षम करें"</string>
<string name="policydesc_disableCamera" msgid="3204405908799676104">"सभी डिवाइस कैमरों का उपयोग रोकें."</string>
<string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"स्क्रीन लॉक की कुछ सुविधाएं बंद करना"</string>
- <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"यह कुछ स्क्रीन लाॅक सुविधाओं का इस्तेमाल रोकती है."</string>
+ <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"इससे कुछ स्क्रीन लॉक सुविधाओं का इस्तेमाल रोका जाता है."</string>
<string-array name="phoneTypes">
<item msgid="8996339953292723951">"घर"</item>
<item msgid="7740243458912727194">"मोबाइल"</item>
@@ -903,7 +909,7 @@
<string name="lockscreen_transport_stop_description" msgid="1449552232598355348">"बंद करें"</string>
<string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"रिवाइंड करें"</string>
<string name="lockscreen_transport_ffw_description" msgid="4763794746640196772">"फ़ास्ट फ़ॉरवर्ड"</string>
- <string name="emergency_calls_only" msgid="3057351206678279851">"केवल आपातकालीन कॉल"</string>
+ <string name="emergency_calls_only" msgid="3057351206678279851">"सिर्फ़ आपातकालीन कॉल"</string>
<string name="lockscreen_network_locked_message" msgid="2814046965899249635">"नेटवर्क लॉक किया गया"</string>
<string name="lockscreen_sim_puk_locked_message" msgid="6618356415831082174">"सिम कार्ड PUK-लॉक किया हुआ है."</string>
<string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"कृपया उपयोग के लिए गाइड देखें या ग्राहक सहायता से संपर्क करें."</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"अनलॉक क्षेत्र का विस्तार करें."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"स्लाइड अनलॉक."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"आकार अनलॉक."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"मालिक का चेहरा पहचानकर अनलॉक करें."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"पिन अनलॉक."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"पिन के ज़रिए सिम अनलॉक करें."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"पीयूके के ज़रिए सिम अनलॉक करें."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"चालू करें"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"बंद करें"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ज़्यादा जानें"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12 में, ज़रूरत के हिसाब से सूचनाएं पाने की सुविधा की जगह अब \'बेहतर सूचनाएं\' सुविधा काम करेगी. यह सुविधा आपको कार्रवाइयों और जवाबों के सुझाव दिखाती है. साथ ही, आपके डिवाइस पर मिलने वाली सूचनाओं को व्यवस्थित करती है.\n\n\'बेहतर सूचनाएं\' सुविधा, डिवाइस पर मिलने वाली सभी सूचनाओं का कॉन्टेंट ऐक्सेस कर सकती है. इसमें आपकी निजी जानकारी, जैसे कि संपर्कों के नाम और मैसेज शामिल हैं. यह सुविधा, सूचनाओं को रद्द कर सकती है या उनका जवाब भी दे सकती है, जैसे कि फ़ोन कॉल का जवाब देना और \'परेशान न करें\' को कंट्रोल करना."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"रूटीन मोड जानकारी की सूचना"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"बैटरी आम तौर पर जितने समय चलती है, उससे पहले खत्म हो सकती है"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"बैटरी लाइफ़ बढ़ाने के लिए \'बैटरी सेवर\' चालू हो गया है"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index c544dd3..f18080f 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -612,14 +612,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona otiska prsta"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"Upravljajte hardverom za otključavanje licem"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Aplikaciji omogućuje pozivanje načina za dodavanje i brisanje predložaka lica za upotrebu."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"Koristiti hardver za otključavanje licem"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Aplikaciji omogućuje upotrebu hardvera za otključavanje licem radi autentifikacije"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Otključavanje licem"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Ponovo registrirajte svoje lice"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Za poboljšanje prepoznavanja ponovo registrirajte svoje lice"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Postavite otključavanje licem"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Otključajte telefon gledajući u njega"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Postavite više načina otključavanja"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Dodirnite da biste dodali otisak prsta"</string>
@@ -646,18 +644,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Lice nije potvrđeno. Hardver nije dostupan."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Ponovo pokušajte otključavanje licem."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Podaci o novom licu nisu pohranjeni. Izbrišite neko staro."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Otkazana je radnja s licem."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Otključavanje licem otkazao je korisnik."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Previše pokušaja. Onemogućeno otključavanje licem"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Lice nije potvrđeno. Pokušajte ponovo."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Niste postavili otključavanje licem"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Otključavanje licem nije podržano na ovom uređaju."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je privremeno onemogućen."</string>
<string name="face_name_template" msgid="3877037340223318119">"Lice <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Upotreba otključavanja licem"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Upotreba otključavanja licem ili zaključavanja zaslona"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Autentificirajte se licem da biste nastavili"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Za nastavak se identificirajte licem ili vjerodajnicom zaključavanja zaslona"</string>
@@ -960,7 +966,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Proširivanje područja za otključavanje."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Otključavanje klizanjem."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Uzorak za otključavanje."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Otključavanje licem."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Otključavanje PIN-om."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Otključavanje SIM-a PIN-om."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Otključavanje SIM-a PUK-om."</string>
@@ -2128,8 +2135,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"U redu"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Isključi"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saznajte više"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"U Androidu 12 poboljšane obavijesti zamjenjuju prilagodljive obavijesti za Android. Ta značajka prikazuje predložene radnje i odgovore te organizira vaše obavijesti.\n\nPoboljšane obavijesti mogu pristupiti sadržaju obavijesti, uključujući osobne podatke kao što su imena kontakata i poruke. Ta značajka može i odbacivati obavijesti ili poduzimati radnje u skladu s njima, na primjer može odgovarati na telefonske pozive i upravljati značajkom Ne uznemiravaj."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Obavještavanje o informacijama u Rutinskom načinu rada"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterija se može isprazniti prije uobičajenog vremena punjenja"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Štednja baterije aktivirana je kako bi se produljilo trajanje baterije"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index e24b1cc..17942d0 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ujjlenyomat ikon"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"arcalapú feloldásra szolgáló hardver kezelése"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Engedélyezi, hogy az alkalmazás arcsablon-hozzáadási és -törlési metódusokat hívjon."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"arcalapú feloldásra szolgáló hardver használata"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Engedélyezi, hogy az alkalmazás hitelesítésre használja az arcalapú feloldás hardverét"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Arcalapú feloldás"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Rögzítsen újra képet az arcáról"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"A felismerés javítása érdekében rögzítsen újra az arcáról készített képet"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Az arcalapú feloldás beállítása"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Feloldhatja a zárolást úgy, hogy ránéz a telefonra"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"További feloldási módszerek beállítása"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Koppintson ide ujjlenyomat hozzáadásához"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Sikertelen arcellenőrzés. A hardver nem érhető el."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Próbálja újra az arcalapú feloldást."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Nem tárolhatók újabb arcadatok. Törölje valamelyik arcot."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Az arccal kapcsolatos művelet törölve."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Az arcalapú feloldást megszakította a felhasználó."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Túl sok próbálkozás. Próbálja újra később."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Túl sok próbálkozás. Az arcalapú feloldás letiltva."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Nem sikerült ellenőrizni az arcát. Próbálja újra."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Nem állította be az arcalapú feloldást."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Az eszköz nem támogatja az arcalapú feloldást"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Az érzékelő átmenetileg le van tiltva."</string>
<string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> arc"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Arcalapú feloldás használata"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"A folytatás arcalapú feloldással vagy képernyőzárral lehetséges"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"A folytatáshoz használja az arcalapú feloldást"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"A folytatás arcalapú feloldással vagy a képernyőzár feloldásával lehetséges"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"A feloldási terület kiterjesztése."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Feloldás csúsztatással"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Feloldás mintával"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Arcalapú feloldás"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Feloldás PIN kóddal"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM-kártya PIN-kódjának feloldása."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM-kártya PUK-kódjának feloldása."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Kikapcsolás"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"További információ"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"A bővített értesítések felváltják az androidos alkalmazkodó értesítéseket az Android 12-es verziójában. Ez a funkció a javasolt műveleteket és válaszokat mutatja, és rendszerezi az értesítéseket.\n\nA bővített értesítések minden értesítéstartalmat olvashatnak (így a személyes adatokat, mint például a névjegyek nevét és az üzeneteket is). Ez a funkció emellett elvetheti az értesítéseket, valamint reagálhat rájuk, például felveheti a telefonhívásokat, és vezérelheti a Ne zavarjanak módot."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Információs értesítés a rutinmódról"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Előfordulhat, hogy az akkumulátor lemerül a szokásos töltési időszak előtt"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Akkumulátorkímélő mód aktiválva az akkumulátor üzemidejének növelése érdekében"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index c63965b..8c2f27d 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Մատնահետքի պատկերակ"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"կառավարել դեմքով ապակողպման համար սարքը"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Հավելվածին թույլ է տալիս ավելացնել և հեռացնել դեմքի նմուշներ:"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"օգտագործել դեմքով ապակողպման համար սարքը"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Թույլ է տալիս հավելվածին օգտագործել դեմքով ապակողպման համար նախատեսված սարքը"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Դեմքով ապակողպում"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Նորից գրանցեք ձեր դեմքը"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Ճանաչումը լավացնելու համար նորից գրանցեք ձեր դեմքը"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Կարգավորեք դեմքով ապակողպումը"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Ապակողպելու համար պարզապես նայեք հեռախոսին"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Կարգավորեք ապակողպելու այլ եղանակներ"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Հպեք՝ մատնահետք ավելացնելու համար"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Չհաջողվեց հաստատել դեմքը։ Սարքն անհասանելի է:"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Նորից փորձեք դեմքով ապակողպումը։"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Չհաջողվեց պահել նոր դեմքը։ Ջնջեք հին տարբերակը։"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Դեմքի ճանաչումը չեղարկվել է։"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Դեմքով ապակողմումը չեղարկվել է օգտատիրոջ կողմից:"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Չափից շատ փորձեր եք կատարել: Փորձեք ավելի ուշ:"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Չափազանց շատ փորձեր են արվել։ Դեմքով ապակողպումն անջատված է:"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Չհաջողվեց հաստատել դեմքը։ Նորից փորձեք։"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Դուք չեք կարգավորել դեմքով ապակողպումը:"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Դեմքով ապակողպումն այս սարքում չի աջակցվում"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Տվիչը ժամանակավորապես անջատված է:"</string>
<string name="face_name_template" msgid="3877037340223318119">"Դեմք <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Օգտագործել դեմքով ապակողպում"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Օգտագործել դեմքով ապակողպում կամ էկրանի կողպում"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Շարունակելու համար օգտագործեք դեմքի նույնականացումը"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Շարունակելու համար օգտագործեք ձեր դեմքը կամ էկրանի կողպումը"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Ընդլայնել ապակողպման տարածությունը:"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Էջի ապակողպում:"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Սխեմայով ապակողպում:"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Դեմքով ապակողպում:"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin-ն ապակողպված է:"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM քարտի ապակողպում PIN կոդի միջոցով:"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM քարտի ապակողպում PUK կոդի միջոցով:"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Եղավ"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Անջատել"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Իմանալ ավելին"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12-ում ընդլայնված ծանուցումները փոխարինում են Android-ի հարմարվող ծանուցումներին։ Այս գործառույթը դասավորում է ձեր բոլոր ծանուցումները և առաջարկում գործողություններ և պատասխաններ։\n\nԸնդլայնված ծանուցումներին հասանելի է բոլոր ծանուցումների պարունակությունը, ներառյալ անձնական տվյալները, օրինակ՝ կոնտակտների անուններն ու հաղորդագրությունները։ Այս գործառույթը կարող է նաև փակել ծանուցումները կամ սեղմել դրանցում առկա կոճակները, այդ թվում՝ պատասխանել հեռախոսազանգերի և կառավարել «Չանհանգստացնել» ռեժիմը։"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ծանուցում լիցքավորման մասին"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Մարտկոցը կարող է սովորականից շուտ սպառվել"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Մարտկոցի կյանքը երկարացնելու համար ակտիվացվել է մարտկոցի տնտեսման ռեժիմը"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index bce6a81..16644a2 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon sidik jari"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"kelola hardware face unlock"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Mengizinkan apl memicu metode untuk menambah & menghapus template wajah untuk digunakan."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"gunakan hardware face unlock"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Mengizinkan aplikasi untuk menggunakan hardware face unlock untuk autentikasi"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face unlock"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Daftarkan kembali wajah Anda"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Untuk menyempurnakan pengenalan wajah, daftarkan kembali wajah Anda"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Siapkan face unlock"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Buka kunci ponsel dengan melihat ke ponsel"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Siapkan lebih banyak cara untuk membuka kunci"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Ketuk untuk menambahkan sidik jari"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Tidak dapat memverifikasi wajah. Hardware tidak tersedia."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Coba face unlock lagi."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Tidak dapat menyimpan data wajah. Hapus dahulu data lama."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Pemrosesan wajah dibatalkan."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Face unlock dibatalkan oleh pengguna."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Terlalu banyak percobaan. Coba lagi nanti."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Terlalu banyak gagal. Face unlock dinonaktifkan."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Tidak dapat memverifikasi wajah. Coba lagi."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Anda belum menyiapkan face unlock."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Face unlock tidak didukung di perangkat ini."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor dinonaktifkan untuk sementara."</string>
<string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> wajah"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Gunakan face unlock"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Gunakan face lock atau kunci layar"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Gunakan wajah untuk melanjutkan"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gunakan face lock atau kunci layar untuk melanjutkan"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Luaskan area buka kunci."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Buka kunci dengan menggeser."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Buka kunci dengan pola."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Buka kunci dengan face unlock."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Buka kunci dengan PIN."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"PIN SIM terbuka."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"PUK SIM terbuka."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Oke"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Nonaktifkan"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Pelajari lebih lanjut"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Notifikasi yang ditingkatkan menggantikan Notifikasi Adaptif Android di Android 12. Fitur ini menunjukkan tindakan dan balasan yang disarankan, serta mengatur notifikasi.\n\nNotifikasi yang ditingkatkan dapat mengakses konten notifikasi, termasuk informasi pribadi seperti nama kontak dan pesan. Fitur ini juga dapat menutup atau merespons notifikasi, seperti menjawab panggilan telepon dan mengontrol fitur Jangan Ganggu."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notifikasi info Mode Rutinitas"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterai mungkin habis sebelum pengisian daya biasanya"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Penghemat Baterai diaktifkan untuk memperpanjang masa pakai baterai"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 851ae73..46544b0 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingrafaratákn"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"stjórna vélbúnaði andlitsopnunar"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Leyfir forritinu að beita aðferðum til að bæta við og eyða andlitssniðmátum til notkunar."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"nota vélbúnað andlitsopnunar"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Leyfir forritinu að nota vélbúnað andlitsopnunar til auðkenningar"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Andlitsopnun"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Skráðu andlitið þitt aftur"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Skráðu andlitið þitt til að bæta kennsl"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Setja upp andlitsopnun"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Taktu símann úr lás með því að horfa á hann"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Settu upp fleiri leiðir til að taka úr lás"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Ýttu til að bæta við fingrafari"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Andlit ekki staðfest. Vélbúnaður er ekki tiltækur."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Prófaðu andlitsopnun aftur."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Ekki er hægt að vista ný andlitsgögn. Eyddu gömlu fyrst."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Hætt við andlitsgreiningu."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Notandi hætti við andlitsopnun."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Of margar tilraunir. Reyndu aftur síðar."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Of margar tilraunir. Slökkt á andlitsopnun."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Ekki tókst að staðfesta andlit. Reyndu aftur."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Þú hefur ekki sett upp andlitsopnun."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Andlitsopnun er ekki studd í þessu tæki."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Slökkt tímabundið á skynjara."</string>
<string name="face_name_template" msgid="3877037340223318119">"Andlit <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Nota andlitsopnun"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Nota andlit eða skjálás"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Notaðu andlitið þitt til að halda áfram"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Notaðu andlitið eða skjálás til að halda áfram"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Stækka opnunarsvæði."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Opnun með stroku."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Opnun með mynstri."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Andlitsopnun."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Opnun með PIN-númeri."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Taka PIN-númer SIM-korts úr lás."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Taka PUK-númer SIM-korts úr lás."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Í lagi"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Slökkva"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Nánar"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Auknar tilkynningar hafa leyst breytilegar tilkynningar í Android af hólmi í Android 12. Eiginleikinn birtir tillögur að aðgerðum og svörum og flokkar tilkynningar.\n\nAuknar tilkynningar hafa aðgang að efni tilkynninga, þ. á m persónuupplýsingum á borð við nöfn tengiliða og skilaboð. Eiginleikinn getur einnig hunsað eða svarað tilkynningum, til dæmis svarað símtölum og stjórnað „Ónáðið ekki“."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Upplýsingatilkynning aðgerðastillingar"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Rafhlaðan kann að tæmast áður en hún kemst í hleðslu"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Kveikt á rafhlöðusparnaði til að lengja endingu rafhlöðunnar"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 5f7a383..4aa67a6 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icona dell\'impronta"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"gestione dell\'hardware per lo sblocco con il volto"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Consente all\'app di richiamare i metodi per aggiungere e rimuovere i modelli di volti."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"utilizzo dell\'hardware per lo sblocco con il volto"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Consente all\'app di usare hardware per l\'autenticazione mediante lo sblocco con il volto"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Sblocco con il volto"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Registra di nuovo il volto"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Per migliorare il riconoscimento, registra di nuovo il tuo volto"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Configura lo sblocco con il volto"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Sblocca il telefono guardandolo"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configura altri modi per sbloccare"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tocca per aggiungere un\'impronta"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Imposs. verificare volto. Hardware non disponibile."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Riprova lo sblocco con il volto."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Imposs. salvare dati nuovi volti. Elimina un volto vecchio."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Operazione associata al volto annullata."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Sblocco con il volto annullato dall\'utente."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Troppi tentativi. Riprova più tardi."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Troppi tentativi. Lo sblocco con il volto è disattivato."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Impossibile verificare il volto. Riprova."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Non hai configurato lo sblocco con il volto."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Sblocco con il volto non supportato su questo dispositivo."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensore temporaneamente disattivato."</string>
<string name="face_name_template" msgid="3877037340223318119">"Volto <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Usa lo sblocco con il volto"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Usa lo sblocco con il volto o il blocco schermo"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Usa il tuo volto per continuare"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Per continuare devi usare il tuo volto o il tuo blocco schermo"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Espandi area di sblocco."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Sblocco con scorrimento."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Sblocco con sequenza."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Sblocco con il volto."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Sblocco con PIN."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Sblocco tramite PIN della SIM."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Sblocco tramite PUK della SIM."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Disattiva"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Scopri di più"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Le notifiche adattive Android sono state sostituite dalle notifiche avanzate in Android 12. Questa funzionalità mostra risposte e azioni suggerite e organizza le tue notifiche.\n\nLe notifiche avanzate possono accedere ai contenuti di una notifica, incluse le informazioni personali, come i nomi dei contatti e i messaggi. Questa funzionalità può anche ignorare le notifiche o rispondervi, ad esempio accettando le telefonate, e controllare la modalità Non disturbare."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notifica di informazioni sulla modalità Routine"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"La batteria potrebbe esaurirsi prima della ricarica abituale"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Risparmio energetico attivo per far durare di più la batteria"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 0280b10..ea38642 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -615,14 +615,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"סמל טביעת אצבע"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"ניהול החומרה לפתיחה ע\"י זיהוי הפנים"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"מאפשרת לאפליקציה להפעיל שיטות להוספה ומחיקה של תבניות פנים שבהן ייעשה שימוש."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"שימוש בחומרה לפתיחה ע\"י זיהוי הפנים"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"מאפשרת לאפליקציה להשתמש בחומרה לפתיחה ע\"י זיהוי הפנים"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"פתיחה ע\"י זיהוי הפנים"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"יש לבצע סריקה חוזרת של הפנים שלך"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"לשיפור הזיהוי יש לסרוק מחדש את הפנים שלך"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"הגדרה של פתיחה ע\"י זיהוי הפנים"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"יש להביט בטלפון כדי לבטל את נעילתו"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"אפשר להגדיר דרכים נוספות לביטול נעילה"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"יש להקיש כדי להוסיף טביעת אצבע"</string>
@@ -649,18 +647,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"לא ניתן לאמת את הפנים. החומרה לא זמינה."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"יש לנסות שוב את הפתיחה ע\"י זיהוי הפנים."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"לא ניתן לאחסן נתוני פנים חדשים. תחילה יש למחוק את הנתונים הישנים."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"הפעולה לאימות הפנים בוטלה."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"פתיחה ע\"י זיהוי הפנים בוטל על ידי המשתמש."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"יותר מדי ניסיונות. יש לנסות שוב מאוחר יותר."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"יותר מדי ניסיונות. \'פתיחה ע\"י זיהוי הפנים\' מושבת."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"לא ניתן לאמת את הפנים. יש לנסות שוב."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"לא הגדרת פתיחה ע\"י זיהוי הפנים."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"המכשיר הזה לא תומך בפתיחה ע\"י זיהוי הפנים."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"החיישן מושבת באופן זמני."</string>
<string name="face_name_template" msgid="3877037340223318119">"פנים <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"פתיחה ע\"י זיהוי הפנים"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"שימוש בזיהוי פנים או בנעילת מסך"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"יש להשתמש באימות פנים כדי להמשיך"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"יש להשתמש בזיהוי הפנים או בנעילת המסך כדי להמשיך"</string>
@@ -963,7 +969,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"הרחבה של אזור ביטול הנעילה."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"ביטול נעילה באמצעות הסטה."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"ביטול נעילה על ידי שרטוט קו."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"פתיחה ע\"י זיהוי הפנים."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"ביטול נעילה באמצעות קוד אימות."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"ביטול הנעילה של קוד האימות ל-SIM."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"ביטול נעילה של PUK ל-SIM."</string>
@@ -2161,8 +2168,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"אישור"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"השבתה"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"מידע נוסף"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"ההתראות המשופרות החליפו את ההתראות המותאמות ל-Android ב-Android 12. התכונה הזו מציגה הצעות לפעולות ולתשובות ומארגנת את ההתראות שלך.\n\nההתראות המשופרות יכולות לקבל גישה לתוכן של התראות, כולל מידע אישי כמו שמות אנשי קשר והודעות. התכונה הזו יכולה גם לסגור התראות או להשיב להן, למשל מענה לשיחות טלפון ושליטה בתכונה \'נא לא להפריע\'."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"התראת מידע לגבי מצב שגרתי"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"הסוללה עלולה להתרוקן לפני המועד הרגיל של הטעינה"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"תכונת החיסכון בסוללה הופעלה כדי להאריך את חיי הסוללה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index be9b6e5..085a909 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指紋アイコン"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"顔認証ハードウェアの管理"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"使用する顔テンプレートの追加や削除を行うメソッドの呼び出しをアプリに許可します。"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"顔認証ハードウェアの使用"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"顔認証ハードウェアを認証に使用することをアプリに許可します"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"顔認証"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"顔の再登録"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"認識を改善するには、顔を再登録してください"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"顔認証の設定"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"スマートフォンに顔を向けるとロックが解除されます"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"その他のロック解除方法の設定"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"タップすると指紋が追加されます"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"顔を確認できません。ハードウェアを利用できません。"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"顔認証をもう一度お試しください。"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"新しい顔データを保存できません。古いデータを削除してください。"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"顔の操作をキャンセルしました。"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"顔認証はユーザーによりキャンセルされました。"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"試行回数の上限です。後でもう一度お試しください。"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"試行回数が上限を超えたため、顔認証を無効にしました。"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"顔を確認できません。もう一度お試しください。"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"顔認証を設定していません。"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"このデバイスでは、顔認証はご利用いただけません。"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"センサーが一時的に無効になっています。"</string>
<string name="face_name_template" msgid="3877037340223318119">"顔 <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"顔認証の使用"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"顔認証または画面ロックの使用"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"続行するには顔認証を使用してください"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"続行するには、顔認証または画面ロックを使用してください"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"ロック解除エリアを拡大します。"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"スライドロックを解除します。"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"パターンロックを解除します。"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"顔認証を行います。"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PINロックを解除します。"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM PIN のロックを解除します。"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM PUK のロックを解除します。"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"OFF にする"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"詳細"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12 では Android 通知の自動調整が拡張通知に切り替えられました。この機能により、操作や返信の候補が提示され、通知が整理されます。\n\n拡張通知は通知コンテンツにアクセスできます。これには、連絡先の名前などの個人情報やメッセージも含まれます。また、この機能は、通知を非表示にしたり通知に応答したりすることもできます。たとえば、電話に出ることやサイレント モードを管理することができます。"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ルーティン モード情報の通知"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"通常の充電を行う前に電池が切れる可能性があります"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"電池を長持ちさせるため、バッテリー セーバーが有効になりました"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 7c51350..17cfe4c 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"თითის ანაბეჭდის ხატულა"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"სახით განბლოკვის აპარატურის მართვა"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"საშუალებას აძლევს აპს, დაამატოს და წაშალოს სახეების შაბლონები."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"სახით განბლოკვის აპარატურის გამოყენება"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"საშუალებას აძლევს აპს, ამოცნობისთვის გამოიყენოს სახით განბლოკვის აპარატურა"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"სახით განბლოკვა"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"დაარეგისტრირეთ თქვენი სახე ხელახლა"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"ამოცნობის გასაუმჯობესებლად, გთხოვთ, ხელახლა დაარეგისტრიროთ თქვენი სახე"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"სახით განბლოკვის დაყენება"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"განბლოკეთ თქვენი ტელეფონი შეხედვით"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"დააყენეთ განბლოკვის სხვა ხერხები"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"შეეხეთ თითის ანაბეჭდის დასამატებლად"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"სახე ვერ დასტურდება. აპარატი მიუწვდომელია."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"ცადეთ ხელახლა სახით განბლოკვა."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"სახის ახალი მონაცემები ვერ ინახება. ჯერ ძველი წაშალეთ."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"სახის ამოცნობა გაუქმდა."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"სახით განბლოკვა გაუქმდა მომხმარებლის მიერ."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"დაფიქსირდა ბევრი მცდელობა. ცადეთ მოგვიანებით."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"მეტისმეტად ბევრი მცდელობა იყო. სახით განბლოკვა გათიშულია."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"სახის დადასტურება ვერ ხერხდება. ცადეთ ხელახლა."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"თქვენ არ დაგიყენებიათ სახით განბლოკვა."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"სახით განბლოკვა ამ მოწყობილობაზე მხარდაჭერილი არ არის."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"სენსორი დროებით გათიშულია."</string>
<string name="face_name_template" msgid="3877037340223318119">"სახე <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"გამოიყენეთ სახით განბლოკვა"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"გამოიყენეთ სახით ან ეკრანის დაბლოკვა"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"გასაგრძელებლად გამოიყენეთ თქვენი სახე"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"გასაგრძელებლად გამოიყენეთ თქვენი სახე ან ეკრანის განბლოკვის ნიმუში"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"განბლოკვის სივრცის გაშლა."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"გასრიალებით განბლოკვა"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"განბლოკვა ნიმუშით."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"სახით განბლოკვა"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"განბლოკვა Pin-ით."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM-ის PIN-კოდით განბლოკვა."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM-ის PUK-კოდით განბლოკვა."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"კარგი"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"გამორთვა"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"შეიტყვეთ მეტი"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"გაფართოებულმა შეტყობინებებმა ჩაანაცვლა Android-ის ადაპტაციური შეტყობინებების ფუნქცია Android 12-ში. ეს ფუნქცია გაჩვენებთ შემოთავაზებულ მოქმედებებს და პასუხებს, ამასთანავე კი ახდენს თქვენი შეტყობინებების ორგანიზებას.\n\nგაფართოებულ შეტყობინებებს შეუძლია ყველა შეტყობინების კონტენტზე, მათ შორის, ისეთ პერსონალურ ინფორმაციაზე წვდომა, როგორიცაა კონტაქტების სახელები და შეტყობინებები. ამ ფუნქციას ასევე შეუძლია შეტყობინებათა დახურვა ან მათზე პასუხის გაცემა, მაგალითად, სატელეფონო ზარებზე პასუხი და „არ შემაწუხოთ“ რეჟიმის მართვა."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"რუტინის რეჟიმის საინფორმაციო შეტყობინება"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ბატარეა შეიძლება დაჯდეს დატენის ჩვეულ დრომდე"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ბატარეის დამზოგი გააქტიურდა ბატარეის მუშაობის გასახანგრძლივლებლად"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 93e275b..de0373c 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Саусақ ізі белгішесі"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"Бет тану жабдығын басқару"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Қолданбаға пайдаланатын бет үлгілерін енгізу және жою әдістерін шақыруға мүмкіндік береді."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"Бет тану жабдығын пайдалану"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Аутентификациялау үшін қолданбаға бет тану жабдығын пайдалануға рұқсат береді."</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Бет тану"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Бетті қайта тіркеу"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Құрылғы жүзіңізді жақсырақ тануы үшін, бетіңізді қайта тіркеңіз."</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Бет тану функциясын реттеу"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Телефоныңызға қарап, оның құлпын ашыңыз."</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Құлыпты ашудың басқа тәсілдерін реттеу"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Саусақ ізін қосу үшін түртіңіз."</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Бетті тану мүмкін емес. Жабдық қолжетімді емес."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Бет тану функциясын қайта қолданып көріңіз."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Жаңа бетті сақтау мүмкін емес. Алдымен ескісін жойыңыз."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Бетті танудан бас тартылды."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Пайдаланушы бет тану функциясынан бас тартты."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Тым көп әрекет жасалды. Кейінірек қайталаңыз."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Тым көп әрекет жасалды. Бет тану функциясы өшірілді."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Бетті тану мүмкін емес. Әрекетті қайталаңыз."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Бет тану реттелмеді."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Бұл құрылғыда бет тану функциясы істемейді."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Датчик уақытша өшірулі."</string>
<string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> беті"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Бет тану функциясын пайдалану"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Face Lock функциясын немесе экран құлпын пайдалану"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Жалғастыру үшін бетіңізді көрсетіңіз."</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Жалғастыру үшін бетті анықтау функциясын немесе экран құлпын пайдаланыңыз."</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Ашу аймағын кеңейту."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Сырғыту арқылы ашу."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Кескін арқылы ашу."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Бет тану."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin арқылы ашу."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM құлпын PIN кодымен ашу"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM құлпын PUK кодымен ашу"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Жарайды"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Өшіру"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Толығырақ"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12 жүйесінде кеңейтілген хабарландырулар функциясы бейімделетін хабарландырулар функциясын алмастырды. Бұл функция ұсынылған әрекеттер мен жауаптарды көрсетіп, хабарландыруларыңызды ретке келтіреді.\n\nОл хабарландыру мазмұнын, соның ішінде жеке ақпаратыңызды (мысалы, контакт аттары мен хабарлар) пайдалана алады. Сондай-ақ бұл функция арқылы хабарландыруларды жабуға немесе оларға жауап беруге (мысалы, телефон қоңырауларына жауап беру және \"Мазаламау\" режимін басқару) болады."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Режим туралы хабарландыру"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батарея заряды азаюы мүмкін"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Батарея ұзаққа жетуі үшін, Батареяны үнемдеу режимі іске қосылды"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index c8c2e48..1cb7679 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"រូបស្នាមម្រាមដៃ"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"គ្រប់គ្រងហាតវែរដោះសោតាមទម្រង់មុខ"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"អនុញ្ញាតឱ្យកម្មវិធីប្រើវិធីសាស្ត្រដើម្បីបញ្ចូល និងលុបទម្រង់គំរូផ្ទៃមុខសម្រាប់ប្រើប្រាស់។"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ប្រើហាតវែរដោះសោតាមទម្រង់មុខ"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"អនុញ្ញាតឱ្យកម្មវិធីប្រើហាតវែរដោះសោតាមទម្រង់មុខសម្រាប់ការផ្ទៀងផ្ទាត់"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ដោះសោតាមទម្រង់មុខ"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"ស្កេនបញ្ចូលមុខរបស់អ្នកម្ដងទៀត"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"ដើម្បីធ្វើឱ្យការសម្គាល់មុខប្រសើរជាងមុន សូមស្កេនបញ្ចូលមុខរបស់អ្នកម្ដងទៀត"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"រៀបចំការដោះសោតាមទម្រង់មុខ"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"ដោះសោទូរសព្ទរបស់អ្នកដោយសម្លឹងមើលវា"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"រៀបចំវិធីច្រើនទៀតដើម្បីដោះសោ"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"ចុចដើម្បីបញ្ចូលស្នាមម្រាមដៃ"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"មិនអាចផ្ទៀងផ្ទាត់មុខបានទេ។ មិនមានហាតវែរទេ។"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"សាកល្បងដោះសោតាមទម្រង់មុខម្ដងទៀត។"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"មិនអាចផ្ទុកទិន្នន័យទម្រង់មុខថ្មីបានទេ។ សូមលុបទិន្នន័យទម្រង់មុខចាស់ជាមុនសិន។"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"បានបោះបង់ប្រតិបត្តិការចាប់ផ្ទៃមុខ។"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"អ្នកប្រើប្រាស់បានបោះបង់ការដោះសោតាមទម្រង់មុខ។"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"ព្យាយាមចូលច្រើនពេកហើយ។ សូមព្យាយាមម្តងទៀតពេលក្រោយ។"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"ការដោះសោតាមទម្រង់មុខត្រូវបានបិទ ដោយសារព្យាយាមច្រើនដងពេក។"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"មិនអាចផ្ទៀងផ្ទាត់មុខបានទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"អ្នកមិនទាន់រៀបចំការដោះសោតាមទម្រង់មុខនៅឡើយទេ។"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"មិនអាចប្រើការដោះសោតាមទម្រង់មុខនៅលើឧបករណ៍នេះបានទេ។"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"បានបិទឧបករណ៍ចាប់សញ្ញាជាបណ្តោះអាសន្ន។"</string>
<string name="face_name_template" msgid="3877037340223318119">"ផ្ទៃមុខទី <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"ប្រើការដោះសោតាមទម្រង់មុខ"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ប្រើមុខ ឬការចាក់សោអេក្រង់"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"ប្រើមុខរបស់អ្នក ដើម្បីបន្ត"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ប្រើការចាក់សោអេក្រង់ ឬមុខរបស់អ្នក ដើម្បីបន្ត"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"ពង្រីកតំបន់ដោះសោ។"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"រុញដោះសោ។"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"លំនាំដោះសោ។"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"ដោះសោតាមទម្រង់មុខ។"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"កូដ PIN ដោះសោ។"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"ដោះកូដ Pin របស់សីុម។"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"ដោះកូដ Puk របស់សីុម។"</string>
@@ -1862,7 +1869,7 @@
<string name="managed_profile_label_badge" msgid="6762559569999499495">"កន្លែងធ្វើការ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_2" msgid="5673187309555352550">"<xliff:g id="LABEL">%1$s</xliff:g> ការងារទី 2"</string>
<string name="managed_profile_label_badge_3" msgid="6882151970556391957">"<xliff:g id="LABEL">%1$s</xliff:g> ការងារទី 3"</string>
- <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"សួររកកូដ PIN មុនពេលផ្ដាច់"</string>
+ <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"សួររកកូដ PIN មុនពេលដកខ្ទាស់"</string>
<string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"សួររកលំនាំដោះសោមុនពេលដោះខ្ទាស់"</string>
<string name="lock_to_app_unlock_password" msgid="9126722403506560473">"សួររកពាក្យសម្ងាត់មុនពេលផ្ដាច់"</string>
<string name="package_installed_device_owner" msgid="7035926868974878525">"ដំឡើងដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"យល់ព្រម"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"បិទ"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ស្វែងយល់បន្ថែម"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"ការជូនដំណឹងប្រសើរជាងមុនបានជំនួសការជូនដំណឹងដែលមានភាពបត់បែន Android នៅក្នុង Android 12។ មុខងារនេះបង្ហាញការឆ្លើយតប និងសកម្មភាពដែលបានណែនាំ ព្រមទាំងរៀបចំការជូនដំណឹងរបស់អ្នក។\n\nការជូនដំណឹងប្រសើរជាងមុនអាចចូលប្រើខ្លឹមសារនៃការជូនដំណឹង រួមទាំងព័ត៌មានផ្ទាល់ខ្លួនដូចជា ឈ្មោះទំនាក់ទំនង និងសារជាដើម។ មុខងារនេះក៏អាចច្រានចោល ឬឆ្លើយតបនឹងការជូនដំណឹងដូចជា ការទទួលការហៅទូរសព្ទ និងគ្រប់គ្រងមុខងារកុំរំខានផងដែរ។"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ការជូនដំណឹងព័ត៌មានរបស់មុខងារទម្លាប់"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ថ្មអាចនឹងអស់ មុនពេលសាកថ្មធម្មតា"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"បានបើកដំណើរការមុខងារសន្សំថ្ម ដើម្បីបង្កើនកម្រិតថាមពលថ្ម"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index da95466..ad71e8e 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಐಕಾನ್"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"ಫೇಸ್ ಅನ್ಲಾಕ್ ಹಾರ್ಡ್ವೇರ್ ಅನ್ನು ನಿರ್ವಹಿಸಿ"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"ಬಳಕೆಗೆ ಮುಖದ ಟೆಂಪ್ಲೇಟ್ಗಳನ್ನು ಸೇರಿಸಲು ಮತ್ತು ಅಳಿಸಲು ವಿಧಾನಗಳನ್ನು ಮನವಿ ಮಾಡಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ಫೇಸ್ ಅನ್ಲಾಕ್ ಹಾರ್ಡ್ವೇರ್ ಬಳಸಿ"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"ಪ್ರಮಾಣೀಕರಣಕ್ಕಾಗಿ ಫೇಸ್ ಅನ್ಲಾಕ್ ಹಾರ್ಡ್ವೇರ್ ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ಫೇಸ್ ಅನ್ಲಾಕ್"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"ನಿಮ್ಮ ಮುಖವನ್ನು ಮರುನೋಂದಣಿ ಮಾಡಿ"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"ಗುರುತಿಸುವಿಕೆಯನ್ನು ಹೆಚ್ಚಿಸಲು ನಿಮ್ಮ ಮುಖವನ್ನು ಮರುನೋಂದಣಿ ಮಾಡಿ"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"ಫೇಸ್ ಅನ್ಲಾಕ್ ಸೆಟಪ್ ಮಾಡಿ"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"ಫೋನ್ ಅನ್ನು ನೋಡುವ ಮೂಲಕ ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"ಅನ್ಲಾಕ್ ಮಾಡಲು ಹೆಚ್ಚಿನ ಮಾರ್ಗಗಳನ್ನು ಹೊಂದಿಸಿ"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಸೇರಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ಮುಖ ದೃಢೀಕರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಹಾರ್ಡ್ವೇರ್ ಲಭ್ಯವಿಲ್ಲ."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"ಫೇಸ್ ಅನ್ಲಾಕ್ ಅನ್ನು ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"ಹೊಸ ಮುಖ ಡೇಟಾ ಸಂಗ್ರಹಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಮೊದಲು ಹಳೆಯದನ್ನು ಅಳಿಸಿ"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"ಮುಖದ ಕಾರ್ಯಚರಣೆಯನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"ಫೇಸ್ ಅನ್ಲಾಕ್ ಅನ್ನು ಬಳಕೆದಾರರು ರದ್ದುಗೊಳಿಸಿದ್ದಾರೆ."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"ಹಲವು ಬಾರಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"ಹಲವು ಬಾರಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಫೇಸ್ ಅನ್ಲಾಕ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"ಮುಖವನ್ನು ದೃಢೀಕರಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"ನೀವು ಫೇಸ್ ಅನ್ಲಾಕ್ ಅನ್ನು ಸೆಟಪ್ ಮಾಡಿಲ್ಲ."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"ಈ ಸಾಧನದಲ್ಲಿ ಫೇಸ್ ಅನ್ಲಾಕ್ ವೈಶಿಷ್ಟ್ಯವು ಬೆಂಬಲಿತವಾಗಿಲ್ಲ."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"ಸೆನ್ಸಾರ್ ಅನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
<string name="face_name_template" msgid="3877037340223318119">"ಮುಖದ <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"ಫೇಸ್ ಅನ್ಲಾಕ್ ಅನ್ನು ಬಳಸಿ"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ಫೇಸ್ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ಬಳಸಿ"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"ಮುಂದುವರಿಸಲು ನಿಮ್ಮ ಮುಖವನ್ನು ಬಳಸಿ"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ಮುಂದುವರಿಸಲು ನಿಮ್ಮ ಮುಖ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ಬಳಸಿ"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"ಅನ್ಲಾಕ್ ಪ್ರದೇಶವನ್ನು ವಿಸ್ತರಿಸು."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"ಸ್ಲೈಡ್ ಅನ್ಲಾಕ್."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"ಪ್ಯಾಟರ್ನ್ ಅನ್ಲಾಕ್."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"ಫೇಸ್ ಅನ್ಲಾಕ್."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"ಪಿನ್ ಅನ್ಲಾಕ್."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"ಸಿಮ್ ಪಿನ್ ಅನ್ಲಾಕ್ ಮಾಡಿ."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"ಸಿಮ್ PUK ಅನ್ಲಾಕ್ ಮಾಡಿ."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ಸರಿ"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ಆಫ್ ಮಾಡಿ"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"ವರ್ಧಿತ ಅಧಿಸೂಚನೆಗಳು Android 12 ರಲ್ಲಿ Android ಅಡಾಪ್ಟಿವ್ ಅಧಿಸೂಚನೆಗಳನ್ನು ಬದಲಾಯಿಸಿವೆ. ಈ ವೈಶಿಷ್ಟ್ಯವು ಸೂಚಿಸಿದ ಕ್ರಿಯೆಗಳು ಮತ್ತು ಪ್ರತ್ಯುತ್ತರಗಳನ್ನು ತೋರಿಸುತ್ತದೆ ಮತ್ತು ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳನ್ನು ಆಯೋಜಿಸುತ್ತದೆ.\n\nವರ್ಧಿತ ಅಧಿಸೂಚನೆಗಳು ಸಂಪರ್ಕ ಹೆಸರುಗಳು ಮತ್ತು ಸಂದೇಶಗಳಂತಹ ವೈಯಕ್ತಿಕ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಂತೆ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆ ವಿಷಯವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು. ಈ ವೈಶಿಷ್ಟ್ಯವು ಫೋನ್ ಕರೆಗಳಿಗೆ ಉತ್ತರಿಸುವುದು ಮತ್ತು \'ಅಡಚಣೆ ಮಾಡಬೇಡಿ\' ಅನ್ನು ನಿಯಂತ್ರಿಸುವಂತಹ ಅಧಿಸೂಚನೆಗಳನ್ನು ವಜಾಗೊಳಿಸಬಹುದು ಅಥವಾ ಪ್ರತಿಕ್ರಿಯಿಸಬಹುದು."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ದೈನಂದಿನ ಸ್ಥಿತಿಯ ಮಾಹಿತಿಯ ಅಧಿಸೂಚನೆ"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ಚಾರ್ಜ್ಗೆ ಮೊದಲೆ ಬ್ಯಾಟರಿ ಮುಗಿದು ಬಿಡಬಹುದು"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ಬ್ಯಾಟರಿ ಅವಧಿ ಹೆಚ್ಚಿಸಲು ಬ್ಯಾಟರಿ ಸೇವರ್ ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index d721d6c..fde7eaf 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"지문 아이콘"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"얼굴 인식 잠금 해제 하드웨어 관리"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"사용할 얼굴 템플릿의 추가 및 삭제 메서드를 앱에서 호출하도록 허용합니다."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"얼굴 인식 잠금 해제 하드웨어 사용"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"앱에서 얼굴 인식 잠금 해제 하드웨어를 인증에 사용하도록 허용합니다."</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"얼굴 인식 잠금 해제"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"얼굴 재등록 필요"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"인식률을 개선하려면 얼굴을 다시 등록하세요."</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"얼굴 인식 잠금 해제 설정"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"휴대전화의 화면을 응시하여 잠금 해제할 수 있습니다."</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"다른 잠금 해제 방법 설정"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"지문을 추가하려면 탭하세요."</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"얼굴을 확인할 수 없습니다. 하드웨어를 사용할 수 없습니다."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"얼굴 인식 잠금 해제를 다시 시도해 주세요."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"새 얼굴 데이터를 저장할 수 없습니다. 먼저 기존 얼굴 데이터를 삭제하세요."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"얼굴 인식 작업이 취소되었습니다."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"사용자가 얼굴 인식 잠금 해제를 취소했습니다."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"시도 횟수가 너무 많습니다. 나중에 다시 시도하세요."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"시도 횟수가 너무 많습니다. 얼굴 인식 잠금 해제가 사용 중지되었습니다."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"얼굴을 확인할 수 없습니다. 다시 시도하세요."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"얼굴 인식 잠금 해제를 설정하지 않았습니다."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"이 기기에서는 얼굴 인식 잠금 해제가 지원되지 않습니다."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"센서가 일시적으로 사용 중지되었습니다."</string>
<string name="face_name_template" msgid="3877037340223318119">"얼굴 <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"얼굴 인식 잠금 해제 사용"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"얼굴 또는 화면 잠금 사용"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"계속하려면 얼굴로 인증하세요"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"계속하려면 얼굴 또는 화면 잠금을 사용하세요"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"잠금 해제 영역 확장"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"슬라이드하여 잠금해제합니다."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"패턴을 사용하여 잠금해제합니다."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"얼굴을 인식하여 잠금 해제합니다."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"핀을 사용하여 잠금해제합니다."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM PIN 잠금 해제"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM PUK 잠금 해제"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"확인"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"사용 중지"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"자세히 알아보기"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12에서는 Android 적응형 알림이 개선된 알림으로 대체됩니다. 이 기능은 추천 작업과 답장을 표시하고 알림을 정리해 줍니다.\n\n개선된 알림은 연락처 이름과 메시지 등 개인 정보가 포함된 알림 내용에 액세스할 수 있습니다. 또한 전화를 받고 방해 금지 모드를 제어하는 등 알림을 닫거나 처리하는 것도 가능합니다."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"루틴 모드 정보 알림"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"평소에 충전하는 시간 전에 배터리가 소진될 수 있습니다."</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"배터리 수명을 연장하기 위해 절전 모드가 활성화되었습니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 3004b08..4aaed11 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Манжа изинин сүрөтчөсү"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"жүзүнөн таанып ачуу функциясынын аппараттык камсыздоосун башкаруу"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Колдонмого пайдалануу үчүн жүздүн үлгүлөрүн кошуу жана жок кылуу мүмкүндүгүн берет."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"аппараттык камсыздоо үчүн жүзүнөн таанып ачуу функциясын колдонуу"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Колдонмо аныктыкты текшерүүдө Жүзүнөн таанып ачуу функциясынын аппараттык камсыздоосун колдонот"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Жүзүнөн таанып ачуу"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Жүзүңүздү кайра таанытыңыз."</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Мыкты таануу үчүн, жүзүңүздү кайра таанытыңыз"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Жүзүнөн таанып ачуу функциясын жөндөңүз"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Телефонуңузду карап туруп эле кулпусун ачып алыңыз"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Кулпусун ачуунун көбүрөөк жолдорун жөндөңүз"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Манжа изин кошуу үчүн басыңыз"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Жүз ырасталбай жатат. Аппараттык камсыздоо жеткиликсиз."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Жүзүнөн таанып ачуу функциясын кайра текшерип көрүңүз."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Жаңы жүздү сактоо мүмкүн эмес. Адегенде эскисин өчүрүңүз."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Жүздүн аныктыгын текшерүү жокко чыгарылды."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Жүзүнөн таанып ачуу функциясын колдонуучу өчүрүп салды."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Өтө көп жолу аракет жасадыңыз. Бир аздан кийин кайталап көрүңүз."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Өтө көп жолу аракет кылдыңыз. Жүзүнөн таанып ачуу функциясы өчүрүлдү."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Жүз ырасталбай жатат. Кайталап көрүңүз."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Жүзүнөн таанып ачуу функциясын жөндөй элексиз."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Жүзүнөн таанып ачуу функциясы бул түзмөктө иштебейт."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Сенсор убактылуу өчүрүлгөн."</string>
<string name="face_name_template" msgid="3877037340223318119">"Жүз <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Жүзүнөн таанып ачууну колдонуу"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Жүзүнөн таанып ачууну же экрандын кулпусун колдонуу"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Улантуу үчүн жүзүңүздү көрсөтүңүз"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Улантуу үчүн жүзүңүздү же экрандын кулпусун колдонуңуз"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Бөгөттөн чыгаруу аймагын кеңейтүү."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Жылмыштырып ачуу."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Үлгү менен ачуу."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Жүзүнөн таанып ачуу"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Пин код менен ачуу."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM-картанын кулпусун PIN-код менен ачуу."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM-картанын кулпусун PUK-код менен ачуу."</string>
@@ -1070,7 +1077,7 @@
<string name="weeks" msgid="3516247214269821391">"апталар"</string>
<string name="year" msgid="5182610307741238982">"жыл"</string>
<string name="years" msgid="5797714729103773425">"жылдар"</string>
- <string name="now_string_shortest" msgid="3684914126941650330">"азыр"</string>
+ <string name="now_string_shortest" msgid="3684914126941650330">"Учурда"</string>
<plurals name="duration_minutes_shortest" formatted="false" msgid="7519574894537185135">
<item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>мүн.</item>
<item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>мүн.</item>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Макул"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Өчүрүү"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Кененирээк"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12 версиясында ыңгайлаштырылуучу билдирмелер жакшыртылган билдирмелерге алмаштырылды. Бул функция ыкчам аракеттерди жана жоопторду көрсөтүп, билдирмелериңизди иреттейт.\n\nЖакшыртылган билдирмелер бардык билдирмелердин мазмунун, ошондой эле байланыштардын аты-жөнү жана билдирүүлөрү сыяктуу жеке маалыматты көрө алат. Ошондой эле, бул функция билдирмелерди жаап, баскычтарын басып, телефон чалууларга жооп берип жана \"Тынчымды алба\" функциясын башкара алат."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Режимдин адаттагы билдирмеси"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батарея кубаттоого чейин отуруп калышы мүмкүн"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Батареянын отуруп калбашы үчүн Батареяны үнөмдөгүч режими иштетилди"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 00cdb03..d424d87 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ໄອຄອນລາຍນິ້ວມື"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"ຈັດການຮາດແວປົດລັອກດ້ວຍໜ້າ"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"ອະນຸຍາດໃຫ້ແອັບເປີດວິທີການຕ່າງໆເພື່ອເພີ່ມ ແລະ ລຶບແມ່ແບບໃບໜ້າສຳລັບການນຳໃຊ້."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ໃຊ້ຮາດແວການປົດລັອກດ້ວຍໜ້າ"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ຮາດແວການປົດລັອກດ້ວຍໜ້າເພື່ອພິສູດຢືນຢັນ"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ປົດລັອກດ້ວຍໜ້າ"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"ລົງທະບຽນໃບໜ້າຂອງທ່ານຄືນໃໝ່"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"ເພື່ອປັບປຸງການຈຳແນກ, ກະລຸນາລົງທະບຽນໃບໜ້າຂອງທ່ານຄືນໃໝ່."</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"ຕັ້ງຄ່າການປົດລັອກດ້ວຍໜ້າ"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"ປົດລັອກໂທລະສັບຂອງທ່ານໂດຍການເບິ່ງມັນ"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"ຕັ້ງຄ່າວິທີເພີ່ມເຕີມເພື່ອປົດລັອກ"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"ແຕະເພື່ອເພີ່ມລາຍນິ້ວມື"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ບໍ່ສາມາດຢັ້ງຢືນໃບໜ້າໄດ້. ບໍ່ມີຮາດແວໃຫ້ໃຊ້."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"ລອງປົດລັອກດ້ວຍໜ້າອີກເທື່ອໜຶ່ງ."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"ບໍ່ສາມາດບັນທຶກຂໍ້ມູນໃບໜ້າໃໝ່ໄດ້. ກະລຸນາລຶບຂໍ້ມູນເກົ່າອອກກ່ອນ."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"ຍົກເລີກການດຳເນີນການກັບໃບໜ້າແລ້ວ."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"ຜູ້ໃຊ້ຍົກເລີກການປົດລັອກດ້ວຍໜ້າແລ້ວ."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"ມີຄວາມພະຍາຍາມຫຼາຍຄັ້ງເກີນໄປ. ກະລຸນາລອງໃໝ່ໃນພາຍຫຼັງ."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"ພະຍາຍາມຫຼາຍເທື່ອເກີນໄປ. ປິດນຳໃຊ້ການປົດລັອກດ້ວຍໜ້າແລ້ວ."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"ບໍ່ສາມາດຢັ້ງຢືນໃບໜ້າໄດ້. ກະລຸນາລອງໃໝ່."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"ທ່ານຍັງບໍ່ໄດ້ຕັ້ງການປົດລັອກດ້ວຍໜ້າເທື່ອ."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"ບໍ່ຮອງຮັບການປົດລັອກດ້ວຍໜ້າຢູ່ອຸປະກອນນີ້."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"ປິດການເຮັດວຽກຂອງເຊັນເຊີໄວ້ຊົ່ວຄາວແລ້ວ."</string>
<string name="face_name_template" msgid="3877037340223318119">"ໃບໜ້າ <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"ໃຊ້ການປົດລັອກດ້ວຍໜ້າ"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ໃຊ້ໃບໜ້າ ຫຼື ການລັອກໜ້າຈໍ"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"ໃຊ້ໜ້າທ່ານເພື່ອສືບຕໍ່"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ໃຊ້ໃບໜ້າ ຫຼື ການລັອກໜ້າຈໍຂອງທ່ານເພື່ອດຳເນີນການຕໍ່"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"ຂະຫຍາຍຂອບເຂດປົດລັອກ."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"ການປົດລັອກດ້ວຍການເລື່ອນ."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"ປົດລັອກດ້ວຍຮູບແບບ."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"ປົດລັອກດ້ວຍໜ້າ."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"ປົດລັອກດ້ວຍ PIN."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"ປົດລັອກ Sim Pin."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"ປົດລັອກ Sim Puk."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ຕົກລົງ"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ປິດໄວ້"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ສຶກສາເພີ່ມເຕີມ"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"ການແຈ້ງເຕືອນແບບປັບຕົວໄດ້ຂອງ Android ຖືກແທນທີ່ດ້ວຍການແຈ້ງເຕືອນທີ່ປັບປຸງໃຫ້ດີຂຶ້ນໃນ Android 12 ແລ້ວ. ຄຸນສົມບັດນີ້ສະແດງຄຳສັ່ງ ແລະ ການຕອບກັບທີ່ແນະນຳ ແລະ ຈັດລະບຽບການແຈ້ງເຕືອນຂອງທ່ານ.\n\nການແຈ້ງເຕືອນທີ່ປັບປຸງໃຫ້ດີຂຶ້ນສາມາດເຂົ້າເຖິງເນື້ອຫາການແຈ້ງເຕືອນໄດ້, ຮວມທັງຂໍ້ມູນສ່ວນຕົວ ເຊັ່ນ: ຊື່ຜູ້ຕິດຕໍ່ ແລະ ຂໍ້ຄວາມ. ຄຸນສົມບັດນີ້ສາມາດປິດ ຫຼື ຕອບກັບຫາການແຈ້ງເຕືອນໄດ້ນຳ ເຊັ່ນ: ການຮັບສາຍໂທລະສັບ ແລະ ຄວບຄຸມໂໝດຫ້າມລົບກວນ."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ການແຈ້ງເຕືອນຂໍ້ມູນໂໝດກິດຈະວັດປະຈຳວັນ"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ແບັດເຕີຣີອາດໝົດກ່ອນການສາກຕາມປົກກະຕິ"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ເປີດຕົວປະຢັດແບັດເຕີຣີເພື່ອຂະຫຍາຍອາຍຸແບັດເຕີຣີ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index d83022e..05f3e18 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -615,14 +615,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Piršto antspaudo piktograma"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"tvarkyti Atrakinimo pagal veidą aparatinę įrangą"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Programai leidžiama aktyv. metodus, norint pridėti ir ištrinti naudojamus veidų šablonus."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"naudoti Atrakinimo pagal veidą aparatinę įrangą"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Programai leidžiama naudoti Atrakinimo pagal veidą aparatinę įrangą tapatybei nustatyti"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Atrakinimas pagal veidą"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Pakartotinis veido registravimas"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Kad patobulintumėte atpažinimą, iš naujo užregistruokite veidą"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Atrakinimo pagal veidą nustatymas"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Atrakinkite telefoną pažiūrėję į jį"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Daugiau atrakinimo metodų nustatymas"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Palieskite, kad pridėtumėte kontrolinį kodą"</string>
@@ -649,18 +647,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Nepavyko patv. veido. Aparatinė įranga negalima."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Band. naudoti Atrakinimą pagal veidą dar kartą."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Nepavyko išs. naujų veido duomenų. Pirm. ištrinkite senus."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Veido atpažinimo operacija atšaukta."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Atrakinimą pagal veidą atšaukė naudotojas."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Per daug bandymų. Vėliau bandykite dar kartą."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Per daug bandymų. Atrakinimas pagal veidą išjungtas."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Nepavyko patvirtinti veido. Bandykite dar kartą."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Nenustatėte Atrakinimo pagal veidą."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Atrakinimas pagal veidą šiame įrenginyje nepalaikomas."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Jutiklis laikinai išjungtas."</string>
<string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> veidas"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Naudoti atrakinimą pagal veidą"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Naudoti atrakinimą pagal veidą arba ekrano užraktą"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Jei norite tęsti, naudokite atpažinimą pagal veidą"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Jei norite tęsti, naudokite veido atpažinimo funkciją arba ekrano užraktą"</string>
@@ -963,7 +969,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Išplėsti atrakinimo sritį."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Atrakinimas slystant."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Atrakinimas pagal piešinį."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Atrakinimas pagal veidą."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Atrakinimas įvedus PIN kodą."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM kortelės PIN kodo atrakinimas."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM kortelės PUK kodo atrakinimas."</string>
@@ -2161,8 +2168,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Gerai"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Išjungti"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Sužinokite daugiau"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"12 versijos „Android“ patobulinti pranešimai pakeitė „Android“ prisitaikančius pranešimus. Ši funkcija rodo siūlomus veiksmus bei atsakymus ir tvarko jūsų pranešimus.\n\nPatobulintų pranešimų funkcija gali pasiekti pranešimų turinį, įskaitant asmens informaciją (pvz., kontaktų vardus ir pranešimus). Ši funkcija taip pat gali atsisakyti pranešimų arba į juos atsakyti, pvz., atsakyti į telefono skambučius ir valdyti netrukdymo režimą."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Veiksmų sekos režimo informacijos pranešimas"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Akumuliatoriaus energija gali išsekti prieš įprastą įkrovimą"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Akumuliatoriaus tausojimo priemonė suaktyvinta, kad akumuliatorius veiktų ilgiau"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 96b65da..7901668 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -612,14 +612,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Pirksta nospieduma ikona"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"pārvaldīt aparatūru, kas paredzēta autorizācijai pēc sejas"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Atļauj lietotnei izsaukt metodes izmantojamo sejas veidņu pievienošanai un dzēšanai."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"lietot aparatūru, kas paredzēta autorizācijai pēc sejas"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Atļauj lietotnei izmantot autentificēšanai aparatūru, ar ko veic autorizāciju pēc sejas"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Autorizācija pēc sejas"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Atkārtoti reģistrējiet seju"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Lai uzlabotu atpazīšanu, lūdzu, atkārtoti reģistrējiet savu seju"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Autorizācijas pēc sejas iestatīšana"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Atbloķējiet tālruni, skatoties uz to"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Citi atbloķēšanas veidi"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Pieskarieties, lai pievienotu pirksta nospiedumu"</string>
@@ -646,18 +644,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Nevar verificēt seju. Aparatūra nav pieejama."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Vēlreiz mēģiniet veikt autorizāciju pēc sejas."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Nevar saglabāt jaunās sejas datus. Dzēsiet kādu no vecajām."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Darbība ar sejas datiem atcelta."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Lietotājs atcēla autorizāciju pēc sejas."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Pārāk daudz mēģinājumu. Vēlāk mēģiniet vēlreiz."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Pārāk daudz mēģinājumu. Autorizācija pēc sejas ir atspējota."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Nevar verificēt seju. Mēģiniet vēlreiz."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Autorizācija pēc sejas nav iestatīta."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Autorizācija pēc sejas šajā ierīcē netiek atbalstīta"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensors ir īslaicīgi atspējots."</string>
<string name="face_name_template" msgid="3877037340223318119">"Seja <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Autorizācija pēc sejas"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Autorizācijas pēc sejas vai ekrāna bloķēšanas metodes izmantošana"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Lai turpinātu, veiciet autorizāciju pēc sejas"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Izmantojiet autorizāciju pēc sejas vai ekrāna bloķēšanas opciju, lai turpinātu"</string>
@@ -960,7 +966,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Izvērst atbloķēšanas apgabalu."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Autorizācija, velkot ar pirkstu."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Autorizācija ar kombināciju."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Autorizācija pēc sejas."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Autorizācija ar PIN kodu."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM kartes atbloķēšanas PIN"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM kartes atbloķēšanas PUK"</string>
@@ -2128,8 +2135,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Labi"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Izslēgt"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Uzzināt vairāk"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android adaptīvie paziņojumi ir aizstāti ar funkciju “Uzlabotie paziņojumi” operētājsistēmā Android 12. Šī funkcija parāda ieteiktās darbības un atbildes, kā arī kārto jūsu paziņojumus.\n\nFunkcija “Uzlabotie paziņojumi” var piekļūt paziņojumu saturam, tostarp personas informācijai, piemēram, kontaktpersonu vārdiem un ziņojumiem. Šī funkcija var arī noraidīt paziņojumus vai atbildēt uz tiem, piemēram, atbildēt uz tālruņa zvaniem vai pārvaldīt funkciju “Netraucēt”."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Informatīvs paziņojums par akumulatoru"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Akumulators var izlādēties pirms parastā uzlādes laika"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Aktivizēts akumulatora enerģijas taupīšanas režīms, lai palielinātu akumulatora darbības ilgumu"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 5d4f231..0bd80b7 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Икона за отпечатоци"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"управува со хардвер за „Отклучување со лик“"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Дозволува апликац. да повика начини за додавање и бришење шаблони на лице за користење."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"користи хардвер за „Отклучување со лик“"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Дозволува апликацијата да користи хардвер за „Отклучување со лик“ за проверка"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Отклучување со лик"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Повторно регистрирајте го ликот"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"За да се подобри препознавањето, повторно регистрирајте го ликот"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Поставете „Отклучување со лик“"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Отклучете го телефонот со гледање во него"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Поставете уште начини за отклучување"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Допрете за да додадете отпечаток"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Ликот не може да се потврди. Хардвер - недостапен."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Пробајте „Отклучување со лик“ повторно."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Не се зачуваа податоците за нов лик. Избришете го стариот."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Операцијата со лице се откажа."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"„Отклучувањето со лик“ е откажано од корисникот."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Премногу обиди. Обидете се повторно подоцна."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Премногу обиди. „Отклучувањето со лик“ е оневозможено."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Ликот не може да се потврди. Обидете се повторно."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Не сте поставиле „Отклучување со лик“."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"„Отклучувањето со лик“ не е поддржано на уредов."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Сензорот е привремено оневозможен."</string>
<string name="face_name_template" msgid="3877037340223318119">"Лице <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Користи отклучување со лик"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Користи лик или заклучување екран"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Користете го вашиот лик за да продолжите"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Користете отклучување со лик или заклучување екран за да продолжите"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Прошири отклучена област."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Отклучување со лизгање."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Отклучување со шема."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Отклучување со лик."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Отклучување со пин."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Отклучување со PIN на SIM."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Отклучување со PUK на SIM."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Во ред"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Исклучи"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Дознајте повеќе"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"„Подобрените известувања“ ги заменија „Приспособливите известувања на Android“ во Android 12. Оваа функција прикажува предложени дејства и одговори и ги организира вашите известувања.\n\n„Подобрените известувања“ може да пристапат до содржините од известувањата, вклучително и личните податоци, како што се имињата на контактите и пораките. Функцијава може и да отфрла или одговара на известувања, како на пример, одговарање телефонски повици и да ја контролира „Не вознемирувај“."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Известување за информации за режимот за рутини"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батеријата може да се потроши пред вообичаеното време за полнење"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Активиран е „Штедачот на батерија“ за да се продолжи траењето на батеријата"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index d138c2e..57ff57d 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ഫിംഗർപ്രിന്റ് ഐക്കൺ"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"മുഖം തിരിച്ചറിഞ്ഞുള്ള അൺലോക്ക് ഹാർഡ്വെയർ മാനേജ് ചെയ്യുക"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"ഉപയോഗിക്കാനായി, മുഖത്തിന്റെ ടെംപ്ലേറ്റുകൾ ചേർക്കാനും ഇല്ലാതാക്കാനുമുള്ള രീതികൾ അഭ്യർത്ഥിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ഫെയ്സ് അൺലോക്ക് ഹാർഡ്വെയർ ഉപയോഗിക്കുക"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"പരിശോധിച്ചുറപ്പിക്കാൻ ഫെയ്സ് അൺലോക്ക് ഹാർഡ്വെയർ ഉപയോഗിക്കാൻ അനുവദിക്കുന്നു"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ഫെയ്സ് അൺലോക്ക്"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"നിങ്ങളുടെ മുഖം വീണ്ടും എൻറോൾ ചെയ്യൂ"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"തിരിച്ചറിയൽ മെച്ചപ്പെടുത്താൻ, നിങ്ങളുടെ മുഖം ദയവായി വീണ്ടും എൻറോൾ ചെയ്യൂ"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"ഫെയ്സ് അൺലോക്ക് സജ്ജീകരിക്കുക"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"ഫോണിലേക്ക് നോക്കി അത് അൺലോക്ക് ചെയ്യുക"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"അൺലോക്ക് ചെയ്യുന്നതിനുള്ള കൂടുതൽ വഴികൾ സജ്ജീകരിക്കുക"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"ഫിംഗർപ്രിന്റ് ചേർക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"മുഖം പരിശോധിക്കാൻ കഴിയില്ല. ഹാർഡ്വെയർ ലഭ്യമല്ല."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"ഫെയ്സ് അൺലോക്ക് വീണ്ടും പരീക്ഷിക്കൂ"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"പുതിയ മുഖ ഡാറ്റ സംഭരിക്കാനാകില്ല. ആദ്യം പഴയത് ഇല്ലാതാക്കുക."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"മുഖത്തിന്റെ പ്രവർത്തനം റദ്ദാക്കി."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"ഉപയോക്താവ് ഫെയ്സ് അൺലോക്ക് റദ്ദാക്കി"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"നിരവധി തവണ ശ്രമിച്ചു. പിന്നീട് വീണ്ടും ശ്രമിക്കുക."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"വളരെയധികം ശ്രമങ്ങൾ. ഫെയ്സ് അൺലോക്ക് പ്രവർത്തനരഹിതമാക്കി"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"മുഖം പരിശോധിക്കാൻ കഴിയില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"ഫെയ്സ് അൺലോക്ക് സജ്ജീകരിച്ചില്ല."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"ഫെയ്സ് അൺലോക്ക് ഈ ഉപകരണം പിന്തുണയ്ക്കുന്നില്ല."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"സെൻസർ താൽക്കാലികമായി പ്രവർത്തനരഹിതമാക്കി."</string>
<string name="face_name_template" msgid="3877037340223318119">"മുഖം <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"ഫെയ്സ് അൺലോക്ക് ഉപയോഗിക്കുക"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ഫെയ്സ് അല്ലെങ്കിൽ സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"തുടരാൻ നിങ്ങളുടെ മുഖം ഉപയോഗിക്കുക"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"തുടരാൻ നിങ്ങളുടെ മുഖം അല്ലെങ്കിൽ സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"അൺലോക്ക് ഏരിയ വിപുലീകരിക്കുക."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"സ്ലൈഡ് അൺലോക്ക്."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"പാറ്റേൺ അൺലോക്ക്."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"ഫെയ്സ് അൺലോക്ക്."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"പിൻ അൺലോക്ക്."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"സിം പിൻ അൺലോക്ക്."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"സിം Puk അൺലോക്ക്."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ശരി"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ഓഫാക്കുക"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"കൂടുതലറിയുക"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12-ൽ Android അഡാപ്റ്റീവ് അറിയിപ്പുകൾക്ക് പകരം മെച്ചപ്പെടുത്തിയ അറിയിപ്പുകൾ ഉൾപ്പെടുത്തിയിരിക്കുന്നു. നിർദ്ദേശിക്കുന്ന പ്രവർത്തനങ്ങളും മറുപടികളും കാണിക്കുന്നതിനൊപ്പം ഈ ഫീച്ചർ നിങ്ങളുടെ അറിയിപ്പുകൾ ഓർഗനൈസ് ചെയ്യുന്നു.\n\nമെച്ചപ്പെടുത്തിയ അറിയിപ്പുകൾക്ക്, കോൺടാക്റ്റ് പേരുകളും സന്ദേശങ്ങളും പോലുള്ള വ്യക്തിപരമായ വിവരങ്ങൾ ഉൾപ്പെടെയുള്ള അറിയിപ്പ് ഉള്ളടക്കം ആക്സസ് ചെയ്യാനാകും. ഫോൺ കോളുകൾക്ക് മറുപടി നൽകുക, \'ശല്യപ്പെടുത്തരുത്\' നിയന്ത്രിക്കുക എന്നിവ പോലെ, അറിയിപ്പുകൾ ഡിസ്മിസ് ചെയ്യാനും അവയ്ക്ക് മറുപടി നൽകാനും ഈ ഫീച്ചറിന് കഴിയും."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ദിനചര്യ മോഡ് വിവരത്തെ കുറിച്ചുള്ള അറിയിപ്പ്"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"സാധാരണയുള്ളതിലും നേരത്തെ ബാറ്ററിയുടെ ചാർജ് തീർന്നേക്കാം"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ബാറ്ററി ലൈഫ് വര്ദ്ധിപ്പിക്കാൻ, ബാറ്ററി ലാഭിക്കൽ സജീവമാക്കി"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 75ad97f..a10d44d 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -308,7 +308,7 @@
<string name="permgrouplab_location" msgid="1858277002233964394">"Байршил"</string>
<string name="permgroupdesc_location" msgid="1995955142118450685">"энэ төхөөрөмжийн байршилд хандалт хийх"</string>
<string name="permgrouplab_calendar" msgid="6426860926123033230">"Календарь"</string>
- <string name="permgroupdesc_calendar" msgid="6762751063361489379">"Хуанли руу хандах"</string>
+ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"Календарь руу хандах"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"Мессеж"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS мессежийг илгээх, харах"</string>
<string name="permgrouplab_storage" msgid="1938416135375282333">"Файл болон мeдиа"</string>
@@ -427,14 +427,14 @@
<string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"Апп нь таны утасны ирсэн гарсан дуудлага зэргийг агуулсан дуудлагын логыг өөрчлөх боломжтой. Хортой апп нь энийг ашиглан таны дуудлагын логыг өөрчлөх болон арилгах боломжтой."</string>
<string name="permlab_bodySensors" msgid="3411035315357380862">"биеийн мэдрэгчид хандах (зүрхний хэмнэл шалгагч г.м)"</string>
<string name="permdesc_bodySensors" product="default" msgid="2365357960407973997">"Апп-т таны зүрхний цохилт гэх мэт биеийн байдлыг хянадаг мэдрэгчдийн датанд хандалт хийх боломж олгоно."</string>
- <string name="permlab_readCalendar" msgid="6408654259475396200">"Хуанлийн арга хэмжээ, дэлгэрэнгүйг унших"</string>
- <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Энэ апп таны таблетад хадгалсан хуанлийн бүх арга хэмжээг унших, хуанлийн өгөгдлийг хуваалцах, хадгалах боломжтой."</string>
+ <string name="permlab_readCalendar" msgid="6408654259475396200">"Календарийн арга хэмжээ, дэлгэрэнгүйг унших"</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Энэ апп таны таблетад хадгалсан календарийн бүх арга хэмжээг унших, календарийн өгөгдлийг хуваалцах, хадгалах боломжтой."</string>
<string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Энэ апп таны Android TV төхөөрөмжид хадгалсан календарийн бүх арга хэмжээг унших болон таны календарийн өгөгдлийг хуваалцах эсвэл хадгалах боломжтой."</string>
- <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"Энэ апп таны утсанд хадгалсан хуанлийн бүх арга хэмжээг унших, хуанлийн өгөгдлийг хуваалцах, хадгалах боломжтой."</string>
+ <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"Энэ апп таны утсанд хадгалсан календарийн бүх арга хэмжээг унших, календарийн өгөгдлийг хуваалцах, хадгалах боломжтой."</string>
<string name="permlab_writeCalendar" msgid="6422137308329578076">"календарын хуваарийг нэмэх эсвэл өөрчлөх болон эзэмшигчид мэдэгдэлгүйгээр зочидруу имэйл илгээх"</string>
- <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"Энэ апп таны таблет дээр хуанлийн арга хэмжээг нэмэх, устгах, эсвэл өөрчлөх боломжтой. Энэ апп нь хуанли эзэмшигчээс мессеж илгээсэн мэт харагдах, эсвэл эзэмшигчид мэдэгдэлгүйгээр арга хэмжээг өөрчлөх боломжтой."</string>
+ <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"Энэ апп таны таблет дээр календарийн арга хэмжээг нэмэх, устгах, эсвэл өөрчлөх боломжтой. Энэ апп нь календарь эзэмшигчээс мессеж илгээсэн мэт харагдах, эсвэл эзэмшигчид мэдэгдэлгүйгээр арга хэмжээг өөрчлөх боломжтой."</string>
<string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"Энэ апп таны Android TV төхөөрөмжид календарийн арга хэмжээ нэмэх, үүнийг устгах, эсвэл өөрчлөх боломжтой. Энэ апп календарийн өмчлөгчөөс ирсэн мэт харагдаж болох мессеж илгээх эсвэл арга хэмжээг өмчлөгчид нь мэдэгдэлгүйгээр өөрчлөх боломжтой."</string>
- <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"Энэ апп таны утсанд хуанлийн арга хэмжээг нэмэх, устгах, эсвэл өөрчлөх боломжтой. Энэ апп нь хуанли эзэмшигчээс мессеж илгээсэн мэт харагдах, эсвэл эзэмшигчид мэдэгдэлгүйгээр арга хэмжээг өөрчлөх боломжтой."</string>
+ <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"Энэ апп таны утсанд календарийн арга хэмжээг нэмэх, устгах, эсвэл өөрчлөх боломжтой. Энэ апп нь календарь эзэмшигчээс мессеж илгээсэн мэт харагдах, эсвэл эзэмшигчид мэдэгдэлгүйгээр арга хэмжээг өөрчлөх боломжтой."</string>
<string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"байршил нийлүүлэгчийн нэмэлт тушаалд хандах"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"Апп нь байршил нийлүүлэгчийн нэмэлт тушаалд хандах боломжтой. Энэ нь апп-д GPS эсвэл бусад байршлын үйлчилгээний ажиллагаанд нөлөөлөх боломжийг олгоно."</string>
<string name="permlab_accessFineLocation" msgid="6426318438195622966">"нарийвчилсан байршилд зөвхөн нүүр хэсэгт хандах"</string>
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Хурууны хээний дүрс"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"царайгаар түгжээ тайлах техник хангамжийг удирдах"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Аппад царайны загварыг ашиглахын тулд нэмэх эсвэл устгах аргыг идэвхжүүлэхийг зөвшөөрдөг."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"царайгаар түгжээ тайлах техник хангамж ашиглах"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Аппад царайгаар түгжээ тайлах техник хангамжийг баталгаажуулалтад ашиглахыг зөвшөөрдөг"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Царайгаар түгжээ тайлах"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Царайгаа дахин бүртгүүлнэ үү"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Танилтыг сайжруулахын тулд царайгаа дахин бүртгүүлнэ үү"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Царайгаар түгжээ тайлах онцлогийг тохируулна уу"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Утас руугаа харж түгжээг нь тайлна уу"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Түгжээ тайлах илүү олон арга тохируулна уу"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Хурууны хээ нэмэхийн тулд товшино уу"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Царайг бататгаж чадсангүй. Техник хангамж боломжгүй байна."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Царайгаар түгжээ тайлахыг дахин оролдоно уу."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Царайн шинэ өгөгдлийг хадгалж чадсангүй. Эхлээд хуучин өгөгдлийг устгана уу."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Царайны үйл ажиллагааг цуцаллаа."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Хэрэглэгч царайгаар түгжээ тайлахыг цуцалсан."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Хэт олон удаа оролдлоо. Дараа дахин оролдоно уу."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Хэтэрхий олон удаа оролдлоо. Царайгаар түгжээ тайлахыг идэвхгүй болголоо."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Царайг бататгаж чадсангүй. Дахин оролдоно уу."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Та царайгаар түгжээ тайлахыг тохируулаагүй байна."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Царайгаар түгжээ тайлахыг энэ төхөөрөмж дээр дэмждэггүй."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Мэдрэгчийг түр хугацаанд идэвхгүй болгосон."</string>
<string name="face_name_template" msgid="3877037340223318119">"Царай <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Царайгаар түгжээ тайлахыг ашиглах"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Царайгаар түгжээ тайлах эсвэл дэлгэцийн түгжээ ашиглах"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Үргэлжлүүлэхийн тулд царайгаа ашиглана уу"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Үргэлжлүүлэхийн тулд царай эсвэл дэлгэцийн түгжээгээ ашиглана уу"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Түгжээгүй хэсгийг өргөсгөх."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Тайлах гулсуулалт."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Тайлах хээ."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Царайгаар түгжээ тайлах"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Тайлах пин."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Sim-н пин кодыг тайлна уу."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Sim-н Puk кодыг тайлна уу."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Унтраах"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Нэмэлт мэдээлэл авах"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Сайжруулсан мэдэгдэл нь Android 12 дахь Android-н Орчинтой тохирсон мэдэгдлийг орлосон. Энэ онцлог нь санал болгосон үйлдлүүд болон хариунуудыг харуулж, таны мэдэгдлийг цэгцэлнэ.\n\nСайжруулсан мэдэгдэл нь харилцагчийн нэр, мессеж зэрэг хувийн мэдээллийг оруулаад мэдэгдлийн контентод хандах боломжтой. Энэ онцлог мөн утасны дуудлагад хариулах болон Бүү саад бол горимыг хянах зэргээр мэдэгдлийг хаах эсвэл түүнд хариулах боломжтой."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Хэвшлийн горимын мэдээллийн мэдэгдэл"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батарей ихэвчлэн цэнэглэдэг хугацаанаас өмнө дуусаж болзошгүй"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Батарейн ажиллах хугацааг уртасгахын тулд Батарей хэмнэгчийг идэвхжүүллээ"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 53259c5..0756ce2 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"फिंगरप्रिंट आयकन"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"फेस अनलॉक हार्डवेअर व्यवस्थापित करा"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"ॲपला वापरासाठी चेहरा टेम्पलेट जोडण्याच्या आणि हटवण्याच्या पद्धती जारी करू देते."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"फेस अनलॉक हार्डवेअर वापरा"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"अॅपला ऑथेंटिकेशनसाठी फेस अनलॉक हार्डवेअर वापरण्याची अनुमती देते"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"फेस अनलॉक"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"तुमच्या चेहऱ्याची पुन्हा नोंदणी करा"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"ओळखण्यामध्ये सुधारणा करण्यासाठी, कृपया तुमच्या चेहऱ्याची पुन्हा नोंदणी करा"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"फेस अनलॉक सेट करा"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"तुमच्या फोनकडे पाहून तो अनलॉक करा"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"अनलॉक करण्याच्या आणखी पद्धती सेट करा"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"फिंगरप्रिंट जोडण्यासाठी टॅप करा"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"चेहरा पडताळू शकत नाही. हार्डवेअर उपलब्ध नाही."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"फेस अनलॉकचा पुन्हा प्रयत्न करा."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"नवीन फेस डेटा स्टोअर करू शकत नाही. आधी जुना हटवा."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"चेहरा ऑपरेशन रद्द केले गेले."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"वापरकर्त्याने फेस अनलॉक रद्द केले आहे."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"खूप जास्त प्रयत्न केले. नंतर पुन्हा प्रयत्न करा."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"बरेच प्रयत्न. फेस अनलॉक बंद केले आहे."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"चेहरा पडताळणी करू शकत नाही. पुन्हा प्रयत्न करा."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"तुम्ही फेस अनलॉक सेट केले नाही."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"या डिव्हाइसवर फेस अनलॉकला सपोर्ट नाही."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"सेन्सर तात्पुरता बंद केला आहे."</string>
<string name="face_name_template" msgid="3877037340223318119">"चेहरा <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"फेस अनलॉक वापरा"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"फेस किंवा स्क्रीन लॉक वापरा"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"पुढे सुरू ठेवण्यासाठी तुमचा चेहरा वापरा"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"पुढे सुरू ठेवण्यासाठी तुमचा चेहरा किंवा स्क्रीन लॉक वापरा"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"अनलॉक क्षेत्र विस्तृत करा."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"स्लाइड अनलॉक."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"पॅटर्न अनलॉक."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"फेस अनलॉक."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"पिन अनलॉक."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"सिम पिन अनलॉक करा"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"सिम PUK अनलॉक करा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 76be13f..e6c4171 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon cap jari"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"urus perkakasan buka kunci wajah"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Membenarkan apl menggunakan kaedah untuk menambahkan dan memadamkan templat wajah untuk digunakan."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"gunakan perkakasan buka kunci wajah"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Membenarkan apl menggunakan perkakasan buka kunci wajah untuk pengesahan"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Buka kunci wajah"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Daftarkan semula wajah anda"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Untuk meningkatkan pengecaman, sila daftarkan semula wajah anda"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Sediakan buka kunci wajah"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Buka kunci telefon anda dengan melihat telefon anda"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Sediakan lebih banyak cara untuk membuka kunci"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Ketik untuk menambahkan cap jari"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Tdk dpt sahkan wajah. Perkakasan tidak tersedia."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Cuba buka kunci wajah sekali lagi."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Tdk dpt menyimpan data wajah baharu. Padamkan yg lama dahulu."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Pengendalian wajah dibatalkan."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Buka kunci wajah dibatalkan oleh pengguna."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Terlalu banyak percubaan. Cuba sebentar lagi."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Terlalu banyak percubaan. Buka kunci wajah dilumpuhkan."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Tidak dapat mengesahkan wajah. Cuba lagi."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Anda belum menyediakan buka kunci wajah."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Buka kunci wajah tidak disokong pada peranti ini."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Penderia dilumpuhkan sementara."</string>
<string name="face_name_template" msgid="3877037340223318119">"Wajah <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Gunakan buka kunci wajah"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Gunakan kunci wajah atau skrin"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Gunakan wajah untuk teruskan"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gunakan wajah atau kunci skrin anda untuk meneruskan"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Kembangkan bahagian buka kunci."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Buka kunci luncur."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Buka kunci corak."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Buka Kunci Wajah"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Buka kunci pin."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Buka kunci Pin Sim."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Buka kunci Puk Sim."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Matikan"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Ketahui lebih lanjut"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Pemberitahuan yang dipertingkatkan menggantikan Pemberitahuan Boleh Suai Android dalam Android 12. Ciri ini menunjukkan tindakan dan balasan yang dicadangkan, serta mengatur pemberitahuan anda.\n\nPemberitahuan yang dipertingkatkan dapat mengakses kandungan pemberitahuan, termasuk maklumat peribadi seperti nama kenalan dan mesej. Ciri ini juga dapat mengetepikan atau membalas pemberitahuan, seperti menjawab panggilan telefon dan mengawal Jangan Ganggu."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Pemberitahuan maklumat Mod Rutin"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateri mungkin habis sebelum pengecasan biasa"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Penjimat Bateri diaktifkan untuk memanjangkan hayat bateri"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index bf24d7c..12f2f39 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"လက်ဗွေ သင်္ကေတ"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"မျက်နှာပြလော့ခ်ဖွင့်သည့် စက်ပစ္စည်းကို စီမံခြင်း"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"အသုံးပြုရန်အတွက် မျက်နှာပုံစံထည့်ရန် (သို့) ဖျက်ရန်နည်းလမ်းကို အက်ပ်အား သုံးခွင့်ပြုသည်။"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"မျက်နှာပြ လော့ခ်ဖွင့်သည့် စက်ပစ္စည်းကို သုံးပါ"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"အထောက်အထားစိစစ်ရန်အတွက် ဤအက်ပ်အား မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း စက်ပစ္စည်းကိုသုံးခွင့်ပြုသည်"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"သင့်မျက်နှာကို စာရင်းပြန်သွင်းပါ"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"ပိုမှတ်မိစေရန် သင့်မျက်နှာကို စာရင်းပြန်သွင်းပါ"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း စနစ်ထည့်သွင်းပါ"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"သင့်ဖုန်းကိုကြည့်၍ သော့ဖွင့်ပါ"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"သော့ဖွင့်ရန် နောက်ထပ်နည်းလမ်းများကို စနစ်ထည့်သွင်းပါ"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"လက်ဗွေထည့်ရန် တို့ပါ"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"မျက်နှာကို အတည်ပြု၍ မရပါ။ ဟာ့ဒ်ဝဲ မရနိုင်ပါ။"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်းကို ထပ်စမ်းကြည့်ပါ။"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"မျက်နှာဒေတာအသစ် သိမ်း၍မရပါ။ အဟောင်းကို အရင်ဖျက်ပါ။"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"မျက်နှာ ဆောင်ရွက်ခြင်းကို ပယ်ဖျက်လိုက်ပါပြီ။"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"မှတ်နှာပြ လော့ခ်ဖွင့်ခြင်းကို မလုပ်တော့ပါ။"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"အကြိမ်များစွာ စမ်းပြီးပါပြီ။ နောက်မှထပ်စမ်းပါ။"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"စမ်းသပ်ကြိမ် များနေပြီ။ မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း ပိတ်လိုက်ပါပြီ။"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"မျက်နှာကို အတည်ပြု၍ မရပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း ထည့်သွင်းမထားပါ"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"ဤစက်ပစ္စည်းတွင် မျက်နှာပြ လော့ခ်ဖွင့်ခြင်းကို သုံး၍မရပါ။"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"အာရုံခံကိရိယာကို ယာယီပိတ်ထားသည်။"</string>
<string name="face_name_template" msgid="3877037340223318119">"မျက်နှာ <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"မျက်နှာပြ လော့ခ်ဖွင့်ရန်"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"မျက်နှာမှတ်သော့ဖွင့်ခြင်း (သို့) ဖန်သားပြင်လော့ခ်ချခြင်းကို သုံးခြင်း"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"ရှေ့ဆက်ရန် သင့်မျက်နှာကို သုံးပါ"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ရှေ့ဆက်ရန် သင်၏ မျက်နှာ (သို့) ဖန်သားပြင်လော့ခ်ကို သုံးပါ"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"သော့မချထားသာ နယ်ပယ်ကို ချဲ့ပါ"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"ဘေးတိုက်ပွတ်ဆွဲ၍ သော့ဖွင့်ခြင်း"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"ပုံစံဖြင့် သော့ဖွင့်ခြင်း"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"ပင်နံပါတ်ဖြင့် သော့ဖွင့်ခြင်း"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"ဆင်းမ်ကဒ် ပင်နံပါတ်လော့ခ်ဖွင့်ပါ။"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"ဆင်းမ်ကဒ် Puk လော့ခ်ဖွင့်ပါ။"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ပိတ်ရန်"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ပိုမိုလေ့လာရန်"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12 တွင် ‘Android အလိုက်သင့် အကြောင်းကြားချက်များ’ ကို အဆင့်မြင့် အကြောင်းကြားချက်များဖြင့် အစားထိုးထားသည်။ ဤဝန်ဆောင်မှုက အကြံပြုထားသော လုပ်ဆောင်ချက်နှင့် ပြန်စာများကို ပြပေးပြီး သင်၏အကြောင်းကြားချက်များကို စီစဉ်ပေးသည်။\n\nအဆင့်မြင့် အကြောင်းကြားချက်များက အဆက်အသွယ်အမည်နှင့် မက်ဆေ့ဂျ်များကဲ့သို့ ကိုယ်ရေးကိုယ်တာအချက်လက်များ အပါအဝင် အကြောင်းကြားချက် အကြောင်းအရာကို သုံးနိုင်သည်။ ဤဝန်ဆောင်မှုက ဖုန်းခေါ်ဆိုမှုများ ဖြေခြင်းနှင့် ‘မနှောင့်ယှက်ရ’ ကို ထိန်းချုပ်ခြင်းကဲ့သို့ အကြောင်းကြားချက်များကို ပယ်နိုင်သည် (သို့) တုံ့ပြန်နိုင်သည်။"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ပုံမှန်မုဒ်အတွက် အချက်အလက်ပြသည့် အကြောင်းကြားချက်"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ပုံမှန်အားသွင်းမှုမပြုလုပ်မီ ဘက်ထရီကုန်သွားနိုင်သည်"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ဘက်ထရီသက်တမ်းကို တိုးမြှင့်ရန် \'ဘက်ထရီအားထိန်း\' စတင်ပြီးပါပြီ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 913afc3..0c724bf 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon for fingeravtrykk"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"administrere maskinvare for Ansiktslås"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Lar appen bruke metoder for å legge til og slette ansiktmaler for bruk."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"bruk maskinvare for Ansiktslås"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Lar appen bruke maskinvare for Ansiktslås til autentisering"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Ansiktslås"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Registrer ansiktet ditt på nytt"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"For å forbedre gjenkjennelse, registrer ansiktet ditt på nytt"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Konfigurer ansiktslås"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Lås opp telefonen ved å se på den"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Konfigurer flere måter å låse opp på"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Trykk for å legge til et fingeravtrykk"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Kan ikke bekrefte ansikt. Utilgjengelig maskinvare."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Prøv Ansiktslås igjen."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Kan ikke lagre nye ansiktsdata. Slett gamle data først."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Ansikt-operasjonen ble avbrutt."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Ansiktslås ble avbrutt av brukeren."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"For mange forsøk. Prøv igjen senere."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"For mange forsøk. Ansiktslås er slått av."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Kan ikke bekrefte ansiktet. Prøv igjen."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Du har ikke konfigurert Ansiktslås."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Ansiktslås støttes ikke på denne enheten"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensoren er midlertidig slått av."</string>
<string name="face_name_template" msgid="3877037340223318119">"Ansikt <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Bruk ansiktslås"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Bruk ansikts- eller skjermlås"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Bruk ansiktet for å fortsette"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Bruk ansikts- eller skjermlåsen for å fortsette"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Vis opplåsingsfeltet."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Opplåsning ved å dra med fingeren."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Mønsteropplåsning."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Ansiktslås"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PIN-opplåsning."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"PIN-opplåsing for SIM-kort."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"PUK-opplåsing for SIM-kort."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Slå av"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Finn ut mer"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Forbedrede varsler erstatter tilpassede Android-varsler i Android 12. Denne funksjonen viser foreslåtte handlinger og svar og organiserer varslene dine.\n\nForbedrede varsler har tilgang til varselinnhold, inkludert personopplysninger som kontaktnavn og meldinger. Funksjonen kan også avvise og svare på varsler, for eksempel svare på anrop og kontrollere «Ikke forstyrr»."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Varsel med informasjon om rutinemodus"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batteriet kan gå tomt før den vanlige ladingen"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterisparing er aktivert for å forlenge batterilevetiden"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index f7acb7d..08154c9 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"फिंगरप्रिन्ट आइकन"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"फेस अनलकको हार्डवेयर व्यवस्थित गर्नुहोस्"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"एपलाई प्रयोगका लागि अनुहार टेम्प्लेट थप्न र मेटाउने तरिका आह्वान गर्न अनुमति दिन्छ।"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"फेस अनलकको हार्डवेयर प्रयोग गर्नुहोस्"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"एपलाई प्रमाणीकरणका लागि फेस अनलकको हार्डवेयर प्रयोग गर्न अनुमति दिन्छ"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"फेस अनलक"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"आफ्नो अनुहार पुनः दर्ता गर्नुहोस्"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"अनुहार पहिचानको गुणस्तर सुधार गर्न कृपया आफ्नो अनुहार पुनः दर्ता गर्नुहोस्"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"फेस अनलक सेटअप गर्नुहोस्"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"फोनमा हेरेकै भरमा फोन अनलक गर्नुहोस्"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"अनलक गर्ने अन्य तरिकाहरू सेटअप गर्नुहोस्"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"फिंगरप्रिन्ट हाल्न ट्याप गर्नुहोस्"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"अनुहार पुष्टि गर्न सकिएन। हार्डवेयर उपलब्ध छैन।"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"फेरि फेस अनलक प्रयोग गरी हेर्नुहोस्।"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"अनुहारसम्बन्धी नयाँ डेटा भण्डारण गर्न सकिएन। पहिले कुनै पुरानो डेटा मेटाउनुहोस्।"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"अनुहार पहिचान रद्द गरियो।"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"प्रयोगकर्ताले फेस अनलक रद्द गर्नुभयो।"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"धेरैपटक प्रयासहरू भए। पछि फेरि प्रयास गर्नुहोस्।"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"अत्यधिक प्रयासहरू भए। फेस अनलक असक्षम पारियो।"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"अनुहार पुष्टि गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"तपाईंले फेस अनलक सुविधा सेट अप गर्नुभएको छैन।"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"यस डिभाइसमा फेस अनलक सुविधा प्रयोग गर्न मिल्दैन।"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"केही समयका लागि सेन्सर असक्षम पारियो।"</string>
<string name="face_name_template" msgid="3877037340223318119">"अनुहार <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"फेस अनलक प्रयोग गर्नुहोस्"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"फेस अनलक वा स्क्रिन लक प्रयोग गर्नुहोस्"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"जारी राख्न आफ्नो अनुहारको सहायताले पुष्टि गर्नुहोस्"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"जारी राख्न आफ्नो फेस वा स्क्रिन लक प्रयोग गरी पुष्टि गर्नुहोस्"</string>
@@ -733,7 +739,7 @@
<string name="policylab_resetPassword" msgid="214556238645096520">"स्क्रिन लक परिवर्तन गर्ने"</string>
<string name="policydesc_resetPassword" msgid="4626419138439341851">"स्क्रिन लक परिवर्तन गर्नुहोस्।"</string>
<string name="policylab_forceLock" msgid="7360335502968476434">"स्क्रिन लक गर्ने"</string>
- <string name="policydesc_forceLock" msgid="1008844760853899693">"कसरी र कहिले स्क्रिन लक गर्ने नियन्त्रण गर्नुहोस्।"</string>
+ <string name="policydesc_forceLock" msgid="1008844760853899693">"कसरी र कहिले स्क्रिन लक गर्ने भन्ने कुरा सेट गर्न"</string>
<string name="policylab_wipeData" msgid="1359485247727537311">"सबै डेटा मेट्ने"</string>
<string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"एउटा फ्याक्ट्रि डेटा रिसेट गरेर चेतावनी नआउँदै ट्याबल्टको डेटा मेट्नुहोस्।"</string>
<string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"फ्याक्ट्री डेटा रिसेट गरेर चेतावनी नदिइकन आफ्नो Android टिभी डिभाइसको डेटा मेटाउनुहोस्।"</string>
@@ -751,7 +757,7 @@
<string name="policylab_disableCamera" msgid="5749486347810162018">"क्यामेरालाई असक्षम गराउनुहोस्"</string>
<string name="policydesc_disableCamera" msgid="3204405908799676104">"सबै उपकरण क्यामराहरूको प्रयोग रोक्नुहोस्"</string>
<string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"स्क्रिन लकका केही सुविधा असक्षम पार्ने"</string>
- <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"केही स्क्रिन लक सुविधाहरूको प्रयोगमा रोक लगाउनुहोस्।"</string>
+ <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"स्क्रिन लकका केही सुविधाहरूको प्रयोगमा रोक लगाउन।"</string>
<string-array name="phoneTypes">
<item msgid="8996339953292723951">"गृह"</item>
<item msgid="7740243458912727194">"मोबाइल"</item>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"अनलक क्षेत्र बढाउनुहोस्।"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"स्लाइड अनलक।"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"ढाँचा अनलक।"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"फेस अनलक"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin अनलक"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Sim को Pin मार्फत अनलक गर्ने प्रक्रिया।"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Sim को Puk मार्फत अनलक गर्ने प्रक्रिया।"</string>
@@ -1862,7 +1869,7 @@
<string name="managed_profile_label_badge" msgid="6762559569999499495">"कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_2" msgid="5673187309555352550">"कार्यालयको दोस्रो <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="6882151970556391957">"कार्यालयको तेस्रो <xliff:g id="LABEL">%1$s</xliff:g>"</string>
- <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"पिन निकाल्नुअघि PIN सोध्नुहोस्"</string>
+ <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"अनपिन गर्नुअघि PIN मागियोस्"</string>
<string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"अनपिन गर्नअघि अनलक प्याटर्न माग्नुहोस्"</string>
<string name="lock_to_app_unlock_password" msgid="9126722403506560473">"पिन निकाल्नुअघि पासवर्ड सोध्नुहोस्"</string>
<string name="package_installed_device_owner" msgid="7035926868974878525">"तपाईंका प्रशासकले स्थापना गर्नुभएको"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ठिक छ"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"अफ गर्नुहोस्"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"थप जान्नुहोस्"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android १२ मा Android को अनुकूल पार्न मिल्ने सूचनाहरू नामक सुविधालाई परिष्कृत सूचनाहरू नामक सुविधाले प्रतिस्थापन गरेको छ। यो सुविधाले कारबाही तथा जवाफसम्बन्धी सुझाव देखाउँछ र तपाईंका सूचनाहरू व्यवस्थित गर्छ।\n\nपरिष्कृत सूचनाहरू नामक सुविधाले सूचनामा उल्लिखित सम्पर्क व्यक्तिको नाम र म्यासेज जस्ता व्यक्तिगत जानकारीलगायतका सामग्री हेर्न तथा प्रयोग गर्न सक्छ। यो सुविधाले फोन उठाउने तथा \'बाधा नपुऱ्याउनुहोस्\' मोड नियन्त्रण गर्ने कार्यसहित सूचनाहरू हटाउने वा सूचनाहरूको जवाफ दिने कार्य पनि गर्न सक्छ।"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"दिनचर्या मोडको जानकारीमूलक सूचना"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"प्रायः चार्ज गर्ने समय हुनुभन्दा पहिले नै ब्याट्री सकिन सक्छ"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ब्याट्रीको आयु बढाउन ब्याट्री सेभर सक्रिय गरियो"</string>
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index baffa5a..816ddd4 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -17,14 +17,6 @@
NOTE: You might also want to edit: packages/SystemUI/res/values-night/colors.xml
-->
<resources>
- <!-- The primary text color if the text is on top of a dark background.
- This is also affects colorized notifications with dark backgrounds. -->
- <color name="notification_primary_text_color_dark">#ddffffff</color>
-
- <!-- The secondary text color if the text is on top of a dark background. -->
- <color name="notification_secondary_text_color_dark">#b2ffffff</color>
-
- <color name="notification_default_color_dark">#ddffffff</color>
<color name="notification_primary_text_color_current">@color/notification_primary_text_color_dark</color>
<color name="notification_secondary_text_color_current">@color/notification_secondary_text_color_dark</color>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index cf7f4cf..3c1dc50 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Vingerafdruk-icoon"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"hardware voor ontgrendelen via gezichtsherkenning beheren"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Hiermee kan de app methoden aanroepen om gezichtstemplates toe te voegen en te verwijderen voor gebruik."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"hardware voor ontgrendelen via gezichtsherkenning gebruiken"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Hiermee kan de app hardware voor ontgrendelen via gezichtsherkenning gebruiken voor verificatie"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Ontgrendelen via gezichtsherkenning"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Je gezicht opnieuw registreren"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Registreer je gezicht opnieuw om de herkenning te verbeteren"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Stel ontgrendelen via gezichtsherkenning in"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Ontgrendel je telefoon door ernaar te kijken"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Stel meer manieren in om te ontgrendelen"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tik om een vingerafdruk toe te voegen"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Kan gezicht niet verifiëren. Hardware niet beschikbaar."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Probeer ontgrendelen via gezichtsherkenning opnieuw."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Kan nieuwe gezichten niet opslaan. Verwijder eerst een oude."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Bewerking voor gezichtsherkenning geannuleerd."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Ontgrendelen via gezichtsherkenning geannuleerd door gebruiker."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Te veel pogingen. Probeer het later opnieuw."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Te veel pogingen. Ontgrendelen via gezichtsherkenning staat uit."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Kan gezicht niet verifiëren. Probeer het nog eens."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Je hebt ontgrendelen via gezichtsherkenning niet ingesteld."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Ontgrendelen via gezichtsherkenning wordt niet ondersteund op dit apparaat."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor staat tijdelijk uit."</string>
<string name="face_name_template" msgid="3877037340223318119">"Gezicht <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Ontgrendelen via gezichtsherkenning gebruiken"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Gezicht of schermgrendeling gebruiken"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Gebruik je gezicht om door te gaan"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gebruik je gezicht of schermvergrendeling om door te gaan"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Ontgrendelingsgebied uitvouwen."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Ontgrendeling via schuiven."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Ontgrendeling via patroon."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Ontgrendelen via gezichtsherkenning"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Ontgrendeling via pincode."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Pincode-ontgrendeling voor simkaart."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Pukcode-ontgrendeling voor simkaart."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Uitzetten"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Meer informatie"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"In Android 12 hebben verbeterde meldingen aanpasbare Android-meldingen vervangen. Deze functie laat voorgestelde acties en antwoorden zien en ordent je meldingen.\n\nVerbeterde meldingen hebben toegang tot meldingscontent, waaronder persoonlijke informatie zoals contactnamen en berichten. Deze functie kan ook meldingen sluiten of erop reageren, zoals telefoongesprekken aannemen, en Niet storen beheren."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Informatiemelding voor routinemodus"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"De batterij raakt mogelijk leeg voordat deze normaal gesproken wordt opgeladen"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterijbesparing is geactiveerd om de batterijduur te verlengen"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 51d8f52..4191294 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ଟିପଚିହ୍ନ ଆଇକନ୍"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"ଫେସ୍ ଅନଲକ୍ ହାର୍ଡୱେର୍ ପରିଚାଳନା କରନ୍ତୁ"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"ବ୍ୟବହାର ପାଇଁ ଆପ୍କୁ ଫେସିଆଲ୍ ଟେମ୍ପଲେଟ୍ ଯୋଡିବା ଓ ଡିଲିଟ୍ ର ପଦ୍ଧତି ପାଇଁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ଫେସ୍ ଅନଲକ୍ ହାର୍ଡୱେର୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"ପ୍ରମାଣୀକରଣ ପାଇଁ ଫେସ୍ ଅନଲକ୍ ହାର୍ଡୱେର୍ର ବ୍ୟବହାର କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ଫେସ୍ ଅନଲକ୍"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"ଆପଣଙ୍କର ମୁହଁ ପୁଣି-ଏନ୍ରୋଲ୍ କରନ୍ତୁ"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"ଚିହ୍ନଟକରଣକୁ ଉନ୍ନତ କରିବା ପାଇଁ, ଦୟାକରି ଆପଣଙ୍କର ମୁହଁ ପୁଣି-ଏନ୍ରୋଲ୍ କରନ୍ତୁ।"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"ଫେସ୍ ଅନଲକ୍ ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"ଫୋନକୁ ଦେଖି ଏହାକୁ ଅନଲକ୍ କରନ୍ତୁ"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"ଅନଲକ୍ କରିବା ପାଇଁ ଆହୁରି ଅଧିକ ଉପାୟ ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"ଏକ ଟିପଚିହ୍ନ ଯୋଗ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ମୁହଁ ଚିହ୍ନଟ କରିପାରିଲା ନାହିଁ। ହାର୍ଡୱେୟାର୍ ଉପଲବ୍ଧ ନାହିଁ।"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"ଫେସ୍ ଅନଲକ୍ ପୁଣି ବ୍ୟବହାର କରି ଦେଖନ୍ତୁ।"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"ନୂଆ ମୁହଁ ଡାଟା ଷ୍ଟୋର୍ ହେବ ନାହିଁ। ପ୍ରଥମେ ପୁରୁଣାକୁ ଡିଲିଟ୍ କରନ୍ତୁ।"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"ଫେସ୍ର ଅପରେଶନ୍ କ୍ୟାନ୍ସଲ୍ ହୋଇଗଲା"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ଦ୍ୱାରା ଫେସ୍ ଅନଲକ୍ ବାତିଲ୍ କରାଯାଇଛି।"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"ବାରମ୍ବାର ଚେଷ୍ଟା। ପରେ ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"ଅତ୍ୟଧିକ ପ୍ରଚେଷ୍ଟା। ଫେସ୍ ଅନଲକ୍ ଅକ୍ଷମ ହୋଇଛି।"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"ମୁହଁ ଚିହ୍ନଟ କରିପାରିଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"ଆପଣ ଫେସ୍ ଅନଲକ୍ ସେଟ୍ ଅପ୍ କରିନାହାଁନ୍ତି।"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"ଏହି ଡିଭାଇସରେ ଫେସ୍ ଅନଲକ୍ ସମର୍ଥିତ ନୁହେଁ।"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"ସେନ୍ସରକୁ ଅସ୍ଥାୟୀ ଭାବେ ଅକ୍ଷମ କରାଯାଇଛି।"</string>
<string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g>ଙ୍କ ଫେସ୍"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"ଫେସ୍ ଅନଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ଫେସ୍ ବା ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ଚେହେରା ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ଚେହେରା କିମ୍ବା ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"ଅନଲକ୍ କ୍ଷେତ୍ରକୁ ବଢ଼ାନ୍ତୁ।"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"ସ୍ଲାଇଡ୍ ଅନଲକ୍।"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"ପାଟର୍ନ ଅନଲକ୍।"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"ଫେସ୍ ଅନଲକ୍।"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PIN ଅନଲକ୍।"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"PIN ଦ୍ଵାରା SIMକୁ ଅନଲକ୍ କରନ୍ତୁ।"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"PUK ଦ୍ଵାରା SIMକୁ ଅନଲକ୍ କରନ୍ତୁ।"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ଠିକ୍ ଅଛି"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ଅଧିକ ଜାଣନ୍ତୁ"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12ରେ Android ଆଡେପ୍ଟିଭ୍ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଉନ୍ନତ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକରେ ପରିବର୍ତ୍ତନ କରାଯାଇଛି। ଏହି ଫିଚର୍ ପ୍ରସ୍ତାବିତ କାର୍ଯ୍ୟ ଏବଂ ପ୍ରତ୍ୟୁତ୍ତରଗୁଡ଼ିକୁ ଦେଖାଏ ଏବଂ ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ବ୍ୟବସ୍ଥିତ କରେ।\n\nଉନ୍ନତ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଯୋଗାଯୋଗ ନାମ ଏବଂ ମେସେଜଗୁଡ଼ିକ ପରି ବ୍ୟକ୍ତିଗତ ସୂଚନା ସମେତ ବିଜ୍ଞପ୍ତିର ବିଷୟବସ୍ତୁକୁ ଆକ୍ସେସ୍ କରିପାରିବ। ଏହି ଫିଚର୍ ଫୋନ୍ କଲଗୁଡ଼ିକର ଉତ୍ତର ଦେବା ଏବଂ \'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\'କୁ ନିୟନ୍ତ୍ରଣ କରିବା ପରି, ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ମଧ୍ୟ ଖାରଜ କରିପାରିବ କିମ୍ବା ସେଗୁଡ଼ିକର ଉତ୍ତର ଦେଇପାରିବ।"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ନିୟମିତ ମୋଡ୍ ସୂଚନା ବିଜ୍ଞପ୍ତି"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ସାଧାରଣ ଭାବରେ ଚାର୍ଜ୍ କରିବା ପୂର୍ବରୁ ବ୍ୟାଟେରୀ ସରିଯାଇପାରେ"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ବ୍ୟାଟେରୀର ସମୟକୁ ବଢ଼ାଇବା ପାଇଁ ବ୍ୟଟେରୀ ସେଭର୍କୁ କାର୍ଯ୍ୟକାରୀ କରାଯାଇଛି"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 037ee60..3c198f0 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਪ੍ਰਤੀਕ"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"ਫ਼ੇਸ ਅਣਲਾਕ ਹਾਰਡਵੇਅਰ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"ਐਪ ਨੂੰ ਵਰਤਣ ਲਈ ਚਿਹਰਾ ਟੈਮਪਲੇਟ ਸ਼ਾਮਲ ਕਰਨ ਜਾਂ ਮਿਟਾਉਣ ਦੀਆਂ ਵਿਧੀਆਂ ਦੀ ਬੇਨਤੀ ਕਰਨ ਦਿੰਦੀ ਹੈ।"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ਫ਼ੇਸ ਅਣਲਾਕ ਹਾਰਡਵੇਅਰ ਵਰਤੋ"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"ਐਪ ਨੂੰ ਪ੍ਰਮਾਣੀਕਰਨ ਲਈ ਫ਼ੇਸ ਅਣਲਾਕ ਹਾਰਡਵੇਅਰ ਵਰਤਣ ਦਿੰਦੀ ਹੈ"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ਫ਼ੇਸ ਅਣਲਾਕ"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"ਆਪਣਾ ਚਿਹਰਾ ਮੁੜ-ਦਰਜ ਕਰੋ"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"ਪਛਾਣ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ, ਕਿਰਪਾ ਕਰਕੇ ਆਪਣੇ ਚਿਹਰੇ ਨੂੰ ਮੁੜ-ਦਰਜ ਕਰੋ"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"ਫ਼ੇਸ ਅਣਲਾਕ ਸੈੱਟਅੱਪ ਕਰੋ"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"ਆਪਣੇ ਫ਼ੋਨ ਵੱਲ ਦੇਖ ਕੇ ਇਸਨੂੰ ਅਣਲਾਕ ਕਰੋ"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"ਅਣਲਾਕ ਕਰਨ ਦੇ ਹੋਰ ਤਰੀਕਿਆਂ ਦਾ ਸੈੱਟਅੱਪ ਕਰੋ"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ਚਿਹਰੇ ਦੀ ਪੁਸ਼ਟੀ ਨਹੀਂ ਹੋ ਸਕੀ। ਹਾਰਡਵੇਅਰ ਉਪਲਬਧ ਨਹੀਂ।"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"ਫ਼ੇਸ ਅਣਲਾਕ ਦੁਬਾਰਾ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"ਨਵਾਂ ਚਿਹਰਾ ਡਾਟਾ ਸਟੋਰ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ। ਪਹਿਲਾਂ ਪੁਰਾਣਾ ਹਟਾਓ।"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"ਚਿਹਰਾ ਪਛਾਣਨ ਦੀ ਪ੍ਰਕਿਰਿਆ ਰੱਦ ਕੀਤੀ ਗਈ।"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"ਵਰਤੋਂਕਾਰ ਨੇ ਫ਼ੇਸ ਅਣਲਾਕ ਰੱਦ ਕੀਤਾ।"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"ਹੱਦੋਂ ਵੱਧ ਕੋਸ਼ਿਸ਼ਾਂ। ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"ਬਹੁਤ ਸਾਰੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ। ਫ਼ੇਸ ਅਣਲਾਕ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"ਚਿਹਰੇ ਦੀ ਪੁਸ਼ਟੀ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"ਤੁਸੀਂ ਫ਼ੇਸ ਅਣਲਾਕ ਸੈੱਟਅੱਪ ਨਹੀਂ ਕੀਤਾ ਹੈ।"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"ਇਸ ਡੀਵਾਈਸ ਵਿੱਚ ਫ਼ੇਸ ਅਣਲਾਕ ਦੀ ਸੁਵਿਧਾ ਨਹੀਂ ਹੈ।"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"ਸੈਂਸਰ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
<string name="face_name_template" msgid="3877037340223318119">"ਚਿਹਰਾ <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"ਫ਼ੇਸ ਅਣਲਾਕ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ਫ਼ੇਸ ਜਾਂ ਸਕ੍ਰੀਨ ਲਾਕ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣੇ ਚਿਹਰੇ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣਾ ਚਿਹਰਾ ਜਾਂ ਸਕ੍ਰੀਨ ਲਾਕ ਵਰਤੋ"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"ਅਣਲਾਕ ਖੇਤਰ ਦਾ ਵਿਸਤਾਰ ਕਰੋ।"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"ਅਣਲਾਕ ਸਲਾਈਡ ਕਰੋ।"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"ਪੈਟਰਨ ਅਣਲਾਕ।"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"ਫ਼ੇਸ ਅਣਲਾਕ।"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"ਪਿੰਨ ਅਣਲਾਕ।"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"ਸਿਮ ਪਿੰਨ ਅਣਲਾਕ।"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"ਸਿਮ Puk ਅਣਲਾਕ।"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ਠੀਕ ਹੈ"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ਬੰਦ ਕਰੋ"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ਹੋਰ ਜਾਣੋ"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12 ਵਿੱਚ ਵਿਸਤ੍ਰਿਤ ਸੂਚਨਾਵਾਂ ਨੂੰ Android ਅਡੈਪਟਿਵ ਸੂਚਨਾਵਾਂ ਨਾਲ ਬਦਲ ਦਿੱਤਾ ਗਿਆ। ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਸੁਝਾਈਆਂ ਗਈਆਂ ਕਾਰਵਾਈਆਂ ਅਤੇ ਜਵਾਬ ਦਿਖਾਉਂਦੀ ਹੈ ਅਤੇ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਵਿਵਸਥਿਤ ਕਰਦੀ ਹੈ।\n\nਵਿਸਤ੍ਰਿਤ ਸੂਚਨਾਵਾਂ ਸੂਚਨਾ ਸਮੱਗਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀਆਂ ਹਨ, ਜਿਸ ਵਿੱਚ ਸੰਪਰਕ ਨਾਮ ਅਤੇ ਸੁਨੇਹਿਆਂ ਵਰਗੀ ਨਿੱਜੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੈ। ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਸੂਚਨਾਵਾਂ ਨੂੰ ਖਾਰਜ ਵੀ ਕਰ ਸਕਦੀ ਹੈ ਜਾਂ ਸੂਚਨਾਵਾਂ ਦਾ ਜਵਾਬ ਵੀ ਦੇ ਸਕਦੀ ਹੈ, ਜਿਵੇਂ ਕਿ ਫ਼ੋਨ ਕਾਲਾਂ ਦਾ ਜਵਾਬ ਦੇਣਾ ਅਤੇ \'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਨੂੰ ਕੰਟਰੋਲ ਕਰਨਾ।"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"ਨਿਯਮਬੱਧ ਮੋਡ ਦੀ ਜਾਣਕਾਰੀ ਵਾਲੀ ਸੂਚਨਾ"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"ਬੈਟਰੀ ਚਾਰਜ ਕਰਨ ਦੇ ਮਿੱਥੇ ਸਮੇਂ ਤੋਂ ਪਹਿਲਾਂ ਸ਼ਾਇਦ ਬੈਟਰੀ ਖਤਮ ਹੋ ਜਾਵੇ"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 7d8bcac..22abb33 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -615,14 +615,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona odcisku palca"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"zarządzanie sprzętem do rozpoznawania twarzy"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Zezwala na aktywowanie przez aplikację metody dodawania i usuwania szablonów twarzy."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"używanie sprzętu do rozpoznawania twarzy"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Zezwala na używanie przez aplikację sprzętu do rozpoznawania twarzy w uwierzytelniania"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Rozpoznawanie twarzy"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Zarejestruj swoją twarz ponownie"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Aby poprawić rozpoznawanie, ponownie zarejestruj swoją twarz"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Skonfiguruj rozpoznawanie twarzy"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Popatrz na ekran telefonu, aby go odblokować"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Skonfiguruj więcej sposobów odblokowywania"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Kliknij, aby dodać odcisk palca"</string>
@@ -649,18 +647,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Nie można zweryfikować twarzy. Sprzęt niedostępny."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Spróbuj rozpoznawania twarzy ponownie."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Nie można przechowywać nowych danych twarzy. Usuń stare."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Analiza twarzy została anulowana."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Użytkownik anulował rozpoznawanie twarzy."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Zbyt wiele prób. Spróbuj ponownie później."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Zbyt wiele prób. Rozpoznawanie twarzy zostało wyłączone."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Nie można zweryfikować twarzy. Spróbuj ponownie."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Rozpoznawanie twarzy nie jest skonfigurowane."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"To urządzenie nie obsługuje rozpoznawania twarzy."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Czujnik jest tymczasowo wyłączony."</string>
<string name="face_name_template" msgid="3877037340223318119">"Twarz <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Używaj rozpoznawania twarzy"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Używaj rozpoznawania twarzy lub blokady ekranu"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Użyj skanu twarzy, aby kontynuować"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Aby kontynuować, użyj rozpoznawania twarzy lub blokady ekranu"</string>
@@ -963,7 +969,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Rozwiń obszar odblokowania."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Odblokowanie przesunięciem."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Odblokowanie wzorem."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Rozpoznawanie twarzy"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Odblokowanie kodem PIN."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Odblokowanie kodu PIN karty SIM."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Odblokowanie kodu PUK karty SIM."</string>
@@ -2161,8 +2168,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Wyłącz"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Więcej informacji"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"W Androidzie 12 ulepszone powiadomienia zastąpiły powiadomienia adaptacyjne. Ta funkcja pokazuje sugerowane działania i odpowiedzi oraz porządkuje powiadomienia.\n\nUlepszone powiadomienia mogą czytać wszystkie powiadomienia, w tym dane osobowe takie jak nazwy kontaktów i treść wiadomości. Funkcja może też zamykać powiadomienia oraz reagować na nie, np. odbierać połączenia telefoniczne i sterować trybem Nie przeszkadzać."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Powiadomienie z informacją o trybie rutynowym"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateria może się wyczerpać przed zwykłą porą ładowania"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Włączono Oszczędzanie baterii, by wydłużyć czas pracy na baterii"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 39fbdc7..564cec7 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"gerenciar hardware de desbloqueio facial"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Permite que o app execute métodos para adicionar e excluir modelos de rosto para uso."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"usar hardware de desbloqueio facial"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Permite que o app use o hardware de desbloqueio facial para autenticação"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Desbloqueio facial"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Registre seu rosto novamente"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Para melhorar o reconhecimento, registre seu rosto novamente"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Configure o desbloqueio facial"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Desbloqueie o smartphone olhando para ele"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configure mais formas de desbloquear a tela"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Toque para adicionar uma impressão digital"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Impossível verificar rosto. Hardware indisponível."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Tente usar o desbloqueio facial novamente."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Não é possível salvar dados faciais. Exclua dados antigos."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Operação facial cancelada."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Desbloqueio facial cancelado pelo usuário."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Excesso de tentativas. Tente novamente mais tarde."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Muitas tentativas. Desbloqueio facial desativado."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Não é possível verificar o rosto. Tente novamente."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"O desbloqueio facial não foi configurado."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"O desbloqueio facial não é compatível com este dispositivo."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor desativado temporariamente."</string>
<string name="face_name_template" msgid="3877037340223318119">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Usar desbloqueio facial"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Usar reconhecimento facial ou bloqueio de tela"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Use seu rosto para continuar"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use seu rosto ou o bloqueio de tela para continuar"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Expandir a área de desbloqueio."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Desbloqueio com deslize."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Desbloqueio com padrão."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Desbloqueio facial."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Desbloqueio com PIN."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Desbloqueio com PIN do chip."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Desbloqueio com PUK do chip."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desativar"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saiba mais"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"No Android 12, as notificações aprimoradas substituíram as notificações adaptáveis. Esse recurso exibe ações e respostas sugeridas, além de organizar suas notificações.\n\nAs notificações aprimoradas podem acessar o conteúdo das notificações, incluindo informações pessoais como nomes de contatos e mensagens. Elas também podem dispensar ou responder às notificações, como atender chamadas telefônicas e controlar o Não perturbe."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificação de informação do modo rotina"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"A bateria pode acabar antes da recarga normal"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"A Economia de bateria foi ativada para aumentar a duração da carga"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 48a1d9d..d38a49b 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"gerir hardware de Desbloqueio facial"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Permite à app invocar métodos para adicionar e eliminar modelos faciais para uso."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"utilizar hardware de Desbloqueio facial"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Permite que a app utilize hardware de Desbloqueio facial para autenticação"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Desbloqueio facial"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Volte a inscrever o seu rosto"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Para melhorar o reconhecimento, volte a inscrever o seu rosto."</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Configure o desbloqueio facial"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Desbloqueie o telemóvel ao olhar para ele"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configure mais formas de desbloquear"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Toque para adicionar uma impressão digital"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Não pode validar o rosto. Hardware não disponível."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Experimente de novo o Desbloqueio facial"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Não pode guardar novos dados de rostos. Elimine um antigo."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Operação de rosto cancelada."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Desbloqueio facial cancelado pelo utilizador"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Demasiadas tentativas. Tente novamente mais tarde."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Demasiadas tentativas. O Desbloqueio facial está desativado."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Não é possível validar o rosto. Tente novamente."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Não configurou o Desbloqueio facial."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Desbloqueio facial não suportado neste dispositivo."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor temporariamente desativado."</string>
<string name="face_name_template" msgid="3877037340223318119">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Utilizar o desbloqueio facial"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Utilizar o bloqueio através do rosto ou de ecrã"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Utilize o rosto para continuar"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilize o rosto ou o bloqueio de ecrã para continuar"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Expandir área de desbloqueio."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Desbloqueio através de deslize."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Desbloqueio através de sequência."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Desbloqueio facial"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Desbloqueio através de PIN."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Desbloqueio do SIM através de PIN."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Desbloqueio do PUK do SIM."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desativar"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saber mais"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"As notificações melhoradas substituíram as notificações adaptáveis do Android no Android 12. Esta funcionalidade mostra ações e respostas sugeridas e organiza as suas notificações.\n\nAs notificações melhoradas podem aceder a todo o conteúdo das notificações, incluindo informações pessoais como nomes de contactos e mensagens. Esta funcionalidade também pode ignorar ou responder a notificações, como atender chamadas telefónicas, e controlar o modo Não incomodar."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificação de informações do Modo rotina"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Pode ficar sem bateria antes do carregamento habitual"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Poupança de bateria ativada para prolongar a duração da bateria"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 39fbdc7..564cec7 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"gerenciar hardware de desbloqueio facial"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Permite que o app execute métodos para adicionar e excluir modelos de rosto para uso."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"usar hardware de desbloqueio facial"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Permite que o app use o hardware de desbloqueio facial para autenticação"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Desbloqueio facial"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Registre seu rosto novamente"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Para melhorar o reconhecimento, registre seu rosto novamente"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Configure o desbloqueio facial"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Desbloqueie o smartphone olhando para ele"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configure mais formas de desbloquear a tela"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Toque para adicionar uma impressão digital"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Impossível verificar rosto. Hardware indisponível."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Tente usar o desbloqueio facial novamente."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Não é possível salvar dados faciais. Exclua dados antigos."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Operação facial cancelada."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Desbloqueio facial cancelado pelo usuário."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Excesso de tentativas. Tente novamente mais tarde."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Muitas tentativas. Desbloqueio facial desativado."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Não é possível verificar o rosto. Tente novamente."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"O desbloqueio facial não foi configurado."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"O desbloqueio facial não é compatível com este dispositivo."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor desativado temporariamente."</string>
<string name="face_name_template" msgid="3877037340223318119">"Rosto <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Usar desbloqueio facial"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Usar reconhecimento facial ou bloqueio de tela"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Use seu rosto para continuar"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use seu rosto ou o bloqueio de tela para continuar"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Expandir a área de desbloqueio."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Desbloqueio com deslize."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Desbloqueio com padrão."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Desbloqueio facial."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Desbloqueio com PIN."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Desbloqueio com PIN do chip."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Desbloqueio com PUK do chip."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Desativar"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Saiba mais"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"No Android 12, as notificações aprimoradas substituíram as notificações adaptáveis. Esse recurso exibe ações e respostas sugeridas, além de organizar suas notificações.\n\nAs notificações aprimoradas podem acessar o conteúdo das notificações, incluindo informações pessoais como nomes de contatos e mensagens. Elas também podem dispensar ou responder às notificações, como atender chamadas telefônicas e controlar o Não perturbe."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificação de informação do modo rotina"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"A bateria pode acabar antes da recarga normal"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"A Economia de bateria foi ativada para aumentar a duração da carga"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 3fb344d..e57f12a 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -612,14 +612,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Pictograma amprentă"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"să gestioneze hardware de deblocare facială"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Permite aplicației să invoce metode pentru a adăuga și a șterge șabloane faciale pentru utilizare."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"să folosească hardware de deblocare facială"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Permite aplicației să folosească hardware de deblocare facială pentru autentificare"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Deblocare facială"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Reînregistrați-vă chipul"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Pentru a îmbunătăți recunoașterea, reînregistrați-vă chipul"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Configurați deblocarea facială"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Deblocați-vă telefonul uitându-vă la acesta"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configurați mai multe moduri de deblocare"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Atingeți ca să adăugați o amprentă"</string>
@@ -646,18 +644,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Nu se poate confirma fața. Hardware-ul nu este disponibil."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Încercați din nou deblocarea facială."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Nu se pot stoca date faciale noi. Ștergeți întâi unele vechi."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Operațiunea privind chipul a fost anulată."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Deblocarea facială este anulată de utilizator."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Prea multe încercări. Reîncercați mai târziu."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Prea multe încercări. Deblocarea facială este dezactivată."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Nu se poate confirma fața. Încercați din nou."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Nu ați configurat deblocarea facială."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Deblocarea facială nu este acceptată pe dispozitiv."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Senzorul este dezactivat temporar."</string>
<string name="face_name_template" msgid="3877037340223318119">"Chip <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Folosiți deblocarea facială"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Folosiți deblocarea facială sau ecranul de blocare"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Folosiți-vă chipul ca să continuați"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Folosiți-vă chipul sau blocarea ecranului pentru a continua"</string>
@@ -960,7 +966,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Extindeți zona de deblocare."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Deblocare prin glisare."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Deblocare cu model."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Deblocare facială."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Deblocare cu PIN."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Deblocare PIN pentru cardul SIM."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Deblocare PUK pentru cardul SIM."</string>
@@ -2128,8 +2135,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Dezactivați"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Aflați mai multe"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Notificările optimizate au înlocuit Notificările adaptive Android de pe Android 12. Această funcție afișează acțiuni și răspunsuri sugerate și vă organizează notificările.\n\nNotificările optimizate pot accesa conținutul notificărilor, inclusiv informații cu caracter personal, precum mesajele și numele persoanelor de contact. În plus, funcția poate să închidă sau să răspundă la notificări, de exemplu, să răspundă la apeluri telefonice și să gestioneze opțiunea Nu deranja."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificare pentru informații despre modul Rutină"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateria se poate descărca înainte de încărcarea obișnuită"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Economisirea bateriei este activată pentru a prelungi durata de funcționare a bateriei"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index c840e3f..35bc2a7 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -615,14 +615,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок отпечатка пальца"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"Управление аппаратным обеспечением для функции \"Фейсконтроль\""</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Приложение сможет добавлять и удалять шаблоны лиц."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"Использование аппаратного обеспечения для функции \"Фейсконтроль\""</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Приложение сможет использовать для аутентификации аппаратное обеспечение фейсконтроля."</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Фейсконтроль"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Зарегистрируйте лицо ещё раз"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Чтобы улучшить распознавание лица, зарегистрируйте его ещё раз"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Настройте фейсконтроль"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Вы сможете разблокировать телефон, просто посмотрев на него."</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Настройте другие способы разблокировки"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Нажмите, чтобы добавить отпечаток пальца."</string>
@@ -649,18 +647,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Не удалось распознать лицо. Сканер недоступен."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Попробуйте воспользоваться фейсконтролем ещё раз."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Недостаточно места. Удалите старые данные для распознавания."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Распознавание отменено"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Фейсконтроль: операция отменена пользователем."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Слишком много попыток. Повторите позже."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Слишком много попыток. Функция \"Фейсконтроль\" отключена."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Не удалось распознать лицо. Повторите попытку."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Вы не настроили фейсконтроль."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Это устройство не поддерживает функцию \"Фейсконтроль\"."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Датчик временно отключен."</string>
<string name="face_name_template" msgid="3877037340223318119">"Лицо <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Использовать фейсконтроль"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Использовать фейсконтроль или блокировку экрана"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Чтобы продолжить, используйте функцию фейсконтроля."</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Чтобы продолжить, посмотрите на экран или используйте данные для разблокировки."</string>
@@ -963,7 +969,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Развернуть области разблокировки"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Прокрутка"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Графический ключ"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Фейсконтроль"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PIN-код"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Разблокировка PIN-кода SIM-карты."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Разблокировка PUK-кода SIM-карты."</string>
@@ -2161,8 +2168,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ОК"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Отключить"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Подробнее"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"В Android 12 адаптивные уведомления заменены улучшенными. Эта функция упорядочивает все ваши уведомления и подсказывает ответы и действия.\n\nЕй доступно содержимое всех уведомлений, в том числе личная информация, такая как имена контактов и сообщения. Также эта функция может закрывать уведомления и нажимать кнопки в них, например отвечать на звонки или управлять режимом \"Не беспокоить\"."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Уведомление о батарее"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батарея может разрядиться"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Чтобы увеличить время работы от батареи, был включен режим энергосбережения."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 38f909c..8acc1092 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ඇඟිලි සලකුණු නිරූපකය"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"මුහුණෙන් අගුළු හැරීම දෘඪාංග කළමනා කරන්න"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"මුහුණු අච්චු එකතු කිරීමට සහ ඉවත් කිරීමට අදාළ ක්රම භාවිතය සඳහා මෙම යෙදුමට ඉඩ දෙයි."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"මුහුණෙන් අගුළු හැරීමේ දෘඪාංග භෘවිත කරන්න"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"සත්යාපනය සඳහා මුහුණෙන් අගුළු හැරීමේ දෘඪාංග භාවිත කිරීමට යෙදුමට ඉඩ දෙයි"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"මුහුණෙන් අගුළු හැරීම"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"ඔබේ මුහුණ යළි ලියාපදිංචි කරන්න"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"හඳුනා ගැනීම වැඩිදියුණු කිරීමට, ඔබේ මුහුණ යළි-ලියාපදිංචි කරන්න"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"මුහුණෙන් අගුළු හැරීම පිහිටුවන්න"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"ඔබගේ දුරකථනය දෙස බැලීමෙන් එහි අගුලු හරින්න"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"අගුලු හැරීමට තවත් ක්රම සකසන්න"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"ඇඟිලි සලකුණක් එක් කිරීමට තට්ටු කරන්න"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"මුහුණ සත්යාපනය කළ නොහැක. දෘඩාංගය නොමැත."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"නැවතත් මුහුණෙන් අගුළු හැරීම උත්සාහ කරන්න."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"නව මුහුණු දත්ත ගබඩා කළ නොහැක. පළමුව පැරණි එකක් මකන්න."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"මුහුණු මෙහෙයුම අවලංගු කරන ලදී."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"පරිශීලකයා මුහුණෙන් අගුළු හැරීම අවලංගු කර ඇත."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"උත්සාහයන් ඉතා වැඩි ගණනකි. පසුව නැවත උත්සාහ කරන්න."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"ප්රයත්න ගණන වැඩියි. මුහුණෙන් අගුළු හැරීම අබලයි."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"මුහුණ සත්යාපන කළ නොහැක. නැවත උත්සාහ කරන්න."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"ඔබ මුහුණෙන් අගුළු හැරීම සකසා නැත"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"මෙම උපාංගයෙහි මුහුණෙන් අගුළු හැරීම සහය නොදැක්වේ"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"සංවේදකය තාවකාලිකව අබල කර ඇත."</string>
<string name="face_name_template" msgid="3877037340223318119">"මුහුණු <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"මුහුණෙන් අගුළු හැරීම භාවිත කරන්න"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"මුහුණෙන් අගුළු හැරීම හෝ තිර අගුල භාවිත කරන්න"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"ඉදිරියට යාමට ඔබගේ මුහුණ භාවිත කරන්න"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ඉදිරියට යාමට ඔබගේ මුහුණු හෝ තිර අගුල භාවිත කරන්න"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"අගුළු නොදැමූ ප්රදේශය පුළුල් කරන්න."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"සර්පණ අගුළු ඇරීම."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"රටා අගුළු ඇරීම."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"මුහුණෙන් අගුළු හැරීම."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PIN අගුළු ඇරීම."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Sim Pin අගුලු දැමීම."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Sim Puk අගුලු දැමීම."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"හරි"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ක්රියාවිරහිත කරන්න"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"තව දැන ගන්න"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"වැඩිදියුණු කළ දැනුම්දීම් Android 12 හි Android අනුවර්තී දැනුම්දීම් ප්රතිස්ථාපනය කරයි. මෙම විශේෂාංගය යෝජිත ක්රියා සහ පිළිතුරු පෙන්වන අතර, ඔබගේ දැනුම්දීම් සංවිධානය කරයි.\n\nවැඩිදියුණු කළ දැනුම්දීම්වලට සම්බන්ධතා නම් සහ පණිවිඩ වැනි පුද්ගලික තොරතුරු ඇතුළුව, සියලු දැනුම්දීම් අන්තර්ගතය වෙත ප්රවේශ විය හැකිය. මෙම විශේෂාංගයට දැනුම්දීම් ඉවත දැමීමට හෝ දුරකථන ඇමතුම්වලට පිළිතුරු දීම සහ බාධා නොකිරීම පාලනය කිරීම වැනි, දැනුම්දීම්වලට ප්රතිචාර දැක්වීමටද හැකිය."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"දිනචරියා ප්රකාර තතු දැනුම්දීම"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"බැටරිය සුපුරුදු ආරෝපණයට පෙර ඉවර විය හැක"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"බැටරි සුරැකුම බැටරි ආයු කාලය දීර්ඝ කිරීමට සක්රිය කෙරිණි"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 6a92ab3..416b673 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -615,14 +615,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona odtlačku prsta"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"spravovať hardvér odomknutia tvárou"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Umožňuje aplikácii vyvolať metódy, ktoré pridávajú a odstraňujú šablóny tvárí."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"používať hardvér odomknutia tvárou"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Umožňuje aplikácii používať na overenie totožnosti hardvér odomknutia tvárou"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Odomknutie tvárou"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Znova zaregistrujte svoju tvár"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Znova zaregistrujte svoju tvár, aby sa zlepšilo rozpoznávanie"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Nastavte odomknutie tvárou"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Odomykajte telefón tak, že sa naň pozriete"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Nastavte viac spôsobov odomknutia"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Klepnutím pridajte odtlačok prsta"</string>
@@ -649,18 +647,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Tvár sa nedá overiť. Hardvér nie je k dispozícii."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Skúste znova použiť odomknutie tvárou."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Nové údaje o tvári sa nedajú uložiť. Najprv odstráňte jeden zo starých záznamov."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Operácia týkajúca sa tváre bola zrušená"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Odomknutie tvárou zrušil používateľ."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Príliš veľa pokusov. Skúste to neskôr."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Príliš veľa pokusov. Odomknutie tvárou bolo zakázané."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Nedá sa overiť tvár. Skúste to znova."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Nenastavili ste odomknutie tvárou."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Toto zariadenie nepodporuje odomknutie tvárou."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Senzor je dočasne vypnutý."</string>
<string name="face_name_template" msgid="3877037340223318119">"Tvár <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Použiť odomknutie tvárou"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Použiť tvár alebo zámku obrazovky"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Pokračujte pomocou tváre"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Pokračujte použitím tváre alebo zámky obrazovky"</string>
@@ -963,7 +969,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Rozšíriť oblasť na odomknutie."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Odomknutie prejdením prstom."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Odomknutie vzorom."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Odomknutie tvárou."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Odomknutie kódom PIN."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Odomknutie pomocou kódu PIN SIM karty."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Odomknutie pomocou kódu PUK SIM karty."</string>
@@ -2161,8 +2168,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Vypnúť"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Ďalšie informácie"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Adaptívne upozornenia Androidu boli v Androide 12 nahradené zlepšenými upozorneniami. Táto funkcia zobrazuje navrhované akcie aj odpovede a organizuje vaše upozornenia.\n\nZlepšené upozornenia majú prístup k obsahu upozornení vrátane osobných údajov, ako sú mená kontaktov a správy. Táto funkcia tiež môže zavrieť upozornenia alebo na ne reagovať, napríklad prijať telefonáty a ovládať režim bez vyrušení."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Upozornenie s informáciami o rutinnom režime"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batéria sa môže vybiť pred obvyklým nabitím"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Bol aktivovaný šetrič batérie na predĺženie výdrže batérie"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 18988d7..eea0517 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -615,14 +615,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona prstnih odtisov"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"upravljanje strojne opreme za odklepanje z obrazom"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Aplikaciji omogoča sprožanje načinov za dodajanje in brisanje predlog z obrazi za uporabo."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"uporaba strojne opreme za odklepanje z obrazom"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Aplikaciji omogoča uporabo strojne opreme za odklepanje z obrazom za preverj. pristnosti"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Odklepanje z obrazom"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Znova registrirajte obraz"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Za izboljšanje prepoznavanja znova registrirajte svoj obraz"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Nastavite odklepanje z obrazom"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Odklenite telefon tako, da ga pogledate."</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Nastavite več načinov odklepanja"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Dotaknite se, da dodate prstni odtis."</string>
@@ -649,18 +647,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Obraza ni mogoče preveriti. Str. opr. ni na voljo."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Znova izvedite odklepanje z obrazom."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Novega obraza ni mogoče shraniti. Najprej izbrišite starega."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Dejanje z obrazom je bilo preklicano."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Odklepanje z obrazom je preklical uporabnik."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Preveč poskusov. Poskusite znova pozneje."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Preveč poskusov. Odklepanje z obrazom je onemogočeno."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Obraza ni mogoče preveriti. Poskusite znova."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Odklepanja z obrazom niste nastavili."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Ta naprava ne podpira odklepanja z obrazom."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Tipalo je začasno onemogočeno."</string>
<string name="face_name_template" msgid="3877037340223318119">"Obraz <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Uporaba odklepanja z obrazom"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Uporaba odklepanja z obrazom ali s poverilnico"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Uporabite obraz, če želite nadaljevati."</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Za nadaljevanje uporabite obraz ali odklepanje s poverilnico."</string>
@@ -737,7 +743,7 @@
<string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Nadzira število vnesenih nepravilnih gesel pri odklepanju zaslona in zaklene napravo Android TV ali izbriše vse podatke tega uporabnika, če je vnesenih preveč nepravilnih gesel."</string>
<string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"Nadzira število vnesenih nepravilnih gesel pri odklepanju zaslona in zaklene telefon ali izbriše vse podatke lastnika, če je vnesenih preveč nepravilnih gesel."</string>
<string name="policylab_resetPassword" msgid="214556238645096520">"Spreminjanje zaklepanja zaslona"</string>
- <string name="policydesc_resetPassword" msgid="4626419138439341851">"Spreminjanje zaklepanja zaslona."</string>
+ <string name="policydesc_resetPassword" msgid="4626419138439341851">"Spremeni zaklepanje zaslona."</string>
<string name="policylab_forceLock" msgid="7360335502968476434">"Zaklepanje zaslona"</string>
<string name="policydesc_forceLock" msgid="1008844760853899693">"Nadzor nad tem, kako in kdaj se zaklene zaslon."</string>
<string name="policylab_wipeData" msgid="1359485247727537311">"Brisanje vseh podatkov"</string>
@@ -963,7 +969,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Razširitev območja odklepanja."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Odklepanje s podrsanjem."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Odklepanje z vzorcem."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Odklepanje z obrazom."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Odklepanje s kodo PIN."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Odklepanje kartice SIM s kodo PIN"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Odklepanje kartice SIM s kodo PUK"</string>
@@ -2161,8 +2168,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"V redu"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Izklopi"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Več o tem"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Pametna obvestila so v Androidu 12 zamenjala prilagodljiva obvestila Android. Ta funkcija prikazuje predlagana dejanja in odgovore ter organizira vaša obvestila.\n\nPametna obvestila lahko preberejo vso vsebino obvestil, vključno z osebnimi podatki, kot so imena in sporočila stikov. Ta funkcija lahko tudi opusti obvestila ali se odziva nanje (npr. sprejema telefonske klice in upravlja način Ne moti)."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rutinsko informativno obvestilo o načinu delovanja"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Baterija se bo morda izpraznila, preden jo običajno priključite na polnjenje"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Vklopilo se je varčevanje z energijo baterije za podaljšanje časa delovanja baterije"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 7150c5b..055de56 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona e gjurmës së gishtit"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"menaxho harduerin për shkyçjen me fytyrë"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Lejon aplikacionin të aktivizojë mënyra për shtim e fshirje të shablloneve të përdorura."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"përdor harduerin e shkyçjes me fytyrë"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Lejon aplikacionin të përdorë harduerin e shkyçjes me fytyrë për procesin e vërtetimit"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Shkyçja me fytyrë"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Regjistro përsëri fytyrën tënde"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Për të përmirësuar njohjen, regjistro përsëri fytyrën tënde"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Konfiguro shkyçjen me fytyrë"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Shkyçe telefonin duke parë tek ai"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Konfiguri më shumë mënyra për të shkyçur"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Trokit për të shtuar një gjurmë gishti"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Fytyra s\'mund të verifikohet. Hardueri nuk ofrohet."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Provo përsëri shkyçjen me fytyrë."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"S\'mund të ruhen të dhëna të reja fytyre. Fshi një të vjetër në fillim."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Veprimi me fytyrën u anulua."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Shkyçja me fytyrë u anulua nga përdoruesi."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Shumë përpjekje. Provo sërish më vonë."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Shumë përpjekje. Shkyçja me fytyrë u çaktivizua."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Fytyra nuk mund të verifikohet. Provo përsëri."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Nuk e ke konfiguruar shkyçjen me fytyrë."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Shkyçja me fytyrë nuk mbështetet në këtë pajisje"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensori është çaktivizuar përkohësisht."</string>
<string name="face_name_template" msgid="3877037340223318119">"Fytyra <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Përdor shkyçjen me fytyrë"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Përdor kyçjen me fytyrë ose kyçjen e ekranit"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Përdor fytyrën tënde për të vazhduar"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Përdor fytyrën tënde ose kyçjen e ekranit për të vazhduar"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Zgjero zonën e shkyçjes."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Rrëshqit shkyçjen."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Shkyçje me motiv."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Shkyçja me fytyrë."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Shkyçje me PIN."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Shkyçja e kartës SIM me kodin PIN"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Shkyçja e kartës SIM me kodin PUK"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Në rregull"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Çaktivizo"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Mëso më shumë"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Njoftimet e përmirësuara kanë zëvendësuar \"Njoftimet me përshtatje të Android\" në Android 12. Kjo veçori shfaq veprimet dhe përgjigjet e sugjeruara dhe organizon njoftimet e tua.\n\nNjoftimet e përmirësuara mund të kenë qasje te përmbajtja e njoftimeve, duke përfshirë informacionet personale si emrat e kontakteve dhe mesazhet. Kjo veçori mund t\'i heqë ose të përgjigjet po ashtu për njoftimet, si p.sh. t\'u përgjigjet telefonatave, dhe të kontrollojë modalitetin \"Mos shqetëso\"."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Njoftimi i informacionit të \"Modalitetit rutinë\""</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateria mund të mbarojë përpara ngarkimit të zakonshëm"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"\"Kursyesi i baterisë\" u aktivizua për të rritur kohëzgjatjen e baterisë"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 43fc2ba..3aa9764 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -612,14 +612,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Икона отиска прста"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"управљање хардв. за откључавање лицем"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Дозвољава да апликација активира методе за додавање и брисање шаблона лица ради коришћења."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"коришћење хардвера за откључавање лицем"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Дозвољава да апликација користи хардвер за откључавање лицем ради потврде идентитета"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Откључавање лицем"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Поново региструјте лице"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Да бисте побољшали препознавање, поново региструјте лице"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Подесите откључавање лицем"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Откључајте телефон тако што ћете га погледати"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Подесите још начина за откључавање"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Додирните да бисте додали отисак прста"</string>
@@ -646,18 +644,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Провера лица није успела. Хардвер није доступан."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Пробајте поново откључавање лицем."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Нови подаци о лицу нису сачувани. Прво избришете претходне."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Обрада лица је отказана."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Корисник је отказао откључавање лицем"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Превише покушаја. Пробајте поново касније."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Превише покушаја. Откључавање лицем је онемогућено."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Провера лица није успела. Пробајте поново."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Нисте подесили откључавање лицем"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Откључавање лицем није подржано на овом уређају"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Сензор је привремено онемогућен."</string>
<string name="face_name_template" msgid="3877037340223318119">"Лице <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Користите откључавање лицем"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Користите закључавање лицем или закључавање екрана"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Потврдите идентитет лицем да бисте наставили"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Користите лице или закључавање екрана да бисте наставили"</string>
@@ -960,7 +966,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Прошири област откључавања."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Откључавање превлачењем."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Откључавање шаблоном."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Откључавање лицем."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Откључавање PIN-ом."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Откључава SIM картицу PIN-ом."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Откључава SIM картицу PUK-ом."</string>
@@ -2128,8 +2135,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Потврди"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Искључи"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Сазнајте више"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Побољшана обавештења су заменила Android прилагодљива обавештења у Android-у 12. Ова функција показује предложене радње и одговоре и организује обавештења.\n\nПобољшана обавештења могу да приступају садржају обавештења, укључујући личне податке попут имена контаката и порука. Ова функција може и да одбацује обавештења или да одговара на њих, на пример, да се јавља на телефонске позиве и контролише режим Не узнемиравај."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Обавештење о информацијама Рутинског режима"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Батерија ће се можда испразнити пре уобичајеног пуњења"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Уштеда батерије је активирана да би се продужило трајање батерије"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index ede2c50..bacbe65 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon för fingeravtryck"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"hantera maskinvara för ansiktslås"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Tillåter att appen anropar metoder för att lägga till och radera ansiktsmallar."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"använd maskinvara för ansiktslås"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Tillåter att appen använder maskinvara för ansiktslås vid autentisering"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Ansiktslås"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Registrera ansiktet på nytt"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Gör om registreringen av ansiktet så att ansiktsigenkänningen ska fungera bättre"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Konfigurera ansiktslås"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Lås upp telefonen genom att titta på den"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Konfigurera fler sätt att låsa upp"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Tryck för att lägga till ett fingeravtryck"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Ansiktsverifiering går ej. Otillgänglig maskinvara."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Försök att använda ansiktslåset igen."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Kan inte lagra ny ansiktsdata. Radera först gammal data."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Ansiktsåtgärden har avbrutits."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Ansiktslås avbröts av användaren."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Du har gjort för många försök. Försök igen senare."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"För många försök. Ansiktslås har inaktiverats."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Det gick inte att verifiera ansiktet. Försök igen."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Du har inte konfigurerat ansiktslås."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Ansiktslås stöds inte på den här enheten."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensorn har tillfälligt inaktiverats."</string>
<string name="face_name_template" msgid="3877037340223318119">"Ansikte <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Använd ansiktslåset"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Använd ansiktslåset eller skärmlåset"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Fortsätt med hjälp av ditt ansikte"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Fortsätt med hjälp av ditt ansikte eller skärmlåset"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Expandera upplåsningsytan."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Lås upp genom att dra."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Lås upp med grafiskt lösenord."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Ansiktslås."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Lås upp med PIN-kod."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Lås upp med SIM-kortets pinkod."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Lås upp med SIM-kortets PUK-kod."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Inaktivera"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Läs mer"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Förbättrade aviseringar har ersatt Anpassade aviseringar för Android i Android 12. Den här funktionen visar förslag på åtgärder och svar och organiserar dina aviseringar.\n\nFörbättrade aviseringar har åtkomst till allt innehåll i aviseringar, inklusive personliga uppgifter som namn på kontakter och meddelanden. Funktionen kan även ignorera aviseringar eller utföra åtgärder utifrån dem, till exempel svara på telefonsamtal och styra Stör ej."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Avisering om rutinläge"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batteriet kan ta slut innan du brukar ladda det"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batterisparläget har aktiverats för att utöka batteritiden"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index aafff7b..00a96d0 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Aikoni ya alama ya kidole"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"dhibiti maunzi ya kufungua kwa uso"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Huruhusu programu iombe njia za kuongeza na kufuta violezo vya uso vitakavyotumiwa."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"tumia maunzi ya kufungua kwa uso"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Huruhusu programu itumie maunzi ya kufungua kwa uso ili kuthibitisha"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Kufungua kwa uso"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Sajili uso wako tena"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Ili kuimarisha utambuzi, tafadhali sajili uso wako tena"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Weka mipangilio ya kufungua kwa uso"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Fungua simu yako kwa kuiangalia"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Weka mipangilio ya mbinu zaidi za kufungua"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Gusa ili uweke alama ya kidole"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Imeshindwa kuthibitisha uso. Maunzi hayapatikani."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Jaribu kufungua kwa uso tena."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Imeshindwa kuhifadhi data ya uso mpya. Futa wa kale kwanza."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Utendaji wa kitambulisho umeghairiwa."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Kufungua kwa uso kumeghairiwa na mtumiaji."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Umejaribu mara nyingi mno. Jaribu tena baadaye."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Umejaribu mara nyingi mno. Kipengele cha kufungua kwa uso kimezimwa."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Imeshindwa kuthibitisha uso. Jaribu tena."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Hujaweka mipangilio ya kufungua kwa uso."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Kufungua kwa uso hakutumiki kwenye kifaa hiki."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Kitambuzi kimezimwa kwa muda."</string>
<string name="face_name_template" msgid="3877037340223318119">"Uso wa <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Tumia kipengele cha kufungua kwa uso"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Tumia uso au mbinu ya kufunga skrini"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Tumia uso wako ili uendelee"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Tumia uso au mbinu yako ya kufunga skrini ili uendelee"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Panua eneo la kufungua."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Kufungua slaidi."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Kufungua kwa ruwaza."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Kufungua kwa uso."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Kufungua kwa PIN."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Kufungua Pin ya Sim."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Kufungua Puk ya Sim."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Sawa"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Zima"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Pata maelezo zaidi"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Kipengele cha Arifa Zilizoboreshwa kilichukua nafasi ya Arifa Zinazojirekebisha za Android katika Android 12. Kipengele hiki kinaonyesha majibu na vitendo vinavyopendekezwa na kupanga arifa zako.\n\nKipengele cha Arifa zilizoboreshwa kinaweza kufikia maudhui ya arifa, ikiwa ni pamoja na taarifa binafsi kama vile majina ya anwani na ujumbe. Kipengele hiki kinaweza pia kuondoa au kujibu arifa, kama vile kujibu simu na kudhibiti kipengele cha Usinisumbue."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Arifa ya maelezo ya Hali ya Kawaida"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Huenda betri itakwisha chaji mapema"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Imewasha Kiokoa Betri ili kurefusha muda wa matumizi ya betri"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 6e10fbb..03a1b8d 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"கைரேகை ஐகான்"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"\'முகம் காட்டித் திறத்தல்\' அம்சத்துக்கான வன்பொருளை நிர்வகித்தல்"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"உபயோகிப்பதற்காக முக டெம்ப்ளேட்டுகளை சேர்க்கும்/நீக்கும் முறைகளை இயக்க, ஆப்ஸை அனுமதிக்கும்."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"’முகம் காட்டித் திறத்தல்’ அம்சத்திற்கான வன்பொருளைப் பயன்படுத்துதல்"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"அடையாளம் காண \'முகம் காட்டித் திறத்தலுக்கான\' வன்பொருளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கும்"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"முகம் காட்டித் திறத்தல்"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"முகத்தை மீண்டும் பதிவுசெய்யவும்"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"அடையாளத்தை மேம்படுத்த முகத்தை மீண்டும் பதிவுசெய்யவும்"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"முகம் காட்டித் திறத்தல் அம்சத்தை அமையுங்கள்"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"மொபைலைப் பார்ப்பதன் மூலம் அதைத் திறக்கலாம்"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"திறக்க, மேலும் பல வழிகளை அமையுங்கள்"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"கைரேகையைச் சேர்க்கத் தட்டுங்கள்"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"முகத்தைச் சரிபார்க்க இயலவில்லை. வன்பொருள் இல்லை."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"\'முகம் காட்டித் திறத்தலை\' மீண்டும் முயலவும்."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"புதிய முகங்களைச் சேர்க்க இயலவில்லை. பழையது ஒன்றை நீக்கவும்."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"முக அங்கீகாரச் செயல்பாடு ரத்துசெய்யப்பட்டது."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"பயனர் \'முகம் காட்டித் திறத்தல்\' அம்சத்தை ரத்துசெய்தார்."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"பலமுறை முயன்றுவிட்டீர்கள். பிறகு முயலவும்."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"பலமுறை முயன்றுவிட்டீர்கள். \'முகம் காட்டித் திறத்தல்’ அம்சம் முடக்கப்பட்டது."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"முகத்தைச் சரிபார்க்க இயலவில்லை. மீண்டும் முயலவும்."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"‘முகம் காட்டித் திறத்தல்’ அம்சத்தை நீங்கள் அமைக்கவில்லை."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"இந்த சாதனத்தில் ’முகம் காட்டித் திறத்தல்’ ஆதரிக்கப்படவில்லை."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"சென்சார் தற்காலிகமாக முடக்கப்பட்டுள்ளது."</string>
<string name="face_name_template" msgid="3877037340223318119">"முகம் <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"முகம் காட்டித் திறத்தலை உபயோகி"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"முகம் காட்டித் திறத்தல் / திரைப் பூட்டைப் பயன்படுத்து"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"தொடர்வதற்கு உங்கள் முகத்தைப் பயன்படுத்துங்கள்"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"தொடர, உங்கள் முகத்தையோ திரைப் பூட்டையோ பயன்படுத்துங்கள்"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"திறப்பதற்கான பகுதியை விவரிக்கவும்."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"ஸ்லைடு மூலம் திறத்தல்."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"பேட்டர்ன் மூலம் திறத்தல்."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"முகம் காட்டித் திறத்தல்."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin மூலம் திறத்தல்."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"சிம்மைத் திறக்கும் பின்."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"சிம்மைத் திறக்கும் Puk."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"சரி"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ஆஃப் செய்"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"மேலும் அறிக"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12 பதிப்பில் \'Android சூழலுக்கேற்ற அறிவிப்புகள்\' அம்சத்திற்குப் பதிலாக \'மேம்பட்ட அறிவிப்புகள்\' மாற்றப்பட்டுள்ளது. இந்த அம்சம், பரிந்துரைக்கப்படும் செயல்களையும் பதில்களையும் காட்டுவதுடன் உங்கள் அறிவிப்புகளையும் ஒழுங்கமைக்கும்.\n\nதொடர்புகளின் பெயர்கள், மெசேஜ்கள் போன்ற தனிப்பட்ட தகவல்கள் உட்பட அனைத்து அறிவிப்பு உள்ளடக்கத்தையும் \'மேம்பட்ட அறிவிப்புகள்\' அணுக முடியும். மேலும் இந்த அம்சத்தால் அறிவிப்புகளை நிராகரிக்கவும் அவற்றுக்குப் பதிலளிக்கவும் முடியும் (அழைப்புகளுக்குப் பதிலளிப்பது, \'தொந்தரவு செய்ய வேண்டாம்\' அம்சத்தைக் கட்டுப்படுத்துவது போன்றவை)."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"வழக்கமான பேட்டரி சேமிப்பானுக்கான விவர அறிவிப்பு"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"வழக்கமாகச் சார்ஜ் செய்வதற்கு முன்பே பேட்டரி தீர்ந்துபோகக்கூடும்"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"பேட்டரி நிலையை நீட்டிக்க பேட்டரி சேமிப்பான் இயக்கப்பட்டுள்ளது"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 3980fcb..9bb10ea9 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"వేలిముద్ర చిహ్నం"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"ఫేస్ అన్లాక్ చేయగల హార్డ్వేర్ను మేనేజ్ చేయడం"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"వినియోగం కోసం ముఖ టెంప్లేట్లను జోడించే మరియు తొలగించే పద్ధతులను అమలు చేయడానికి యాప్ను అనుమతిస్తుంది."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ఫేస్ అన్లాక్ హార్డ్వేర్ను ఉపయోగించడం"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"ప్రామాణీకరణ కోసం ఫేస్తో అన్లాక్ చేయగల హార్డ్వేర్ ఉపయోగానికి యాప్ను అనుమతిస్తుంది"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ఫేస్ అన్లాక్"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"మీ ముఖాన్ని తిరిగి నమోదు చేయండి"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"గుర్తింపును మెరుగుపరచడానికి, దయచేసి మీ ముఖంను తిరిగి నమోదు చేసుకోండి"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"ఫేస్ అన్లాక్ను సెటప్ చేయండి"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"మీ ఫోన్ను చూడటం ద్వారా దాన్ని అన్లాక్ చేయండి"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"అన్లాక్ చేయడానికి మరిన్ని మార్గాలను సెటప్ చేయండి"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"వేలిముద్రను జోడించడానికి ట్యాప్ చేయండి"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ముఖం ధృవీకరించలేరు. హార్డ్వేర్ అందుబాటులో లేదు."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"ఫేస్ అన్లాక్ను మళ్లీ ప్రయత్నించండి."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"కొత్త ముఖం డేటాను నిల్వ చేయడం కాదు. మొదట పాతది తొలిగించండి."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"ముఖ కార్యకలాపం రద్దయింది."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"ఫేస్ అన్లాక్ను యూజర్ రద్దు చేశారు."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"చాలా ఎక్కువ ప్రయత్నాలు చేసారు. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"చాలా సార్లు ప్రయత్నించారు. ఫేస్ అన్లాక్ డిజేబుల్ చేయబడింది."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"ముఖం ధృవీకరించలేకపోయింది. మళ్లీ ప్రయత్నించండి."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"మీరు ఫేస్ అన్లాక్ను సెటప్ చేయలేదు."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"ఈ పరికరంలో ఫేస్ అన్లాక్ను ఉపయోగించడానికి సపోర్ట్ లేదు."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"సెన్సార్ తాత్కాలికంగా డిజేబుల్ చేయబడింది."</string>
<string name="face_name_template" msgid="3877037340223318119">"ముఖ <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"ఫేస్ అన్లాక్ను ఉపయోగించండి"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ఫేస్ లేదా స్క్రీన్ లాక్ను ఉపయోగించండి"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"కొనసాగించడానికి మీ ముఖాన్ని ఉపయోగించండి"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"కొనసాగించడానికి మీ ముఖం లేదా స్క్రీన్ లాక్ను ఉపయోగించండి"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"అన్లాక్ ప్రాంతాన్ని విస్తరింపజేయండి."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"స్లయిడ్ అన్లాక్."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"ఆకృతి అన్లాక్."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"ఫేస్ అన్లాక్."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"పిన్ అన్లాక్."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Sim పిన్ అన్లాక్."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Sim Puk అన్లాక్."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"సరే"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ఆఫ్ చేయండి"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"మరింత తెలుసుకోండి"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12లో Android అనుకూల నోటిఫికేషన్లను, మెరుగైన నోటిఫికేషన్లు భర్తీ చేశాయి. సూచించిన చర్యలు, రిప్లయిలను ఈ ఫీచర్ చూపించి, మీ నోటిఫికేషన్లను ఆర్గనైజ్ చేస్తుంది.\n\nకాంటాక్ట్ పేర్లు, మెసేజ్లు లాంటి వ్యక్తిగత సమాచారంతో సహా నోటిఫికేషన్ కంటెంట్ను మెరుగైన నోటిఫికేషన్లు యాక్సెస్ చేయవచ్చు. ఫోన్ కాల్లకు సమాధానమివ్వడం, \'అంతరాయం కలిగించవద్దు\' ఆప్షన్ను కంట్రోల్ చేయడం లాంటి నోటిఫికేషన్లను విస్మరించడం లేదా ప్రతిస్పందించడం కూడా ఈ ఫీచర్ చేయగలదు."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"రొటీన్ మోడ్ సమాచార నోటిఫికేషన్"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"మామూలుగా ఛార్జ్ చేసేలోపు బ్యాటరీ ఖాళీ కావచ్చు"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"బ్యాటరీ జీవితకాలాన్ని పెంచడానికి బ్యాటరీ సేవర్ యాక్టివేట్ చేయబడింది"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index b5cb73b..0f55dba 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -321,7 +321,7 @@
<string name="permgroupdesc_camera" msgid="7585150538459320326">"ถ่ายภาพและบันทึกวิดีโอ"</string>
<string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"อุปกรณ์ที่อยู่ใกล้เคียง"</string>
<string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"ค้นหาและเชื่อมต่อกับอุปกรณ์ที่อยู่ใกล้เคียง"</string>
- <string name="permgrouplab_calllog" msgid="7926834372073550288">"ประวัติการโทร"</string>
+ <string name="permgrouplab_calllog" msgid="7926834372073550288">"บันทึกการโทร"</string>
<string name="permgroupdesc_calllog" msgid="2026996642917801803">"อ่านและเขียนบันทึกการโทรของโทรศัพท์"</string>
<string name="permgrouplab_phone" msgid="570318944091926620">"โทรศัพท์"</string>
<string name="permgroupdesc_phone" msgid="270048070781478204">"โทรและจัดการการโทร"</string>
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ไอคอนลายนิ้วมือ"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"จัดการฮาร์ดแวร์การปลดล็อกด้วยใบหน้า"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"อนุญาตให้แอปเรียกใช้วิธีเพิ่มและลบเทมเพลตใบหน้าสำหรับการใช้งาน"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ใช้ฮาร์ดแวร์การปลดล็อกด้วยใบหน้า"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"อนุญาตให้แอปใช้ฮาร์ดแวร์การปลดล็อกด้วยใบหน้าเพื่อตรวจสอบสิทธิ์"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ปลดล็อกด้วยใบหน้า"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"ลงทะเบียนใบหน้าอีกครั้ง"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"โปรดลงทะเบียนใบหน้าอีกครั้งเพื่อปรับปรุงการจดจำ"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"ตั้งค่าการปลดล็อกด้วยใบหน้า"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"ปลดล็อกโทรศัพท์โดยมองไปที่โทรศัพท์"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"ตั้งค่าการปลดล็อกด้วยวิธีอื่น"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"แตะเพื่อเพิ่มลายนิ้วมือ"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"ยืนยันใบหน้าไม่ได้ ฮาร์ดแวร์ไม่พร้อมใช้งาน"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"ลองใช้การปลดล็อกด้วยใบหน้าอีกครั้ง"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"จัดเก็บข้อมูลใบหน้าใหม่ไม่ได้ ลบข้อมูลเก่าออกไปก่อน"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"ยกเลิกการดำเนินการกับใบหน้าแล้ว"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"ผู้ใช้ยกเลิกการใช้การปลดล็อกด้วยใบหน้า"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"ดำเนินการหลายครั้งเกินไป ลองอีกครั้งในภายหลัง"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"ลองหลายครั้งเกินไป ปิดใช้การปลดล็อกด้วยใบหน้าแล้ว"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"ยืนยันใบหน้าไม่ได้ ลองอีกครั้ง"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"คุณยังไม่ได้ตั้งค่าการปลดล็อกด้วยใบหน้า"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"อุปกรณ์นี้ไม่รองรับการปลดล็อกด้วยใบหน้า"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"ปิดใช้เซ็นเซอร์ชั่วคราวแล้ว"</string>
<string name="face_name_template" msgid="3877037340223318119">"ใบหน้า <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"ใช้การปลดล็อกด้วยใบหน้า"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"ใช้การล็อกด้วยใบหน้าหรือการล็อกหน้าจอ"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"ใช้ใบหน้าของคุณเพื่อดำเนินการต่อ"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ใช้ใบหน้าหรือการล็อกหน้าจอเพื่อดำเนินการต่อ"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"ขยายพื้นที่ปลดล็อก"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"การปลดล็อกด้วยการเลื่อน"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"การปลดล็อกด้วยรูปแบบ"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"การปลดล็อกด้วยใบหน้า"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"การปลดล็อกด้วย PIN"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"การปลดล็อก PIN ของซิม"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"การปลดล็อก PUK ของซิม"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ตกลง"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"ปิด"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"ดูข้อมูลเพิ่มเติม"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"การแจ้งเตือนที่เพิ่มประสิทธิภาพมาแทนที่การแจ้งเตือนแบบปรับอัตโนมัติของ Android ใน Android 12 ฟีเจอร์นี้จะแสดงการดำเนินการและการตอบกลับที่แนะนำ ตลอดจนจัดระเบียบการแจ้งเตือน\n\nการแจ้งเตือนที่เพิ่มประสิทธิภาพจะเข้าถึงเนื้อหาของการแจ้งเตือนได้ ซึ่งรวมถึงข้อมูลส่วนบุคคล เช่น ชื่อผู้ติดต่อและข้อความ ฟีเจอร์นี้ยังปิดหรือตอบสนองต่อการแจ้งเตือนได้ด้วย เช่น การรับสายโทรศัพท์และการควบคุมโหมดห้ามรบกวน"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"การแจ้งเตือนข้อมูลโหมดกิจวัตร"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"แบตเตอรี่อาจหมดก่อนการชาร์จปกติ"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"เปิดใช้งานโหมดประหยัดแบตเตอรี่แล้วเพื่อยืดอายุการใช้งานแบตเตอรี่"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 434fe4a..67a5c5d 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icon ng fingerprint"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"pamahalaan ang hardware ng pag-unlock gamit ang mukha"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Pumapayag na mag-invoke ang app ng paraang magdagdag at mag-delete ng template ng mukha."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"gamitin ang hardware ng Pag-unlock Gamit ang Mukha"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Pinapayagan ang app na gamitin ang hardware ng Pag-unlock Gamit ang Mukha para sa pag-authenticate"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Pag-unlock Gamit ang Mukha"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"I-enroll ulit ang iyong mukha"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Para mapahusay ang pagkilala, paki-enroll ulit ang iyong mukha"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"I-set up ang pag-unlock gamit ang mukha"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"I-unlock ang iyong telepono sa pamamagitan ng pagtingin dito"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Mag-set up ng higit pang paraan para mag-unlock"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"I-tap para magdagdag ng fingerprint"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Di ma-verify ang mukha. Di available ang hardware."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Subukan ulit ang pag-unlock gamit ang mukha."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Hindi ma-store ang data ng mukha. Mag-delete muna ng iba."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Nakansela ang operation kaugnay ng mukha."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Kinansela ng user ang pag-unlock gamit ang mukha."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Masyadong maraming pagsubok. Subukang muli mamaya."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Masyadong maraming pagsubok. Na-disable ang pag-unlock gamit ang mukha."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Hindi ma-verify ang mukha. Subukang muli."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Hindi mo pa nase-set up ang pag-unlock gamit ang mukha."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Hindi sinusuportahan ang pag-unlock gamit ang mukha sa device na ito."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Pansamantalang na-disable ang sensor."</string>
<string name="face_name_template" msgid="3877037340223318119">"Mukha <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Gumamit ng pag-unlock gamit ang mukha"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Gumamit ng mukha o lock ng screen"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Gamitin ang iyong mukha para magpatuloy"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gamitin ang iyong mukha o lock ng screen para magpatuloy"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Palakihin ang bahagi ng pag-unlock."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Pag-unlock ng slide."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Pag-unlock ng pattern."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Pag-unlock gamit ang mukha."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pag-unlock ng pin."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Pag-unlock ng Pin ng Sim."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Pag-unlock ng Puk ng Sim."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"I-off"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Matuto pa"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Pinalitan ng mga pinahusay na notification ang Mga Adaptive na Notification ng Android sa Android 12. Nagpapakita ng mga iminumungkahing pagkilos at sagot ang feature na ito, at isinasaayos nito ang iyong mga notification.\n\nMaa-access ng mga pinahusay na notification ang content ng notification, kabilang ang personal na impormasyon gaya ng mga pangalan ng contact at mensahe. Magagawa rin ng feature na ito na i-dismiss o tugunan ang mga notification, gaya ng pagsagot sa mga tawag sa telepono, at kontrolin ang Huwag Istorbohin."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notification ng impormasyon ng Routine Mode"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Maaaring maubos ang baterya bago ang karaniwang pag-charge"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Na-activate ang Pantipid ng Baterya para patagalin ang buhay ng baterya"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 5388729..c491db7 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Parmak izi simgesi"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"yüz tanıma kilidi donanımı yönet"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Uygulamanın, kullanılacak yüz şablonlarını ekleme ve silme yöntemlerini başlatmasına izin verir."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"yüz tanıma kilidi donanımını kullan"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Uygulamanın yüz tanıma kilidi donanımı kullanmasına izin verir"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Yüz tanıma kilidi"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Yüzünüzü yeniden kaydedin"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Daha iyi tanınmasını sağlamak için lütfen yüzünüzü yeniden kaydedin"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Yüz tanıma kilidini kurun"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Telefonunuza bakarak kilidini açın"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Kilidi açmak için daha fazla yöntem ayarlayın"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Parmak izi eklemek için dokunun"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Yüz doğrulanamıyor. Donanım kullanılamıyor."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Yüz tanıma kilidini yeniden deneyin."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Yeni yüz verisi depolanamıyor. Önce eski bir tanesini silin."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Yüz işlemi iptal edildi."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Yüz tanıma kilidi kullanıcı tarafından iptal edildi."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Çok fazla deneme yapıldı. Daha sonra tekrar deneyin."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Çok fazla deneme yapıldı. Yüz tanıma kilidi devredışı."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Yüz doğrulanamıyor. Tekrar deneyin."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Yüz tanıma kilidi ayarlamadınız."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Bu cihazda yüz tanıma kilidi desteklenmiyor"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensör geçici olarak devre dışı bırakıldı."</string>
<string name="face_name_template" msgid="3877037340223318119">"Yüz <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Yüz tanıma kilidi kullan"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Yüz tanıma veya ekran kilidi kullan"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Devam etmek için yüzünüzü kullanın"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Devam etmek için yüz veya ekran kilidinizi kullanın"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Kilit açma alanını genişletin."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Kaydırarak kilit açma."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Desenle kilit açma."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Yüzle tanıma kilidi."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin koduyla kilit açma."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM PIN kilidini açın."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM PUK kilidini açın."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"Tamam"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Kapat"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Daha fazla bilgi"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Gelişmiş bildirimler, Android 12\'de Android Uyarlamalı Bildirimler\'in yerini aldı. Bu özellik, önerilen işlem ve yanıtları gösterir ve bildirimlerinizi organize eder.\n\nGelişmiş bildirimler, kişiler ve mesajlar gibi kişisel bilgiler dahil olmak üzere tüm bildirim içeriklerine erişebilir. Bu özellik ayrıca bildirimleri kapatabilir veya telefon aramalarını yanıtlamak ve Rahatsız Etmeyin modunu kontrol etmek gibi işlemlerle bildirimlere yanıt verebilir."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rutin Modu bilgi bildirimi"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Pil normal şarjdan önce bitebilir"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Pilin ömrünü uzatmak için Pil Tasarrufu etkinleştirildi"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index c36f60c..f129480 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -615,14 +615,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок відбитка пальця"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"керувати апаратним забезпечення фейсконтролю"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Додаток може активувати способи додавання й видалення шаблонів облич."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"використовувати апаратне забезпечення для Фейсконтролю"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Додаток зможе використовувати для автентифікації апаратне забезпечення фейсконтролю"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Фейсконтроль"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Повторно проскануйте обличчя"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Повторно проскануйте обличчя для ефективнішого розпізнавання"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Налаштуйте фейсконтроль"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Ви зможете розблоковувати телефон, подивившись на нього"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Налаштуйте більше способів розблокування"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Натисніть, щоб додати відбиток пальця"</string>
@@ -649,18 +647,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Не вдається перевірити обличчя. Апаратне забезпечення недоступне."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Спробуйте скористатися фейсконтролем ще раз."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Не вдається зберегти нові дані про обличчя. Видаліть старі."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Дію з обличчям скасовано."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Фейсконтроль: користувач скасував операцію."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Забагато спроб. Повторіть пізніше."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Забагато спроб. Фейсконтроль вимкнено."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Не вдається перевірити обличчя. Повторіть спробу."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Ви не налаштували фейсконтроль"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"На цьому пристрої не підтримується фейсконтроль."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Датчик тимчасово вимкнено."</string>
<string name="face_name_template" msgid="3877037340223318119">"Обличчя <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Доступ через фейсконтроль"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Використовувати фейсконтроль або дані для розблокування екрана"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Щоб продовжити, скористайтеся фейсконтролем"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Щоб продовжити, скористайтеся фейсконтролем або даними для розблокування екрана"</string>
@@ -963,7 +969,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Розгорнути область розблокування."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Розблокування повзунком."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Розблокування ключем."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Фейсконтроль"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Розблокування PIN-кодом."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Розблокування SIM-карти PIN-кодом."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Розблокування SIM-карти PUK-кодом."</string>
@@ -2161,8 +2168,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Вимкнути"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Докладніше"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"В Android 12 адаптивні сповіщення замінено на покращені. Ця функція допомагає впорядковувати сповіщення й показує в них пропоновані дії та відповіді.\n\nПокращені сповіщення надають доступ до вмісту сповіщень, зокрема до такої особистої інформації, як повідомлення й імена контактів. Ця функція може автоматично закривати сповіщення чи реагувати на них, наприклад відповідати на телефонні дзвінки або керувати режимом \"Не турбувати\"."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Сповіщення про послідовнсть дій"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Акумулятор може розрядитися раніше ніж зазвичай"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Режим енергозбереження активовано для збільшення часу роботи акумулятора"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index dd47641..8305fb1 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"فنگر پرنٹ آئیکن"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"فیس اَنلاک والے ہارڈ ویئر کا نظم کریں"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"ایپ کو چہرے کی تمثیلات شامل اور حذف کرنے کے طریقوں کو کالعدم قرار دینے کی اجازت دیتا ہے۔"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"فیس اَنلاک والا ہارڈ ویئر استعمال کریں"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"ایپ کو تصدیق کے لیے فیس اَنلاک کا ہارڈ ویئر استعمال کرنے کی اجازت دیتی ہے"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"فیس اَنلاک"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"اپنے چہرے کو دوبارہ مندرج کریں"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"شناخت کو بہتر بنانے کے لیے براہ کرم اپنے چہرے کو دوبارہ مندرج کریں"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"فیس اَنلاک سیٹ اپ کریں"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"اپنے فون کی طرف دیکھ کر اسے غیر مقفل کریں"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"غیر مقفل کرنے کے مزید طریقے سیٹ اپ کریں"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"فنگر پرنٹ شامل کرنے کیلئے تھپتھپائیں"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"چہرے کی توثیق نہیں کی جا سکی۔ ہارڈ ویئر دستیاب نہیں ہے۔"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"فیس اَنلاک کو دوبارہ آزمائیں۔"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"چہرے کا نیا ڈیٹا اسٹور نہیں کر سکتے۔ پہلے پرانا حذف کریں۔"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"چہرے پر ہونے والی کارروائی منسوخ ہو گئی۔"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"صارف نے فیس اَنلاک کو منسوخ کر دیا۔"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"کافی زیادہ کوششیں کی گئیں۔ دوبارہ کوشش کریں۔"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"کافی زیادہ کوششیں۔ فیس اَنلاک غیر فعال کر دیا گیا۔"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"چہرے کی توثیق نہیں کی جا سکی۔ پھر آزمائيں۔"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"آپ نے فیس اَنلاک کو سیٹ نہیں کیا ہے۔"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"اس آلہ پر فیس اَنلاک تعاون یافتہ نہیں ہے۔"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"سینسر عارضی طور غیر فعال ہے۔"</string>
<string name="face_name_template" msgid="3877037340223318119">"چہرہ <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"فیس اَنلاک استعمال کریں"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"فیس یا اسکرین لاک استعمال کریں"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"جاری رکھنے کے لیے اپنے چہرے کا استعمال کریں"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"جاری رکھنے کے لیے اپنے چہرے یا اسکرین لاک کا استعمال کریں"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"غیر مقفل کرنے والے علاقے کو پھیلائیں۔"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"سلائیڈ کے ذریعے غیر مقفل کریں۔"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"پیٹرن کے ذریعے غیر مقفل کریں۔"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"فیس اَنلاک۔"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"پن کے ذریعے غیر مقفل کریں۔"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Sim پن غیر مقفل۔"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Sim Puk غیر مقفل۔"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"ٹھیک ہے"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"آف کریں"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"مزید جانیں"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12 میں بہتر کردہ اطلاعات کو Android اڈاپٹیو کی اطلاعات سے تبدیل کیا گیا۔ یہ خصوصیت تجویز کردہ کارروائیاں اور جوابات دکھاتی ہے اور آپ کی اطلاعات کا نظم کرتی ہے۔\n\nبہتر کردہ اطلاعات رابطوں کے نام اور پیغامات جیسی ذاتی معلومات سمیت اطلاعات کے مواد تک رسائی حاصل کر سکتی ہیں۔ یہ خصوصیت اطلاعات کو برخاست کر سکتی ہے یا ان کا جواب بھی دے سکتی ہے جیسے فون کالز کا جواب دینا اور ڈسٹرب نہ کریں کو کنٹرول کرنا۔"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"روٹین موڈ معلومات کی اطلاع"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"معمول چارج سے پہلے بیٹری ختم ہو سکتی ہے"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"بیٹری لائف کو بڑھانے کے لیے بیٹری سیور کو فعال کر دیا گیا ہے"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 16ccc5e..20991b4 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Barmoq izi belgisi"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"yuz bilan ochish qurilmasini boshqarish"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Ilova foydalanish uchun yuz namunalarini qo‘shish va o‘chirish usullarini tatbiq qilishi mumkin."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"yuz bilan ochish qurilmasidan foydalanish"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Haqiqiylikni tekshirish uchun yuz bilan ochishdan foydalanish imkonini beradi"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Yuz bilan ochish"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Yuzingizni yana qayd qiling"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Yuzingiz yanada yaxshiroq aniqlanishi uchun uni yana bir marta qayd qiling"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Yuz bilan ochishni sozlash"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Telefoningizni yuz tekshiruvi yordamida qulfdan chiqaring"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Qulfdan chiqarishning boshqa usullarini sozlang"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Barmoq izi kiritish uchun bosing"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Yuzingiz tasdiqlanmadi. Qurilma ishlamayapti."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Yana yuz bilan ochishga urining."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Yuzga oid axborot saqlanmadi. Avval eskilari tozalansin."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Yuzni aniqlash bekor qilindi."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Yuz bilan ochishni foydalanuvchi bekor qildi."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Juda ko‘p urinildi. Keyinroq qaytadan urining."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Juda koʻp urinildi. Yuz bilan ochish faolsizlantirildi."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Yuzingiz tasdiqlanmadi. Qaytadan urining."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Hali yuz bilan ochishni sozlamagansiz"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Yuz bilan ochish bu qurilmada ishlamaydi"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Sensor vaqtincha faol emas."</string>
<string name="face_name_template" msgid="3877037340223318119">"Yuz <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Yuz bilan ochish"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Yuz bilan ochish yoki ekran qulfi"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Yuz tekshiruvi bilan davom eting"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Davom etish uchun yuz tekshiruvi yoki ekran qulfidan foydalaning"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Qulfni ochish maydonini kengaytirish."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Qulfni silab ochish"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Grafik kalit bilan ochish."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Yuz bilan ochish."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Pin qulfini ochish."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM kartani PIN kod bilan ochish."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM kartani PUK kod bilan ochish."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Faolsizlantirish"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Batafsil"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Android 12 tizimida moslashuvchan bildirishnomalar oʻrniga yangicha bildirishnomalar chiqadi. Bu funksiya amallar va javoblarni taklif qiladi va bildirishnomalaringizni boshqaradi.\n\nYangicha bildirishnomalar barcha bildirishnomalar kontentini, jumladan kontakt nomlari va xabarlar kabi shaxsiy bildirishnomalarni ham oʻqiy oladi. Shuningdek, bu funksiya bildirishnomalarni yopishi yoki telefon chaqiruvlariga javob berishi va Bezovta qilinmasin rejimini boshqarishi mumkin."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Kun tartibi rejimi haqidagi bildirishnoma"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Batareya quvvati odatdagidan ertaroq tugashi mumkin"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Batareya quvvatini uzoqroq vaqtga yetkazish uchun quvvat tejash rejimi yoqildi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index fa719e4..6a69709 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Biểu tượng vân tay"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"quản lý phần cứng của tính năng mở khóa bằng khuôn mặt"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Cho phép ứng dụng gọi ra các phương pháp để thêm và xóa mẫu khuôn mặt sử dụng."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"sử dụng phần cứng của tính năng mở khóa bằng khuôn mặt"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Cho phép ứng dụng dùng phần cứng mở khóa bằng khuôn mặt để tiến hành xác thực"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Mở khóa bằng khuôn mặt"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Đăng ký lại khuôn mặt của bạn"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Để cải thiện khả năng nhận dạng, hãy đăng ký lại khuôn mặt của bạn"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Thiết lập tính năng mở khóa bằng khuôn mặt"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Mở khóa điện thoại bằng cách nhìn vào điện thoại"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Thiết lập thêm những cách mở khóa khác"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Nhấn để thêm vân tay"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Không thể xác minh khuôn mặt. Phần cứng không có sẵn."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Thử lại thao tác mở khóa bằng khuôn mặt."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Không lưu được dữ liệu khuôn mặt mới. Hãy xóa dữ liệu cũ trước."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Đã hủy thao tác dùng khuôn mặt."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Người dùng đã hủy thao tác mở khóa bằng khuôn mặt."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Bạn đã thử quá nhiều lần. Hãy thử lại sau."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Quá nhiều lần thử. Đã tắt tính năng mở khóa bằng khuôn mặt."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Không thể xác minh khuôn mặt. Hãy thử lại."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Bạn chưa thiết lập tính năng mở khóa bằng khuôn mặt."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Thiết bị này không hỗ trợ tính năng mở khóa bằng khuôn mặt."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Đã tạm thời tắt cảm biến."</string>
<string name="face_name_template" msgid="3877037340223318119">"Khuôn mặt <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Dùng tính năng mở khóa bằng khuôn mặt"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Dùng khuôn mặt hoặc phương thức khóa màn hình"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Hãy dùng khuôn mặt của bạn để tiếp tục"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Dùng khuôn mặt của bạn hoặc phương thức khóa màn hình để tiếp tục"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Mở rộng vùng khóa."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Mở khóa bằng cách trượt."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Mở khóa bằng hình."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Mở khóa bằng khuôn mặt."</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Mở khóa bằng mã pin."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Mở khóa bằng mã PIN của SIM."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Mở khóa bằng mã PUK của SIM."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Tắt"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Tìm hiểu thêm"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Thông báo nâng cao đã thay thế Thông báo thích ứng trên Android trong Android 12. Tính năng này hiển thị những thao tác và câu trả lời đề xuất, đồng thời sắp xếp các thông báo của bạn.\n\nThông báo nâng cao có thể đọc mọi nội dung thông báo, bao gồm cả thông tin cá nhân như tên liên hệ và tin nhắn. Tính năng này cũng có thể đóng hoặc phản hồi các thông báo, chẳng hạn như trả lời cuộc gọi điện thoại, đồng thời có thể kiểm soát chế độ Không làm phiền."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Thông báo cung cấp thông tin về chế độ sạc thông thường"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Pin có thể hết trước khi sạc bình thường"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Trình tiết kiệm pin được kích hoạt để kéo dài thời lượng pin"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 90692d0..3bf61b2 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指纹图标"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"管理人脸解锁硬件"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"允许该应用调用方法来添加和删除可用的人脸模板。"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"使用人脸解锁硬件"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"允许该应用使用人脸解锁硬件进行身份验证"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"人脸解锁"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"重新注册您的面孔"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"要提升识别精确度,请重新注册您的面孔"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"设置人脸解锁"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"脸部对准手机即可将其解锁"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"设置更多解锁方式"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"点按即可添加指纹"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"无法验证人脸。硬件无法使用。"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"请重新尝试人脸解锁。"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"无法存储新的人脸数据。请先删除旧的人脸数据。"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"面孔处理操作已取消。"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"用户已取消人脸解锁。"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"尝试次数过多,请稍后重试。"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"尝试次数过多,人脸解锁已停用。"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"无法验证人脸,请重试。"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"您尚未设置人脸解锁。"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"此设备不支持人脸解锁。"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"传感器已暂时停用。"</string>
<string name="face_name_template" msgid="3877037340223318119">"面孔 <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"使用人脸解锁"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"使用人脸解锁或屏幕锁定凭据"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"使用您的面孔验证身份才能继续"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"使用人脸解锁或屏幕锁定凭据验证身份,才能继续操作"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"展开解锁区域。"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"滑动解锁。"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"图案解锁。"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"人脸解锁。"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PIN码解锁。"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM 卡 PIN 码解锁。"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM 卡 PUK 码解锁。"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"确定"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"关闭"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"了解详情"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"在 Android 12 中,增强型通知功能取代了 Android 自适应通知功能。增强型通知功能可以显示建议的操作和回复,并可将通知整理得井井有条。\n\n增强型通知功能可以访问通知内容,包括联系人名称和消息等个人信息。该功能还可以关闭或响应通知,例如接听来电以及控制勿扰模式。"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"日常安排模式信息通知"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"电池电量可能会在您平时的充电时间之前耗尽"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"已启用省电模式以延长电池续航时间"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index b24b261..c24e75d 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指紋圖示"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"管理臉孔解鎖硬件"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"允許應用程式調用方法,以加入和刪除可用的臉孔範本。"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"使用臉孔解鎖硬件"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"允許應用程式使用臉孔解鎖硬件來驗證"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"臉孔解鎖"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"重新註冊臉孔"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"如要提高識別能力,請重新註冊您的臉孔"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"設定臉孔解鎖功能"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"直望手機即可解鎖"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"設定更多解鎖方法"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"輕按即可新增指紋"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"無法驗證臉孔,硬件無法使用。"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"請再次嘗試「臉孔解鎖」。"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"無法儲存新的臉容資料,請先刪除舊資料。"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"臉孔操作已取消。"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"使用者已取消「臉孔解鎖」。"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"嘗試次數過多,請稍後再試。"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"嘗試次數過多,「臉孔解鎖」已停用。"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"無法驗證臉孔。請再試一次。"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"您尚未設定「臉孔解鎖」。"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"此裝置不支援「臉孔解鎖」。"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"感應器已暫時停用。"</string>
<string name="face_name_template" msgid="3877037340223318119">"臉孔 <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"使用臉孔解鎖"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"使用臉孔或螢幕鎖定"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"如要繼續操作,請使用您的面孔驗證身分"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"請使用臉孔解鎖或螢幕鎖定功能驗證身分,才能繼續操作"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"展開解鎖區域。"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"滑動解鎖。"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"圖案解鎖。"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"臉孔解鎖。"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PIN 解鎖。"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM 卡 PIN 碼解鎖。"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM 卡 PUK 解鎖。"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"確定"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"關閉"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"瞭解詳情"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"在 Android 12 中,我們將 Android 自動調整通知取代成強化通知。此功能可顯示建議操作和回覆,以及整理通知。\n\n強化通知功能可讀取所有通知內容 (包括聯絡人姓名和訊息等個人資料),以及關閉或回應通知,例如接聽來電和控制「請勿騷擾」功能。"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"「日常安排模式」資料通知"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"電量可能會在日常充電前耗盡"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"「省電模式」已啟用,以便延長電池壽命"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 0d9c21d..7063012 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指紋圖示"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"管理人臉解鎖硬體"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"允許應用程式呼叫方法來新增及移除可用的臉孔範本。"</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"使用人臉解鎖硬體"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"允許應用程式使用人臉解鎖硬體進行驗證"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"人臉解鎖"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"請重新註冊你的臉孔"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"為提升辨識精準度,請重新註冊你的臉孔"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"設定人臉解鎖功能"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"看著手機就能解鎖"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"設定更多解鎖方式"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"輕觸即可新增指紋"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"相關硬體無法使用,因此無法驗證臉孔。"</string>
- <string name="face_error_timeout" msgid="522924647742024699">"請重新進行人臉解鎖。"</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"無法儲存新的臉孔資料,請先刪除舊的資料。"</string>
<string name="face_error_canceled" msgid="2164434737103802131">"臉孔處理作業已取消。"</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"使用者已取消人臉解鎖作業。"</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"嘗試次數過多,請稍後再試。"</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"嘗試次數過多,因此系統已停用人臉解鎖功能。"</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"無法驗證臉孔,請再試一次。"</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"你尚未設定人臉解鎖功能。"</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"這個裝置不支援人臉解鎖功能。"</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"感應器已暫時停用。"</string>
<string name="face_name_template" msgid="3877037340223318119">"臉孔 <xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"使用人臉解鎖功能"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"使用人臉解鎖或螢幕鎖定功能"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"如要繼續操作,請透過你的臉孔驗證身分"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"請使用人臉解鎖或螢幕鎖定功能驗證身分,才能繼續操作"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"展開解鎖區域。"</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"滑動解鎖。"</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"圖案解鎖。"</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"人臉解鎖。"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PIN 解鎖。"</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM 卡 PIN 碼解鎖。"</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM 卡 PUK 解鎖。"</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"確定"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"關閉"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"瞭解詳情"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"在 Android 12 中,加強型通知功能已取代 Android 自動調整通知。這項功能可以顯示建議的操作和回覆內容,也可以整理通知。\n\n加強型通知功能可存取通知內容,包括聯絡人名稱和訊息內文等個人資訊。此外,這項功能還能關閉或回覆通知,例如接聽來電及控管「零打擾」功能。"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"日常安排模式資訊通知"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"電池電力可能會在你平常的充電時間前耗盡"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"已啟用省電模式以延長電池續航力"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index e9e6ce2..8828f85 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -609,14 +609,12 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Isithonjana sezigxivizo zeminwe"</string>
- <string name="permlab_manageFace" msgid="4569549381889283282">"phatha izingxenyekazi zekhompyutha zokuvula ngobuso"</string>
- <string name="permdesc_manageFace" msgid="6204569688492710471">"Ivumela uhlelo lokusebenza ukuthi luhoxise izindlela zokungeza nokususa amathempulethi obuso azosetshenziswa."</string>
- <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"sebenzisa izingxenyekazi zekhompuyutha zokuvula ngobuso"</string>
- <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Ivumela i-app isebenzise izingxenyekazi zekhompyutha zokuvula ngobuso ukuze kuqinisekiswe"</string>
- <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Ukuvula ngobuso"</string>
+ <!-- no translation found for face_recalibrate_notification_name (7311163114750748686) -->
+ <skip />
<string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Phinda ubhalise ubuso bakho"</string>
<string name="face_recalibrate_notification_content" msgid="892757485125249962">"Ukuze uthuthukise ukubonwa, sicela uphinde ubhalise ubuso bakho"</string>
- <string name="face_setup_notification_title" msgid="550617822603450009">"Setha ukuvula ngobuso"</string>
+ <!-- no translation found for face_setup_notification_title (8843461561970741790) -->
+ <skip />
<string name="face_setup_notification_content" msgid="5463999831057751676">"Vula ifoni yakho ngokuyibheka"</string>
<string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Setha izindlela eziningi zokuvula"</string>
<string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Thepha ukuze ungeze izigxivizo zomunwe"</string>
@@ -643,18 +641,26 @@
<string-array name="face_acquired_vendor">
</string-array>
<string name="face_error_hw_not_available" msgid="5085202213036026288">"Ayikwazi ukuqinisekisa ubuso. Izingxenyekazi zekhompyutha azitholakali."</string>
- <string name="face_error_timeout" msgid="522924647742024699">"Zama ukuvula ngobuso futhi."</string>
+ <!-- no translation found for face_error_timeout (2598544068593889762) -->
+ <skip />
<string name="face_error_no_space" msgid="5649264057026021723">"Ayikwazi ukulondoloza idatha yobuso. Susa endala."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"Umsebenzi wobuso ukhanselwe."</string>
- <string name="face_error_user_canceled" msgid="8553045452825849843">"Ukuvula ngobuso kukhanselwe umsebenzisi."</string>
+ <!-- no translation found for face_error_user_canceled (5766472033202928373) -->
+ <skip />
<string name="face_error_lockout" msgid="7864408714994529437">"Imizamo eminingi kakhulu. Zama futhi emuva kwesikhathi."</string>
- <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Imizamo eminingi kakhulu. Ukuvula ngobuso kukhutshaziwe."</string>
+ <!-- no translation found for face_error_lockout_permanent (3277134834042995260) -->
+ <skip />
+ <!-- no translation found for face_error_lockout_screen_lock (5062609811636860928) -->
+ <skip />
<string name="face_error_unable_to_process" msgid="5723292697366130070">"Ayikwazi ukuqinisekisa ubuso. Zama futhi."</string>
- <string name="face_error_not_enrolled" msgid="7369928733504691611">"Awukakusethi ukuvula ngobuso."</string>
- <string name="face_error_hw_not_present" msgid="1070600921591729944">"Ukuvula ngobuso kusekelwe kule divayisi."</string>
+ <!-- no translation found for face_error_not_enrolled (1134739108536328412) -->
+ <skip />
+ <!-- no translation found for face_error_hw_not_present (7940978724978763011) -->
+ <skip />
<string name="face_error_security_update_required" msgid="5076017208528750161">"Inzwa ikhutshazwe okwesikhashana."</string>
<string name="face_name_template" msgid="3877037340223318119">"Ubuso be-<xliff:g id="FACEID">%d</xliff:g>"</string>
- <string name="face_app_setting_name" msgid="8130135875458467243">"Sebenzisa ukuvula ngobuso"</string>
+ <!-- no translation found for face_app_setting_name (5854024256907828015) -->
+ <skip />
<string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Sebenzisa i-face lock noma ukukhiya isikrini"</string>
<string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Sebenzisa ubuso bakho ukuze uqhubeke"</string>
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Sebenzisa ubuso bakho noma ukukhiya isikrini ukuze uqhubeke"</string>
@@ -957,7 +963,8 @@
<string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Nwebisa indawo yokuvula."</string>
<string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Ukuvula ngokuslayida."</string>
<string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Ukuvula ngephethini."</string>
- <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Ukuvula ngobuso"</string>
+ <!-- no translation found for keyguard_accessibility_face_unlock (4533832120787386728) -->
+ <skip />
<string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"Ukuvula ngephinikhodi."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Ukuvulwa kwephinikhodi ye-Sim."</string>
<string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Ukuvulwa kwe-puk ye-Sim."</string>
@@ -2095,8 +2102,7 @@
<string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"KULUNGILE"</string>
<string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Vala"</string>
<string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Funda kabanzi"</string>
- <!-- no translation found for nas_upgrade_notification_learn_more_content (3735480566983530650) -->
- <skip />
+ <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Izaziso ezithuthukisiwe zithathe isikhundla sezaziso eziguqukayo ze-Android ku-Android 12. Lesi sakhi sikhombisa izenzo eziphakanyisiwe nezimpendulo, futhi sihlela izaziso zakho.\n\nIzaziso ezithuthukisiwe zingafinyelela kokuqukethwe kwesaziso, kuhlanganise nemininingwane yomuntu efana namagama woxhumana nabo nemilayezo. Lesi sakhi singacashisa noma siphendule izaziso, njengokuphendula amakholi wefoni, nokulawula okuthi Ungaphazamisi."</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Isaziso solwazi lwe-Routine Mode"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Ibhethri lingaphela ngaphambi kokushaja okuvamile"</string>
<string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Isilondolozi sebhethri siyasebenza ngaphandle kwempilo yebhethri"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index e975938..a5f5051 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1137,6 +1137,9 @@
<!-- Darker accent color used on Material NEXT buttons. @hide -->
<attr name="colorAccentPrimaryVariant" format="color" />
+ <!-- Text color used on top of Material NEXT accent colors. @hide -->
+ <attr name="textColorOnAccent" format="color" />
+
<!-- Secondary darker accent color used on Material NEXT buttons. @hide -->
<attr name="colorAccentSecondaryVariant" format="color" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ab53b4c..1ddff32 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -955,7 +955,7 @@
4 - Go to voice assist
5 - Go to assistant (Settings.Secure.ASSISTANT)
-->
- <integer name="config_longPressOnPowerBehavior">1</integer>
+ <integer name="config_longPressOnPowerBehavior">5</integer>
<!-- Whether the setting to change long press on power behaviour from default to assistant (5)
is available in Settings.
@@ -973,7 +973,7 @@
1 - Mute toggle
2 - Global actions menu
-->
- <integer name="config_keyChordPowerVolumeUp">1</integer>
+ <integer name="config_keyChordPowerVolumeUp">2</integer>
<!-- Control the behavior when the user long presses the back button. Non-zero values are only
valid for watches as part of CDD/CTS.
@@ -3971,6 +3971,9 @@
<!-- URI for in call notification sound -->
<string translatable="false" name="config_inCallNotificationSound">/product/media/audio/ui/InCallNotification.ogg</string>
+ <!-- URI for default ringtone sound file to be used for silent ringer vibration -->
+ <string translatable="false" name="config_defaultRingtoneVibrationSound">/product/media/audio/ui/AttentionalHaptics.ogg</string>
+
<!-- Default number of notifications from the same app before they are automatically grouped by the OS -->
<integer translatable="false" name="config_autoGroupAtCount">4</integer>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 552898b..ef5cfe3 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3236,6 +3236,8 @@
<public name="config_systemCompanionDeviceProvider"/>
<!-- @hide @SystemApi -->
<public name="config_systemUi" />
+ <!-- @hide For use by platform and tools only. Developers should not specify this value. -->
+ <public name="config_defaultRingtoneVibrationSound"/>
</staging-public-group>
<staging-public-group type="id" first-id="0x01020055">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8f40974..b33a281 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1594,7 +1594,7 @@
<!-- Message shown during fingerprint acquisision when the fingerprint sensor needs cleaning -->
<string name="fingerprint_acquired_imager_dirty">Clean the sensor</string>
<!-- Message shown during fingerprint acquisision when the user removes their finger from the sensor too quickly -->
- <string name="fingerprint_acquired_too_fast">Finger moved too fast</string>
+ <string name="fingerprint_acquired_too_fast">Hold a little longer</string>
<!-- Message shown during fingerprint acquisision when the user moves their finger too slowly -->
<string name="fingerprint_acquired_too_slow">Finger moved too slow. Please try again.</string>
<!-- Message shown during fingerprint acquisition when the fingerprint was already enrolled.[CHAR LIMIT=50] -->
@@ -1656,23 +1656,14 @@
<!-- Content description which should be used for the fingerprint icon. -->
<string name="fingerprint_icon_content_description">Fingerprint icon</string>
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=70] -->
- <string name="permlab_manageFace">manage face unlock hardware</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=90] -->
- <string name="permdesc_manageFace">Allows the app to invoke methods to add and delete facial templates for use.</string>
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=70] -->
- <string name="permlab_useFaceAuthentication">use face unlock hardware</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=90] -->
- <string name="permdesc_useFaceAuthentication">Allows the app to use face unlock hardware for authentication</string>
-
<!-- Notification name shown when the system requires the user to re-enroll their face. [CHAR LIMIT=NONE] -->
- <string name="face_recalibrate_notification_name">Face unlock</string>
+ <string name="face_recalibrate_notification_name">Face Unlock</string>
<!-- Notification title shown when the system requires the user to re-enroll their face. [CHAR LIMIT=NONE] -->
<string name="face_recalibrate_notification_title">Re-enroll your face</string>
<!-- Notification content shown when the system requires the user to re-enroll their face. [CHAR LIMIT=NONE] -->
<string name="face_recalibrate_notification_content">To improve recognition, please re-enroll your face</string>
- <!-- Title of a notification that directs the user to set up face unlock by enrolling their face. [CHAR LIMIT=NONE] -->
- <string name="face_setup_notification_title">Set up face unlock</string>
+ <!-- Title of a notification that directs the user to set up Face Unlock by enrolling their face. [CHAR LIMIT=NONE] -->
+ <string name="face_setup_notification_title">Set up Face Unlock</string>
<!-- Contents of a notification that directs the user to set up face unlock by enrolling their face. [CHAR LIMIT=NONE] -->
<string name="face_setup_notification_content">Unlock your phone by looking at it</string>
<!-- Title of a notification that directs the user to enroll a fingerprint. [CHAR LIMIT=NONE] -->
@@ -1727,23 +1718,25 @@
<!-- Error message shown when the face hardware can't be accessed. [CHAR LIMIT=69] -->
<string name="face_error_hw_not_available">Can\u2019t verify face. Hardware not available.</string>
<!-- Error message shown when the face hardware timer has expired and the user needs to restart the operation. [CHAR LIMIT=50] -->
- <string name="face_error_timeout">Try face unlock again.</string>
+ <string name="face_error_timeout">Try Face Unlock again</string>
<!-- Error message shown when the face hardware has run out of room for storing faces. [CHAR LIMIT=69] -->
<string name="face_error_no_space">Can\u2019t store new face data. Delete an old one first.</string>
<!-- Generic error message shown when the face operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user. [CHAR LIMIT=50] -->
<string name="face_error_canceled">Face operation canceled.</string>
- <!-- Generic error message shown when the face unlock operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=68] -->
- <string name="face_error_user_canceled">Face unlock canceled by user.</string>
+ <!-- Generic error message shown when the Face Unlock operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=68] -->
+ <string name="face_error_user_canceled">Face Unlock canceled by user</string>
<!-- Generic error message shown when the face operation fails because too many attempts have been made. [CHAR LIMIT=50] -->
<string name="face_error_lockout">Too many attempts. Try again later.</string>
- <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=77] -->
- <string name="face_error_lockout_permanent">Too many attempts. Face unlock disabled.</string>
+ <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=90] -->
+ <string name="face_error_lockout_permanent">Too many attempts. Face Unlock disabled.</string>
+ <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=90] -->
+ <string name="face_error_lockout_screen_lock">Too many attempts. Enter screen lock instead.</string>
<!-- Generic error message shown when the face hardware can't recognize the face. [CHAR LIMIT=50] -->
<string name="face_error_unable_to_process">Can\u2019t verify face. Try again.</string>
<!-- Generic error message shown when the user has no enrolled face. [CHAR LIMIT=59] -->
- <string name="face_error_not_enrolled">You haven\u2019t set up face unlock.</string>
- <!-- Generic error message shown when the app requests face unlock on a device without a sensor. [CHAR LIMIT=61] -->
- <string name="face_error_hw_not_present">Face unlock is not supported on this device.</string>
+ <string name="face_error_not_enrolled">You haven\u2019t set up Face Unlock</string>
+ <!-- Generic error message shown when the app requests Face Unlock on a device without a sensor. [CHAR LIMIT=61] -->
+ <string name="face_error_hw_not_present">Face Unlock isn\u2019t supported on this device</string>
<!-- Generic error message shown when face unlock is not available due to a security vulnerability. [CHAR LIMIT=50] -->
<string name="face_error_security_update_required">Sensor temporarily disabled.</string>
@@ -1751,7 +1744,7 @@
<string name="face_name_template">Face <xliff:g id="faceId" example="1">%d</xliff:g></string>
<!-- Name for an app setting that lets the user authenticate for that app with their face. [CHAR LIMIT=30] -->
- <string name="face_app_setting_name">Use face unlock</string>
+ <string name="face_app_setting_name">Use Face Unlock</string>
<!-- Name for an app setting that lets the user authenticate for that app with their face or screen lock credential (i.e. PIN, pattern, or password). [CHAR LIMIT=70] -->
<string name="face_or_screen_lock_app_setting_name">Use face or screen lock</string>
<!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with their face. [CHAR LIMIT=70] -->
@@ -2502,8 +2495,8 @@
<string name="keyguard_accessibility_slide_unlock">Slide unlock.</string>
<!-- Accessibility description of the pattern unlock. [CHAR_LIMIT=none] -->
<string name="keyguard_accessibility_pattern_unlock">Pattern unlock.</string>
- <!-- Accessibility description of the face unlock. [CHAR_LIMIT=none] -->
- <string name="keyguard_accessibility_face_unlock">Face unlock.</string>
+ <!-- Accessibility description of the Face Unlock. [CHAR_LIMIT=none] -->
+ <string name="keyguard_accessibility_face_unlock">Face Unlock.</string>
<!-- Accessibility description of the pin lock. [CHAR_LIMIT=none] -->
<string name="keyguard_accessibility_pin_unlock">Pin unlock.</string>
<!-- Accessibility description of the sim pin lock. [CHAR_LIMIT=none] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b8a182b..4da5859 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4267,10 +4267,14 @@
<java-symbol type="attr" name="colorAccentPrimary" />
<java-symbol type="attr" name="colorAccentSecondary" />
<java-symbol type="attr" name="colorAccentTertiary" />
+ <java-symbol type="attr" name="colorAccentPrimaryVariant" />
+ <java-symbol type="attr" name="colorAccentSecondaryVariant" />
+ <java-symbol type="attr" name="colorAccentTertiaryVariant" />
<java-symbol type="attr" name="colorSurface" format="color" />
<java-symbol type="attr" name="colorSurfaceHighlight" format="color" />
<java-symbol type="attr" name="colorSurfaceVariant" format="color" />
<java-symbol type="attr" name="colorSurfaceHeader" format="color" />
+ <java-symbol type="attr" name="textColorOnAccent" format="color" />
<!-- CEC Configuration -->
<java-symbol type="bool" name="config_cecHdmiCecEnabled_userConfigurable" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 41bedb2..97acd5b 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -232,6 +232,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
</style>
@@ -260,6 +261,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -305,6 +307,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -352,6 +355,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -398,6 +402,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -459,6 +464,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -497,6 +503,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -541,6 +548,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -586,6 +594,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -647,6 +656,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -693,6 +703,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -737,6 +748,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -783,6 +795,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -828,6 +841,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -873,6 +887,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -918,6 +933,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -963,6 +979,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -1012,6 +1029,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -1058,6 +1076,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -1101,6 +1120,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -1298,6 +1318,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
<item name="colorPopupBackground">?attr/colorBackgroundFloating</item>
@@ -1327,6 +1348,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -1371,6 +1393,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -1416,6 +1439,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -1463,6 +1487,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -1509,6 +1534,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -1572,6 +1598,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -1609,6 +1636,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -1656,6 +1684,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -1704,6 +1733,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -1751,6 +1781,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
</style>
@@ -1780,6 +1811,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
</style>
@@ -1810,6 +1842,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -1859,6 +1892,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -1906,6 +1940,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -1952,6 +1987,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -1997,6 +2033,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -2042,6 +2079,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -2085,6 +2123,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -2246,6 +2285,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_dark</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_dark</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_dark</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_dark</item>
<item name="colorForegroundInverse">@color/foreground_device_default_light</item>
@@ -2290,6 +2330,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -2344,6 +2385,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
@@ -2391,6 +2433,7 @@
<item name="textColorPrimary">@color/text_color_primary_device_default_light</item>
<item name="textColorSecondary">@color/text_color_secondary_device_default_light</item>
<item name="textColorTertiary">@color/text_color_tertiary_device_default_light</item>
+ <item name="textColorOnAccent">@color/text_color_on_accent_device_default</item>
<item name="colorForeground">@color/foreground_device_default_light</item>
<item name="colorForegroundInverse">@color/foreground_device_default_dark</item>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
index c207135..0c7218e 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
@@ -124,7 +124,8 @@
for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
final String metricTitle = getPowerMetricTitle(component);
final int powerModel = requestedBatteryConsumer.getPowerModel(component);
- if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
+ if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE
+ || powerModel == BatteryConsumer.POWER_MODEL_UNDEFINED) {
addEntry(metricTitle, EntryType.UID_POWER_MODELED,
requestedBatteryConsumer.getConsumedPower(component),
totalPowerByComponentMah[component]
@@ -202,7 +203,8 @@
for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
final String metricTitle = getPowerMetricTitle(component);
final int powerModel = deviceBatteryConsumer.getPowerModel(component);
- if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
+ if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE
+ || powerModel == BatteryConsumer.POWER_MODEL_UNDEFINED) {
addEntry(metricTitle, EntryType.DEVICE_POWER_MODELED,
deviceBatteryConsumer.getConsumedPower(component),
appsBatteryConsumer.getConsumedPower(component));
@@ -237,8 +239,9 @@
private boolean isPowerProfileModelsOnly(BatteryConsumer batteryConsumer) {
for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
- if (batteryConsumer.getPowerModel(component)
- != BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
+ final int powerModel = batteryConsumer.getPowerModel(component);
+ if (powerModel != BatteryConsumer.POWER_MODEL_POWER_PROFILE
+ && powerModel != BatteryConsumer.POWER_MODEL_UNDEFINED) {
return false;
}
}
diff --git a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
index bee0a0b..333eebb 100644
--- a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
+++ b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
@@ -48,9 +48,8 @@
@Test
public void testGetStatsProto() {
- final long sessionEndTimestampMs = 1050;
final BatteryUsageStats bus = buildBatteryUsageStats();
- final byte[] bytes = bus.getStatsProto(sessionEndTimestampMs);
+ final byte[] bytes = bus.getStatsProto();
BatteryUsageStatsAtomsProto proto;
try {
proto = BatteryUsageStatsAtomsProto.parseFrom(bytes);
@@ -60,9 +59,9 @@
}
assertEquals(bus.getStatsStartTimestamp(), proto.sessionStartMillis);
- assertEquals(sessionEndTimestampMs, proto.sessionEndMillis);
+ assertEquals(bus.getStatsEndTimestamp(), proto.sessionEndMillis);
assertEquals(
- sessionEndTimestampMs - bus.getStatsStartTimestamp(),
+ bus.getStatsEndTimestamp() - bus.getStatsStartTimestamp(),
proto.sessionDurationMillis);
assertEquals(bus.getDischargePercentage(), proto.sessionDischargePercentage);
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 415b1f2..93e4a29 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -41,6 +41,7 @@
"frameworks-core-util-lib",
"mockwebserver",
"guava",
+ "androidx.core_core",
"androidx.test.espresso.core",
"androidx.test.ext.junit",
"androidx.test.runner",
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 520d2f1..14a3a01 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -156,6 +156,9 @@
<!-- Allow use of PendingIntent.getIntent() -->
<uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
+ <!-- ChooserActivityTest permissions-->
+ <uses-permission android:name="android.permission.SET_CLIP_SOURCE" />
+
<application android:theme="@style/Theme" android:supportsRtl="true">
<uses-library android:name="android.test.runner" />
<uses-library android:name="org.apache.http.legacy" android:required="false" />
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 0f8c9e2..cd07d46 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -16,6 +16,14 @@
package android.app;
+import static androidx.core.graphics.ColorUtils.calculateContrast;
+
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.fail;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
@@ -27,10 +35,10 @@
import android.content.Context;
import android.content.Intent;
import android.content.LocusId;
+import android.content.res.Configuration;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.Icon;
-import android.media.session.MediaSession;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -325,13 +333,142 @@
assertNull(clone.getLocusId());
}
- private Notification.Builder getMediaNotification() {
- MediaSession session = new MediaSession(mContext, "test");
- return new Notification.Builder(mContext, "color")
- .setSmallIcon(com.android.internal.R.drawable.emergency_icon)
- .setContentTitle("Title")
- .setContentText("Text")
- .setStyle(new Notification.MediaStyle().setMediaSession(session.getSessionToken()));
+ @Test
+ public void testColors_ensureColors_dayMode_producesValidPalette() {
+ Notification.Colors c = new Notification.Colors();
+ boolean colorized = false;
+ boolean nightMode = false;
+ resolveColorsInNightMode(nightMode, c, Color.BLUE, colorized);
+ assertValid(c);
+ }
+
+ @Test
+ public void testColors_ensureColors_nightMode_producesValidPalette() {
+ Notification.Colors c = new Notification.Colors();
+ boolean colorized = false;
+ boolean nightMode = true;
+ resolveColorsInNightMode(nightMode, c, Color.BLUE, colorized);
+ assertValid(c);
+ }
+
+ @Test
+ public void testColors_ensureColors_colorized_producesValidPalette_default() {
+ validateColorizedPaletteForColor(Notification.COLOR_DEFAULT);
+ }
+
+ @Test
+ public void testColors_ensureColors_colorized_producesValidPalette_blue() {
+ validateColorizedPaletteForColor(Color.BLUE);
+ }
+
+ @Test
+ public void testColors_ensureColors_colorized_producesValidPalette_red() {
+ validateColorizedPaletteForColor(Color.RED);
+ }
+
+ @Test
+ public void testColors_ensureColors_colorized_producesValidPalette_white() {
+ validateColorizedPaletteForColor(Color.WHITE);
+ }
+
+ @Test
+ public void testColors_ensureColors_colorized_producesValidPalette_black() {
+ validateColorizedPaletteForColor(Color.BLACK);
+ }
+
+ public void validateColorizedPaletteForColor(int rawColor) {
+ Notification.Colors cDay = new Notification.Colors();
+ Notification.Colors cNight = new Notification.Colors();
+ boolean colorized = true;
+
+ resolveColorsInNightMode(false, cDay, rawColor, colorized);
+ resolveColorsInNightMode(true, cNight, rawColor, colorized);
+
+ if (rawColor != Notification.COLOR_DEFAULT) {
+ assertEquals(rawColor, cDay.getBackgroundColor());
+ assertEquals(rawColor, cNight.getBackgroundColor());
+ }
+
+ assertValid(cDay);
+ assertValid(cNight);
+
+ if (rawColor != Notification.COLOR_DEFAULT) {
+ // When a color is provided, night mode should have no effect on the notification
+ assertEquals(cDay.getBackgroundColor(), cNight.getBackgroundColor());
+ assertEquals(cDay.getPrimaryTextColor(), cNight.getPrimaryTextColor());
+ assertEquals(cDay.getSecondaryTextColor(), cNight.getSecondaryTextColor());
+ assertEquals(cDay.getPrimaryAccentColor(), cNight.getPrimaryAccentColor());
+ assertEquals(cDay.getSecondaryAccentColor(), cNight.getSecondaryAccentColor());
+ assertEquals(cDay.getProtectionColor(), cNight.getProtectionColor());
+ assertEquals(cDay.getContrastColor(), cNight.getContrastColor());
+ assertEquals(cDay.getRippleAlpha(), cNight.getRippleAlpha());
+ }
+ }
+
+ private void assertValid(Notification.Colors c) {
+ // Assert that all colors are populated
+ assertThat(c.getBackgroundColor()).isNotEqualTo(Notification.COLOR_INVALID);
+ assertThat(c.getProtectionColor()).isNotEqualTo(Notification.COLOR_INVALID);
+ assertThat(c.getPrimaryTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
+ assertThat(c.getSecondaryTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
+ assertThat(c.getPrimaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
+ assertThat(c.getSecondaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
+ assertThat(c.getErrorColor()).isNotEqualTo(Notification.COLOR_INVALID);
+ assertThat(c.getContrastColor()).isNotEqualTo(Notification.COLOR_INVALID);
+ assertThat(c.getRippleAlpha()).isAtLeast(0x00);
+ assertThat(c.getRippleAlpha()).isAtMost(0xff);
+
+ // Assert that various colors have sufficient contrast
+ assertContrastIsAtLeast(c.getPrimaryTextColor(), c.getBackgroundColor(), 4.5);
+ assertContrastIsAtLeast(c.getSecondaryTextColor(), c.getBackgroundColor(), 4.5);
+ assertContrastIsAtLeast(c.getPrimaryAccentColor(), c.getBackgroundColor(), 4.5);
+ assertContrastIsAtLeast(c.getErrorColor(), c.getBackgroundColor(), 4.5);
+ assertContrastIsAtLeast(c.getContrastColor(), c.getBackgroundColor(), 4.5);
+
+ // This accent color is only used for emphasized buttons
+ assertContrastIsAtLeast(c.getSecondaryAccentColor(), c.getBackgroundColor(), 1);
+ }
+
+ private void assertContrastIsAtLeast(int foreground, int background, double minContrast) {
+ try {
+ assertThat(calculateContrast(foreground, background)).isAtLeast(minContrast);
+ } catch (AssertionError e) {
+ throw new AssertionError(
+ String.format("Insufficient contrast: foreground=#%08x background=#%08x",
+ foreground, background), e);
+ }
+ }
+
+ private void resolveColorsInNightMode(boolean nightMode, Notification.Colors c, int rawColor,
+ boolean colorized) {
+ runInNightMode(nightMode,
+ () -> c.resolvePalette(mContext, rawColor, colorized, nightMode));
+ }
+
+ private void runInNightMode(boolean nightMode, Runnable task) {
+ final String initialNightMode = changeNightMode(nightMode);
+ try {
+ Configuration currentConfig = mContext.getResources().getConfiguration();
+ boolean isNightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
+ == Configuration.UI_MODE_NIGHT_YES;
+ assertEquals(nightMode, isNightMode);
+ task.run();
+ } finally {
+ runShellCommand("cmd uimode night " + initialNightMode);
+ }
+ }
+
+
+ // Change the night mode and return the previous mode
+ private String changeNightMode(boolean nightMode) {
+ final String nightModeText = runShellCommand("cmd uimode night");
+ final String[] nightModeSplit = nightModeText.split(":");
+ if (nightModeSplit.length != 2) {
+ fail("Failed to get initial night mode value from " + nightModeText);
+ }
+ String previousMode = nightModeSplit[1].trim();
+ runShellCommand("cmd uimode night " + (nightMode ? "yes" : "no"));
+ return previousMode;
}
/**
diff --git a/core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java b/core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java
new file mode 100644
index 0000000..1dfbfcd
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/ConstrainDisplayApisConfigTest.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.Nullable;
+import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test class for {@link ConstrainDisplayApisConfig}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksCoreTests:ConstrainDisplayApisConfigTest
+ */
+@SmallTest
+@Presubmit
+public final class ConstrainDisplayApisConfigTest {
+
+ private Properties mInitialConstrainDisplayApisFlags;
+
+ @Before
+ public void setUp() throws Exception {
+ mInitialConstrainDisplayApisFlags = DeviceConfig.getProperties(
+ NAMESPACE_CONSTRAIN_DISPLAY_APIS);
+ clearConstrainDisplayApisFlags();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ DeviceConfig.setProperties(mInitialConstrainDisplayApisFlags);
+ }
+
+ @Test
+ public void neverConstrainDisplayApis_allPackagesFlagTrue_returnsTrue() {
+ setNeverConstrainDisplayApisAllPackagesFlag("true");
+ // Setting 'never_constrain_display_apis' as well to make sure it is ignored.
+ setNeverConstrainDisplayApisFlag("com.android.other:1:2,com.android.other2::");
+
+ testNeverConstrainDisplayApis("com.android.test", /* version= */ 5, /* expected= */ true);
+ testNeverConstrainDisplayApis("com.android.other", /* version= */ 0, /* expected= */ true);
+ testNeverConstrainDisplayApis("com.android.other", /* version= */ 3, /* expected= */ true);
+ }
+
+ @Test
+ public void neverConstrainDisplayApis_flagsNoSet_returnsFalse() {
+ testNeverConstrainDisplayApis("com.android.test", /* version= */ 1, /* expected= */ false);
+ }
+
+ @Test
+ public void neverConstrainDisplayApis_flagsHasSingleEntry_returnsTrueForPackageWithinRange() {
+ setNeverConstrainDisplayApisFlag("com.android.test:1:1");
+
+ testNeverConstrainDisplayApis("com.android.other", /* version= */ 5, /* expected= */ false);
+ testNeverConstrainDisplayApis("com.android.test", /* version= */ 0, /* expected= */ false);
+ testNeverConstrainDisplayApis("com.android.test", /* version= */ 1, /* expected= */ true);
+ testNeverConstrainDisplayApis("com.android.test", /* version= */ 2, /* expected= */ false);
+ }
+
+ @Test
+ public void neverConstrainDisplayApis_flagHasEntries_returnsTrueForPackagesWithinRange() {
+ setNeverConstrainDisplayApisFlag("com.android.test1::,com.android.test2:1:3,"
+ + "com.android.test3:5:,com.android.test4::8");
+
+ // Package 'com.android.other'
+ testNeverConstrainDisplayApis("com.android.other", /* version= */ 5, /* expected= */ false);
+ // Package 'com.android.test1'
+ testNeverConstrainDisplayApis("com.android.test1", /* version= */ 5, /* expected= */ true);
+ // Package 'com.android.test2'
+ testNeverConstrainDisplayApis("com.android.test2", /* version= */ 0, /* expected= */ false);
+ testNeverConstrainDisplayApis("com.android.test2", /* version= */ 1, /* expected= */ true);
+ testNeverConstrainDisplayApis("com.android.test2", /* version= */ 2, /* expected= */ true);
+ testNeverConstrainDisplayApis("com.android.test2", /* version= */ 3, /* expected= */ true);
+ testNeverConstrainDisplayApis("com.android.test2", /* version= */ 4, /* expected= */ false);
+ // Package 'com.android.test3'
+ testNeverConstrainDisplayApis("com.android.test3", /* version= */ 4, /* expected= */ false);
+ testNeverConstrainDisplayApis("com.android.test3", /* version= */ 5, /* expected= */ true);
+ testNeverConstrainDisplayApis("com.android.test3", /* version= */ 6, /* expected= */ true);
+ // Package 'com.android.test4'
+ testNeverConstrainDisplayApis("com.android.test4", /* version= */ 7, /* expected= */ true);
+ testNeverConstrainDisplayApis("com.android.test4", /* version= */ 8, /* expected= */ true);
+ testNeverConstrainDisplayApis("com.android.test4", /* version= */ 9, /* expected= */ false);
+ }
+
+ @Test
+ public void neverConstrainDisplayApis_flagHasInvalidEntries_ignoresInvalidEntries() {
+ // We add a valid entry before and after the invalid ones to make sure they are applied.
+ setNeverConstrainDisplayApisFlag("com.android.test1::,com.android.test2:1,"
+ + "com.android.test3:5:ten,com.android.test4:5::,com.android.test5::");
+
+ testNeverConstrainDisplayApis("com.android.test1", /* version= */ 5, /* expected= */ true);
+ testNeverConstrainDisplayApis("com.android.test2", /* version= */ 2, /* expected= */ false);
+ testNeverConstrainDisplayApis("com.android.test3", /* version= */ 7, /* expected= */ false);
+ testNeverConstrainDisplayApis("com.android.test4", /* version= */ 7, /* expected= */ false);
+ testNeverConstrainDisplayApis("com.android.test5", /* version= */ 5, /* expected= */ true);
+ }
+
+ private static void testNeverConstrainDisplayApis(String packageName, long version,
+ boolean expected) {
+ boolean result = ConstrainDisplayApisConfig.neverConstrainDisplayApis(
+ buildApplicationInfo(packageName, version));
+ if (expected) {
+ assertTrue(result);
+ } else {
+ assertFalse(result);
+ }
+ }
+
+ private static ApplicationInfo buildApplicationInfo(String packageName, long version) {
+ ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.packageName = packageName;
+ applicationInfo.longVersionCode = version;
+ return applicationInfo;
+ }
+
+ private static void setNeverConstrainDisplayApisFlag(@Nullable String value) {
+ DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, "never_constrain_display_apis",
+ value, /* makeDefault= */ false);
+ }
+
+ private static void setNeverConstrainDisplayApisAllPackagesFlag(@Nullable String value) {
+ DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS,
+ "never_constrain_display_apis_all_packages",
+ value, /* makeDefault= */ false);
+ }
+
+ private static void clearConstrainDisplayApisFlags() {
+ setNeverConstrainDisplayApisFlag(null);
+ setNeverConstrainDisplayApisAllPackagesFlag(null);
+ }
+}
diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java b/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java
index 8b39beb..3e1db36 100644
--- a/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java
+++ b/core/tests/coretests/src/android/hardware/input/InputDeviceLightsManagerTest.java
@@ -23,6 +23,8 @@
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertNotNull;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -128,9 +130,12 @@
assertNotNull(device);
Light[] mockedLights = {
- new Light(1 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_SINGLE),
- new Light(2 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_RGB),
- new Light(3 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_PLAYER_ID)
+ new Light(1 /* id */, "Light1", 0 /* ordinal */, Light.LIGHT_TYPE_INPUT,
+ Light.LIGHT_CAPABILITY_BRIGHTNESS),
+ new Light(2 /* id */, "Light2", 0 /* ordinal */, Light.LIGHT_TYPE_INPUT,
+ Light.LIGHT_CAPABILITY_RGB),
+ new Light(3 /* id */, "Light3", 0 /* ordinal */, Light.LIGHT_TYPE_INPUT,
+ 0 /* capabilities */)
};
mockLights(mockedLights);
@@ -146,10 +151,14 @@
assertNotNull(device);
Light[] mockedLights = {
- new Light(1 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_RGB),
- new Light(2 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_RGB),
- new Light(3 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_RGB),
- new Light(4 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_RGB)
+ new Light(1 /* id */, "Light1", 0 /* ordinal */, Light.LIGHT_TYPE_INPUT,
+ Light.LIGHT_CAPABILITY_RGB),
+ new Light(2 /* id */, "Light2", 0 /* ordinal */, Light.LIGHT_TYPE_INPUT,
+ Light.LIGHT_CAPABILITY_RGB),
+ new Light(3 /* id */, "Light3", 0 /* ordinal */, Light.LIGHT_TYPE_INPUT,
+ Light.LIGHT_CAPABILITY_RGB),
+ new Light(4 /* id */, "Light4", 0 /* ordinal */, Light.LIGHT_TYPE_INPUT,
+ Light.LIGHT_CAPABILITY_RGB)
};
mockLights(mockedLights);
@@ -194,9 +203,12 @@
assertNotNull(device);
Light[] mockedLights = {
- new Light(1 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_PLAYER_ID),
- new Light(2 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_SINGLE),
- new Light(3 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_RGB),
+ new Light(1 /* id */, "Light1", 0 /* ordinal */, Light.LIGHT_TYPE_PLAYER_ID,
+ 0 /* capabilities */),
+ new Light(2 /* id */, "Light2", 0 /* ordinal */, Light.LIGHT_TYPE_INPUT,
+ Light.LIGHT_CAPABILITY_RGB | Light.LIGHT_CAPABILITY_BRIGHTNESS),
+ new Light(3 /* id */, "Light3", 0 /* ordinal */, Light.LIGHT_TYPE_INPUT,
+ Light.LIGHT_CAPABILITY_BRIGHTNESS)
};
mockLights(mockedLights);
@@ -227,23 +239,42 @@
}
@Test
+ public void testLightCapabilities() throws Exception {
+ Light light = new Light(1 /* id */, "Light1", 0 /* ordinal */, Light.LIGHT_TYPE_INPUT,
+ Light.LIGHT_CAPABILITY_RGB | Light.LIGHT_CAPABILITY_BRIGHTNESS);
+ assertThat(light.getType()).isEqualTo(Light.LIGHT_TYPE_INPUT);
+ assertThat(light.getCapabilities()).isEqualTo(Light.LIGHT_CAPABILITY_RGB
+ | Light.LIGHT_CAPABILITY_BRIGHTNESS);
+ assertTrue(light.hasBrightnessControl());
+ assertTrue(light.hasRgbControl());
+ }
+
+ @Test
public void testLightsRequest() throws Exception {
- Light light = new Light(1 /* id */, 0 /* ordinal */, Light.LIGHT_TYPE_INPUT_PLAYER_ID);
- LightState state = new LightState(0xf1);
- LightsRequest request = new Builder().addLight(light, state).build();
+ Light light1 = new Light(1 /* id */, "Light1", 0 /* ordinal */, Light.LIGHT_TYPE_INPUT,
+ 0 /* capabilities */);
+ Light light2 = new Light(2 /* id */, "Light2", 0 /* ordinal */, Light.LIGHT_TYPE_PLAYER_ID,
+ 0 /* capabilities */);
+ LightState state1 = new LightState(0xf1);
+ LightState state2 = new LightState(0xf2, PLAYER_ID);
+ LightsRequest request = new Builder().addLight(light1, state1)
+ .addLight(light2, state2).build();
// Covers the LightsRequest.getLights
- assertThat(request.getLights().size()).isEqualTo(1);
+ assertThat(request.getLights().size()).isEqualTo(2);
assertThat(request.getLights().get(0)).isEqualTo(1);
+ assertThat(request.getLights().get(1)).isEqualTo(2);
// Covers the LightsRequest.getLightStates
- assertThat(request.getLightStates().size()).isEqualTo(1);
- assertThat(request.getLightStates().get(0)).isEqualTo(state);
+ assertThat(request.getLightStates().size()).isEqualTo(2);
+ assertThat(request.getLightStates().get(0)).isEqualTo(state1);
+ assertThat(request.getLightStates().get(1)).isEqualTo(state2);
// Covers the LightsRequest.getLightsAndStates
- assertThat(request.getLightsAndStates().size()).isEqualTo(1);
- assertThat(request.getLightsAndStates().containsKey(1)).isTrue();
- assertThat(request.getLightsAndStates().get(1)).isEqualTo(state);
+ assertThat(request.getLightsAndStates().size()).isEqualTo(2);
+ assertThat(request.getLightsAndStates().containsKey(light1)).isTrue();
+ assertThat(request.getLightsAndStates().get(light1)).isEqualTo(state1);
+ assertThat(request.getLightsAndStates().get(light2)).isEqualTo(state2);
}
}
diff --git a/core/tests/coretests/src/android/os/PackageTagsListTest.java b/core/tests/coretests/src/android/os/PackageTagsListTest.java
new file mode 100644
index 0000000..518e02e
--- /dev/null
+++ b/core/tests/coretests/src/android/os/PackageTagsListTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.os;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.Presubmit;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class PackageTagsListTest {
+
+ @Test
+ public void testPackageTagsList() {
+ PackageTagsList.Builder builder = new PackageTagsList.Builder()
+ .add("package1", "attr1")
+ .add("package1", "attr2")
+ .add("package2");
+ PackageTagsList list = builder.build();
+
+ assertTrue(list.contains(builder.build()));
+ assertTrue(list.contains("package1", "attr1"));
+ assertTrue(list.contains("package1", "attr2"));
+ assertTrue(list.contains("package2", "attr1"));
+ assertTrue(list.contains("package2", "attr2"));
+ assertTrue(list.contains("package2", "attr3"));
+ assertTrue(list.containsAll("package2"));
+ assertTrue(list.includes("package1"));
+ assertTrue(list.includes("package2"));
+ assertFalse(list.contains("package1", "attr3"));
+ assertFalse(list.containsAll("package1"));
+ assertFalse(list.includes("package3"));
+
+ PackageTagsList bigList = builder.add("package3").build();
+ assertTrue(bigList.contains(builder.build()));
+ assertTrue(bigList.contains(list));
+ assertFalse(list.contains(bigList));
+ }
+
+ @Test
+ public void testPackageTagsList_BuildFromMap() {
+ ArrayMap<String, ArraySet<String>> map = new ArrayMap<>();
+ map.put("package1", new ArraySet<>(Arrays.asList("attr1", "attr2")));
+ map.put("package2", new ArraySet<>());
+
+ PackageTagsList.Builder builder = new PackageTagsList.Builder().add(map);
+ PackageTagsList list = builder.build();
+
+ assertTrue(list.contains(builder.build()));
+ assertTrue(list.contains("package1", "attr1"));
+ assertTrue(list.contains("package1", "attr2"));
+ assertTrue(list.contains("package2", "attr1"));
+ assertTrue(list.contains("package2", "attr2"));
+ assertTrue(list.contains("package2", "attr3"));
+ assertTrue(list.containsAll("package2"));
+ assertTrue(list.includes("package1"));
+ assertTrue(list.includes("package2"));
+ assertFalse(list.contains("package1", "attr3"));
+ assertFalse(list.containsAll("package1"));
+ assertFalse(list.includes("package3"));
+
+ map.put("package3", new ArraySet<>());
+ PackageTagsList bigList = builder.add(map).build();
+ assertTrue(bigList.contains(builder.build()));
+ assertTrue(bigList.contains(list));
+ assertFalse(list.contains(bigList));
+ }
+
+ @Test
+ public void testWriteToParcel() {
+ PackageTagsList list = new PackageTagsList.Builder()
+ .add("package1", "attr1")
+ .add("package1", "attr2")
+ .add("package2")
+ .build();
+ Parcel parcel = Parcel.obtain();
+ list.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ PackageTagsList newList = PackageTagsList.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+
+ assertEquals(list, newList);
+ }
+}
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 613232f..8fd1af8 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -110,7 +110,7 @@
mController = new InsetsAnimationControlImpl(controls,
new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
mMockController, 10 /* durationMs */, new LinearInterpolator(),
- 0 /* animationType */, null /* translator */);
+ 0 /* animationType */, 0 /* layoutInsetsDuringAnimation */, null /* translator */);
mController.mReadyDispatched = true;
}
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index cfe3803..3bd2939 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -315,6 +315,51 @@
}
@Test
+ public void testEquals_samePrivacyIndicator() {
+ Rect one = new Rect(0, 1, 2, 3);
+ Rect two = new Rect(4, 5, 6, 7);
+ Rect[] bounds = new Rect[] { one, two, one, two };
+ mState.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(bounds, 0));
+ mState2.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(bounds, 0));
+ assertEqualsAndHashCode();
+ }
+
+ @Test
+ public void testEquals_differentPrivacyIndicatorStaticBounds() {
+ Rect one = new Rect(0, 1, 2, 3);
+ Rect two = new Rect(4, 5, 6, 7);
+ Rect three = new Rect(8, 9, 10, 11);
+ Rect[] boundsOne = new Rect[] { one, two, one, two };
+ Rect[] boundsDifferent = new Rect[] { one, two, three, one };
+ Rect[] boundsDifferentOrder = new Rect[] { two, one, one, two };
+ Rect[] boundsDifferentLength = new Rect[] { one, two };
+ Rect[] boundsNull = new Rect[4];
+ mState.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(boundsOne, 0));
+
+ mState2.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(boundsDifferent, 0));
+ assertNotEqualsAndHashCode();
+
+ mState2.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(boundsDifferentOrder, 0));
+ assertNotEqualsAndHashCode();
+
+ mState2.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(boundsDifferentLength, 0));
+ assertNotEqualsAndHashCode();
+
+ mState2.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(boundsNull, 0));
+ assertNotEqualsAndHashCode();
+ }
+
+ @Test
+ public void testEquals_differentPrivacyIndicatorRotation() {
+ Rect one = new Rect(0, 1, 2, 3);
+ Rect two = new Rect(4, 5, 6, 7);
+ Rect[] arr = new Rect[] { one, two, one, two};
+ mState.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(arr, 0));
+ mState2.setPrivacyIndicatorBounds(new PrivacyIndicatorBounds(arr, 1));
+ assertNotEqualsAndHashCode();
+ }
+
+ @Test
public void testEquals_excludeInvisibleIme() {
mState.getSource(ITYPE_IME).setFrame(new Rect(0, 0, 100, 100));
mState.getSource(ITYPE_IME).setVisible(false);
diff --git a/core/tests/coretests/src/android/view/TunnelModeEnabledListenerTest.java b/core/tests/coretests/src/android/view/TunnelModeEnabledListenerTest.java
new file mode 100644
index 0000000..65dd34f
--- /dev/null
+++ b/core/tests/coretests/src/android/view/TunnelModeEnabledListenerTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+@Presubmit
+public class TunnelModeEnabledListenerTest {
+ private TestableTunnelModeEnabledListener mListener;
+
+ @Before
+ public void init() {
+ mListener = new TestableTunnelModeEnabledListener();
+ }
+
+ @Test
+ public void testRegisterUnregister() {
+ TunnelModeEnabledListener.register(mListener);
+ TunnelModeEnabledListener.unregister(mListener);
+ }
+
+ @Test
+ public void testDispatchUpdatesListener() {
+ TunnelModeEnabledListener.dispatchOnTunnelModeEnabledChanged(mListener, true);
+ assertEquals(true, mListener.mTunnelModeEnabled.get());
+ TunnelModeEnabledListener.dispatchOnTunnelModeEnabledChanged(mListener, false);
+ assertEquals(false, mListener.mTunnelModeEnabled.get());
+ }
+
+ @Test
+ public void testRegisterUpdatesListener() throws Exception {
+ TunnelModeEnabledListener.register(mListener);
+ TimeUnit.SECONDS.sleep(1);
+ assertTrue(mListener.mTunnelModeEnabledUpdated.get());
+ TunnelModeEnabledListener.unregister(mListener);
+ }
+
+ private static class TestableTunnelModeEnabledListener extends TunnelModeEnabledListener {
+ AtomicBoolean mTunnelModeEnabled;
+ AtomicBoolean mTunnelModeEnabledUpdated;
+
+ TestableTunnelModeEnabledListener() {
+ super(Runnable::run);
+ mTunnelModeEnabled = new AtomicBoolean(false);
+ mTunnelModeEnabledUpdated = new AtomicBoolean();
+ }
+
+ @Override
+ public void onTunnelModeEnabledChanged(boolean tunnelModeEnabled) {
+ mTunnelModeEnabled.set(tunnelModeEnabled);
+ mTunnelModeEnabledUpdated.set(true);
+ }
+ }
+
+}
diff --git a/core/tests/coretests/src/android/view/WindowInsetsTest.java b/core/tests/coretests/src/android/view/WindowInsetsTest.java
index b80837f..dd9634b 100644
--- a/core/tests/coretests/src/android/view/WindowInsetsTest.java
+++ b/core/tests/coretests/src/android/view/WindowInsetsTest.java
@@ -61,7 +61,7 @@
WindowInsets.assignCompatInsets(maxInsets, new Rect(0, 10, 0, 0));
WindowInsets.assignCompatInsets(insets, new Rect(0, 0, 0, 0));
WindowInsets windowInsets = new WindowInsets(insets, maxInsets, visible, false, false, null,
- null, systemBars(), true /* compatIgnoreVisibility */);
+ null, null, systemBars(), true /* compatIgnoreVisibility */);
assertEquals(Insets.of(0, 10, 0, 0), windowInsets.getSystemWindowInsets());
}
}
diff --git a/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
deleted file mode 100644
index 833530d..0000000
--- a/core/tests/coretests/src/android/view/inputmethod/CursorAnchorInfoTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2014 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.view.inputmethod;
-
-import static org.junit.Assert.assertEquals;
-
-import android.graphics.Matrix;
-import android.view.inputmethod.CursorAnchorInfo.Builder;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class CursorAnchorInfoTest {
- @Test
- public void testCreateForAdditionalParentMatrix() {
- final Matrix originalMatrix = new Matrix();
- originalMatrix.setTranslate(10.0f, 20.0f);
- final Builder builder = new Builder();
- builder.setMatrix(originalMatrix);
-
- final CursorAnchorInfo originalInstance = builder.build();
-
- assertEquals(originalMatrix, originalInstance.getMatrix());
-
- final Matrix additionalParentMatrix = new Matrix();
- additionalParentMatrix.setTranslate(1.0f, 2.0f);
-
- final Matrix newMatrix = new Matrix(originalMatrix);
- newMatrix.postConcat(additionalParentMatrix);
-
- builder.reset();
- builder.setMatrix(newMatrix);
- // An instance created by the standard Builder class.
- final CursorAnchorInfo newInstanceByBuilder = builder.build();
-
- // An instance created by an @hide method.
- final CursorAnchorInfo newInstanceByMethod =
- CursorAnchorInfo.createForAdditionalParentMatrix(
- originalInstance, additionalParentMatrix);
-
- assertEquals(newMatrix, newInstanceByBuilder.getMatrix());
- assertEquals(newMatrix, newInstanceByMethod.getMatrix());
- assertEquals(newInstanceByBuilder.hashCode(), newInstanceByMethod.hashCode());
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 1633d28..19c2763 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -16,6 +16,8 @@
package com.android.internal.app;
+import static android.app.Activity.RESULT_OK;
+
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.swipeUp;
@@ -558,6 +560,8 @@
ClipDescription clipDescription = clipData.getDescription();
assertThat("text/plain", is(clipDescription.getMimeType(0)));
+
+ assertEquals(mActivityRule.getActivityResult().getResultCode(), RESULT_OK);
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
index 7f0449b..d83645d 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
@@ -59,8 +59,14 @@
30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_SERVICE,
30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
- batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
+ batteryStats.noteUidProcessStateLocked(APP_UID,
+ ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
40 * MINUTE_IN_MS, 40 * MINUTE_IN_MS);
+ batteryStats.noteUidProcessStateLocked(APP_UID,
+ ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE,
+ 50 * MINUTE_IN_MS, 50 * MINUTE_IN_MS);
+ batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
+ 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
mStatsRule.setCurrentTime(54321);
@@ -74,7 +80,7 @@
batteryUsageStats.getUidBatteryConsumers();
final UidBatteryConsumer uidBatteryConsumer = uidBatteryConsumers.get(0);
assertThat(uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND))
- .isEqualTo(20 * MINUTE_IN_MS);
+ .isEqualTo(60 * MINUTE_IN_MS);
assertThat(uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND))
.isEqualTo(10 * MINUTE_IN_MS);
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index e2e672e..55943a0 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -241,6 +241,34 @@
assertEquals(10, callStats.maxCpuTimeMicros);
}
+ @Test
+ public void testSharding() {
+ TestBinderCallsStats bcs = new TestBinderCallsStats();
+ bcs.setShardingModulo(2);
+
+ Binder binder = new Binder();
+ CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
+ bcs.time += 10;
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
+
+ callSession = bcs.callStarted(binder, 2 /* another method */, WORKSOURCE_UID);
+ bcs.time += 10;
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
+
+
+ SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries();
+ assertEquals(1, uidEntries.size());
+ BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID);
+ assertEquals(2, uidEntry.callCount);
+ assertEquals(2, uidEntry.recordedCallCount);
+
+ List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList());
+ assertEquals(2, callStatsList.size());
+
+ assertEquals(1, bcs.getExportedCallStats(true).size());
+ assertEquals(2, bcs.getExportedCallStats(false).size());
+ }
+
private static class BinderWithGetTransactionName extends Binder {
public static String getDefaultTransactionName(int code) {
return "resolved";
@@ -669,7 +697,7 @@
bcs.setAddDebugEntries(true);
bcs.setSamplingInterval(10);
ArrayList<BinderCallsStats.ExportedCallStat> callStats = bcs.getExportedCallStats();
- assertEquals(4, callStats.size());
+ assertEquals(5, callStats.size());
BinderCallsStats.ExportedCallStat debugEntry1 = callStats.get(0);
assertEquals("", debugEntry1.className);
assertEquals("__DEBUG_start_time_millis", debugEntry1.methodName);
@@ -685,6 +713,9 @@
BinderCallsStats.ExportedCallStat debugEntry4 = callStats.get(3);
assertEquals("__DEBUG_sampling_interval", debugEntry4.methodName);
assertEquals(10, debugEntry4.latencyMicros);
+ BinderCallsStats.ExportedCallStat debugEntry5 = callStats.get(4);
+ assertEquals("__DEBUG_sharding_modulo", debugEntry5.methodName);
+ assertEquals(1, debugEntry5.latencyMicros);
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
index cd45060..a36d9fe 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -18,25 +18,28 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.os.BatteryConsumer;
-import android.os.BatteryStats;
-import android.os.BatteryUsageStatsQuery;
import android.os.Binder;
import android.os.Process;
-import android.os.UidBatteryConsumer;
-import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.power.MeasuredEnergyStats;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.io.IOException;
import java.util.ArrayList;
@@ -47,6 +50,8 @@
public class SystemServicePowerCalculatorTest {
private static final double PRECISION = 0.000001;
+ private static final int APP_UID1 = 100;
+ private static final int APP_UID2 = 200;
@Rule
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
@@ -61,73 +66,52 @@
.setAveragePowerForCpuCore(1, 0, 500)
.setAveragePowerForCpuCore(1, 1, 600);
+ @Mock
private BatteryStatsImpl.UserInfoProvider mMockUserInfoProvider;
+ @Mock
+ private KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader mMockKernelCpuUidClusterTimeReader;
+ @Mock
+ private KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader mMockCpuUidFreqTimeReader;
+ @Mock
+ private KernelCpuUidTimeReader.KernelCpuUidUserSysTimeReader mMockKernelCpuUidUserSysTimeReader;
+ @Mock
+ private KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader mMockKerneCpuUidActiveTimeReader;
+ @Mock
+ private SystemServerCpuThreadReader mMockSystemServerCpuThreadReader;
+
+ private final KernelCpuSpeedReader[] mMockKernelCpuSpeedReaders = new KernelCpuSpeedReader[]{
+ mock(KernelCpuSpeedReader.class),
+ mock(KernelCpuSpeedReader.class),
+ };
+
private MockBatteryStatsImpl mMockBatteryStats;
- private MockKernelCpuUidFreqTimeReader mMockCpuUidFreqTimeReader;
- private MockSystemServerCpuThreadReader mMockSystemServerCpuThreadReader;
@Before
public void setUp() throws IOException {
- mMockUserInfoProvider = mock(BatteryStatsImpl.UserInfoProvider.class);
- mMockSystemServerCpuThreadReader = new MockSystemServerCpuThreadReader();
- mMockCpuUidFreqTimeReader = new MockKernelCpuUidFreqTimeReader();
+ MockitoAnnotations.initMocks(this);
mMockBatteryStats = mStatsRule.getBatteryStats()
- .setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader)
+ .setUserInfoProvider(mMockUserInfoProvider)
+ .setKernelCpuSpeedReaders(mMockKernelCpuSpeedReaders)
.setKernelCpuUidFreqTimeReader(mMockCpuUidFreqTimeReader)
- .setUserInfoProvider(mMockUserInfoProvider);
+ .setKernelCpuUidClusterTimeReader(mMockKernelCpuUidClusterTimeReader)
+ .setKernelCpuUidUserSysTimeReader(mMockKernelCpuUidUserSysTimeReader)
+ .setKernelCpuUidActiveTimeReader(mMockKerneCpuUidActiveTimeReader)
+ .setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader);
}
@Test
public void testPowerProfileBasedModel() {
- when(mMockUserInfoProvider.exists(anyInt())).thenReturn(true);
-
- // Test Power Profile has two CPU clusters with 2 speeds each, thus 4 freq times total
- mMockSystemServerCpuThreadReader.setCpuTimes(
- new long[] {30000, 40000, 50000, 60000},
- new long[] {20000, 30000, 40000, 50000});
-
- mMockCpuUidFreqTimeReader.setSystemServerCpuTimes(
- new long[] {10000, 20000, 30000, 40000}
- );
-
- mMockBatteryStats.readKernelUidCpuFreqTimesLocked(null, true, false, null);
-
- int workSourceUid1 = 100;
- int workSourceUid2 = 200;
- int transactionCode = 42;
-
- Collection<BinderCallsStats.CallStat> callStats = new ArrayList<>();
- BinderCallsStats.CallStat stat1 = new BinderCallsStats.CallStat(workSourceUid1,
- Binder.class, transactionCode, true /*screenInteractive */);
- stat1.incrementalCallCount = 100;
- stat1.recordedCallCount = 100;
- stat1.cpuTimeMicros = 1000000;
- callStats.add(stat1);
-
- mMockBatteryStats.noteBinderCallStats(workSourceUid1, 100, callStats);
-
- callStats.clear();
- BinderCallsStats.CallStat stat2 = new BinderCallsStats.CallStat(workSourceUid2,
- Binder.class, transactionCode, true /*screenInteractive */);
- stat2.incrementalCallCount = 100;
- stat2.recordedCallCount = 100;
- stat2.cpuTimeMicros = 9000000;
- callStats.add(stat2);
-
- mMockBatteryStats.noteBinderCallStats(workSourceUid2, 100, callStats);
-
- mMockBatteryStats.updateSystemServiceCallStats();
- mMockBatteryStats.updateSystemServerThreadStats();
+ prepareBatteryStats(null);
SystemServicePowerCalculator calculator = new SystemServicePowerCalculator(
mStatsRule.getPowerProfile());
- mStatsRule.apply(new FakeCpuPowerCalculator(), calculator);
+ mStatsRule.apply(new CpuPowerCalculator(mStatsRule.getPowerProfile()), calculator);
- assertThat(mStatsRule.getUidBatteryConsumer(workSourceUid1)
+ assertThat(mStatsRule.getUidBatteryConsumer(APP_UID1)
.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES))
.isWithin(PRECISION).of(1.888888);
- assertThat(mStatsRule.getUidBatteryConsumer(workSourceUid2)
+ assertThat(mStatsRule.getUidBatteryConsumer(APP_UID2)
.getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES))
.isWithin(PRECISION).of(17.0);
assertThat(mStatsRule.getUidBatteryConsumer(Process.SYSTEM_UID)
@@ -141,58 +125,105 @@
.isWithin(PRECISION).of(18.888888);
}
- private static class MockKernelCpuUidFreqTimeReader extends
- KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader {
- private long[] mSystemServerCpuTimes;
+ @Test
+ public void testMeasuredEnergyBasedModel() {
+ final boolean[] supportedPowerBuckets =
+ new boolean[MeasuredEnergyStats.NUMBER_STANDARD_POWER_BUCKETS];
+ supportedPowerBuckets[MeasuredEnergyStats.POWER_BUCKET_CPU] = true;
+ mStatsRule.getBatteryStats()
+ .initMeasuredEnergyStatsLocked(supportedPowerBuckets, new String[0]);
- MockKernelCpuUidFreqTimeReader() {
- super(/*throttle */false);
- }
+ prepareBatteryStats(new long[]{50000000, 100000000});
- void setSystemServerCpuTimes(long[] systemServerCpuTimes) {
- mSystemServerCpuTimes = systemServerCpuTimes;
- }
+ SystemServicePowerCalculator calculator = new SystemServicePowerCalculator(
+ mStatsRule.getPowerProfile());
- @Override
- public boolean perClusterTimesAvailable() {
- return true;
- }
+ mStatsRule.apply(new CpuPowerCalculator(mStatsRule.getPowerProfile()), calculator);
- @Override
- public void readDelta(boolean forcedRead, @Nullable Callback<long[]> cb) {
- if (cb != null) {
- cb.onUidCpuTime(Process.SYSTEM_UID, mSystemServerCpuTimes);
- }
- }
+ assertThat(mStatsRule.getUidBatteryConsumer(APP_UID1)
+ .getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES))
+ .isWithin(PRECISION).of(1.979351);
+ assertThat(mStatsRule.getUidBatteryConsumer(APP_UID2)
+ .getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES))
+ .isWithin(PRECISION).of(17.814165);
+ assertThat(mStatsRule.getUidBatteryConsumer(Process.SYSTEM_UID)
+ .getConsumedPower(BatteryConsumer.POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS))
+ .isWithin(PRECISION).of(-19.793517);
+ assertThat(mStatsRule.getDeviceBatteryConsumer()
+ .getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES))
+ .isWithin(PRECISION).of(19.793517);
+ assertThat(mStatsRule.getAppsBatteryConsumer()
+ .getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES))
+ .isWithin(PRECISION).of(19.793517);
}
- private static class MockSystemServerCpuThreadReader extends SystemServerCpuThreadReader {
- private final SystemServiceCpuThreadTimes mThreadTimes = new SystemServiceCpuThreadTimes();
+ private void prepareBatteryStats(long[] clusterChargesUc) {
+ when(mMockUserInfoProvider.exists(anyInt())).thenReturn(true);
- MockSystemServerCpuThreadReader() {
- super(null);
- }
+ when(mMockKernelCpuSpeedReaders[0].readDelta()).thenReturn(new long[]{1000, 2000});
+ when(mMockKernelCpuSpeedReaders[1].readDelta()).thenReturn(new long[]{3000, 4000});
- public void setCpuTimes(long[] threadCpuTimesUs, long[] binderThreadCpuTimesUs) {
- mThreadTimes.threadCpuTimesUs = threadCpuTimesUs;
- mThreadTimes.binderThreadCpuTimesUs = binderThreadCpuTimesUs;
- }
+ when(mMockCpuUidFreqTimeReader.perClusterTimesAvailable()).thenReturn(false);
- @Override
- public SystemServiceCpuThreadTimes readDelta() {
- return mThreadTimes;
- }
- }
+ // User/System CPU time in microseconds
+ doAnswer(invocation -> {
+ final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1);
+ callback.onUidCpuTime(APP_UID1, new long[]{1_000_000, 2_000_000});
+ callback.onUidCpuTime(APP_UID2, new long[]{3_000_000, 4_000_000});
+ callback.onUidCpuTime(Process.SYSTEM_UID, new long[]{60_000_000, 80_000_000});
+ return null;
+ }).when(mMockKernelCpuUidUserSysTimeReader).readDelta(anyBoolean(), any());
- private static class FakeCpuPowerCalculator extends PowerCalculator {
- @Override
- protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u,
- long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
- if (u.getUid() == Process.SYSTEM_UID) {
- // SystemServer must be attributed at least as much power as the total
- // of all system services requested by apps.
- app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 1000000);
- }
- }
+ // Active CPU time in milliseconds
+ doAnswer(invocation -> {
+ final KernelCpuUidTimeReader.Callback<Long> callback = invocation.getArgument(1);
+ callback.onUidCpuTime(APP_UID1, 1111L);
+ callback.onUidCpuTime(APP_UID2, 3333L);
+ callback.onUidCpuTime(Process.SYSTEM_UID, 10000L);
+ return null;
+ }).when(mMockKerneCpuUidActiveTimeReader).readDelta(anyBoolean(), any());
+
+ // Per-cluster CPU time in milliseconds
+ doAnswer(invocation -> {
+ final KernelCpuUidTimeReader.Callback<long[]> callback = invocation.getArgument(1);
+ callback.onUidCpuTime(APP_UID1, new long[]{1111, 2222});
+ callback.onUidCpuTime(APP_UID2, new long[]{3333, 4444});
+ callback.onUidCpuTime(Process.SYSTEM_UID, new long[]{50_000, 80_000});
+ return null;
+ }).when(mMockKernelCpuUidClusterTimeReader).readDelta(anyBoolean(), any());
+
+ // System service CPU time
+ final SystemServerCpuThreadReader.SystemServiceCpuThreadTimes threadTimes =
+ new SystemServerCpuThreadReader.SystemServiceCpuThreadTimes();
+ threadTimes.binderThreadCpuTimesUs =
+ new long[]{20_000_000, 30_000_000, 40_000_000, 50_000_000};
+
+ when(mMockSystemServerCpuThreadReader.readDelta()).thenReturn(threadTimes);
+
+ int transactionCode = 42;
+
+ Collection<BinderCallsStats.CallStat> callStats = new ArrayList<>();
+ BinderCallsStats.CallStat stat1 = new BinderCallsStats.CallStat(APP_UID1,
+ Binder.class, transactionCode, true /*screenInteractive */);
+ stat1.incrementalCallCount = 100;
+ stat1.recordedCallCount = 100;
+ stat1.cpuTimeMicros = 1_000_000;
+ callStats.add(stat1);
+
+ mMockBatteryStats.noteBinderCallStats(APP_UID1, 100, callStats);
+
+ callStats.clear();
+ BinderCallsStats.CallStat stat2 = new BinderCallsStats.CallStat(APP_UID2,
+ Binder.class, transactionCode, true /*screenInteractive */);
+ stat2.incrementalCallCount = 100;
+ stat2.recordedCallCount = 100;
+ stat2.cpuTimeMicros = 9_000_000;
+ callStats.add(stat2);
+
+ mMockBatteryStats.noteBinderCallStats(APP_UID2, 100, callStats);
+
+ mMockBatteryStats.updateCpuTimeLocked(true, true, clusterChargesUc);
+
+ mMockBatteryStats.prepareForDumpLocked();
}
}
diff --git a/core/xsd/permission.xsd b/core/xsd/permission.xsd
index 5435047..0ec8f7d 100644
--- a/core/xsd/permission.xsd
+++ b/core/xsd/permission.xsd
@@ -98,6 +98,7 @@
</xs:complexType>
<xs:complexType name="allow-ignore-location-settings">
<xs:attribute name="package" type="xs:string"/>
+ <xs:attribute name="attributionTag" type="xs:string"/>
</xs:complexType>
<xs:complexType name="allow-implicit-broadcast">
<xs:attribute name="action" type="xs:string"/>
diff --git a/core/xsd/schema/current.txt b/core/xsd/schema/current.txt
index c36c422..f3beea1 100644
--- a/core/xsd/schema/current.txt
+++ b/core/xsd/schema/current.txt
@@ -11,7 +11,9 @@
public class AllowIgnoreLocationSettings {
ctor public AllowIgnoreLocationSettings();
+ method public String getAttributionTag();
method public String get_package();
+ method public void setAttributionTag(String);
method public void set_package(String);
}
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index 5aacfdd..ea23aba 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -10,6 +10,7 @@
svetoslavganov@google.com
toddke@android.com
toddke@google.com
+patb@google.com
yamasani@google.com
per-file preinstalled-packages* = file:/MULTIUSER_OWNERS
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 19332c7..8d4739d 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -473,6 +473,7 @@
<permission name="android.permission.UPDATE_FONTS" />
<!-- Permission required for hotword detection service CTS tests -->
<permission name="android.permission.MANAGE_HOTWORD_DETECTION" />
+ <permission name="android.permission.BIND_HOTWORD_DETECTION_SERVICE" />
<permission name="android.permission.MANAGE_APP_HIBERNATION"/>
<!-- Permission required for CTS test - ResourceObserverNativeTest -->
<permission name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" />
diff --git a/framework-jarjar-rules.txt b/framework-jarjar-rules.txt
index 52ee63a..be21f4e 100644
--- a/framework-jarjar-rules.txt
+++ b/framework-jarjar-rules.txt
@@ -1,3 +1,7 @@
+# This rule is meant to be reused across libraries in the bootclasspath that depend
+# on the HIDL libraries.
rule android.hidl.** android.internal.hidl.@1
+
+# Framework-specific renames.
rule android.net.wifi.WifiAnnotations* android.internal.wifi.WifiAnnotations@1
rule com.android.server.vcn.util.** com.android.server.vcn.repackaged.util.@1
diff --git a/graphics/java/android/graphics/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
index ee867dd..55fb83c 100644
--- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java
+++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
@@ -40,9 +40,9 @@
public final class RippleAnimationSession {
private static final String TAG = "RippleAnimationSession";
private static final int ENTER_ANIM_DURATION = 450;
- private static final int EXIT_ANIM_DURATION = 225;
+ private static final int EXIT_ANIM_DURATION = 375;
private static final long NOISE_ANIMATION_DURATION = 7000;
- private static final long MAX_NOISE_PHASE = NOISE_ANIMATION_DURATION / 120;
+ private static final long MAX_NOISE_PHASE = NOISE_ANIMATION_DURATION / 214;
private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
private static final Interpolator FAST_OUT_SLOW_IN =
new PathInterpolator(0.4f, 0f, 0.2f, 1f);
@@ -61,12 +61,12 @@
}
@NonNull RippleAnimationSession enter(Canvas canvas) {
+ mStartTime = AnimationUtils.currentAnimationTimeMillis();
if (isHwAccelerated(canvas)) {
enterHardware((RecordingCanvas) canvas);
} else {
enterSoftware();
}
- mStartTime = AnimationUtils.currentAnimationTimeMillis();
return this;
}
@@ -160,7 +160,8 @@
RenderNodeAnimator expand =
new RenderNodeAnimator(props.getProgress(), .5f);
expand.setTarget(canvas);
- RenderNodeAnimator loop = new RenderNodeAnimator(props.getNoisePhase(), MAX_NOISE_PHASE);
+ RenderNodeAnimator loop = new RenderNodeAnimator(props.getNoisePhase(),
+ mStartTime + MAX_NOISE_PHASE);
loop.setTarget(canvas);
startAnimation(expand, loop);
}
@@ -190,7 +191,7 @@
notifyUpdate();
mProperties.getShader().setProgress((float) expand.getAnimatedValue());
});
- ValueAnimator loop = ValueAnimator.ofFloat(0f, MAX_NOISE_PHASE);
+ ValueAnimator loop = ValueAnimator.ofFloat(mStartTime, mStartTime + MAX_NOISE_PHASE);
loop.addUpdateListener(updatedAnimation -> {
notifyUpdate();
mProperties.getShader().setNoisePhase((float) loop.getAnimatedValue());
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 518fceb..7ad46a1 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -50,6 +50,7 @@
import android.graphics.Shader;
import android.os.Build;
import android.util.AttributeSet;
+import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import com.android.internal.R;
@@ -151,7 +152,7 @@
/** The maximum number of ripples supported. */
private static final int MAX_RIPPLES = 10;
private static final LinearInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
- private static final int DEFAULT_EFFECT_COLOR = 0x80ffffff;
+ private static final int DEFAULT_EFFECT_COLOR = 0x8dffffff;
/** Temporary flag for teamfood. **/
private static final boolean FORCE_PATTERNED_STYLE = true;
@@ -970,15 +971,16 @@
? mState.mColor.getColorForState(getState(), Color.BLACK)
: mMaskColorFilter.getColor());
final int effectColor = mState.mEffectColor.getColorForState(getState(), Color.MAGENTA);
+ final float noisePhase = AnimationUtils.currentAnimationTimeMillis();
shader.setColor(color, effectColor);
shader.setOrigin(cx, cy);
shader.setTouch(x, y);
- shader.setResolution(w, h, mState.mDensity);
- shader.setNoisePhase(0);
+ shader.setResolution(w, h);
+ shader.setNoisePhase(noisePhase);
shader.setRadius(radius);
shader.setProgress(.0f);
properties = new RippleAnimationSession.AnimationProperties<>(
- cx, cy, radius, 0f, p, 0f, color, shader);
+ cx, cy, radius, noisePhase, p, 0f, color, shader);
if (mMaskShader == null) {
shader.setShader(null);
} else {
@@ -1191,6 +1193,9 @@
mRipplePaint = new Paint();
mRipplePaint.setAntiAlias(true);
mRipplePaint.setStyle(Paint.Style.FILL);
+ if (mState.mRippleStyle == STYLE_PATTERNED) {
+ mRipplePaint.setDither(true);
+ }
}
final float x = mHotspotBounds.exactCenterX();
diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java
index e5651e0..57b3223 100644
--- a/graphics/java/android/graphics/drawable/RippleShader.java
+++ b/graphics/java/android/graphics/drawable/RippleShader.java
@@ -20,7 +20,6 @@
import android.graphics.Color;
import android.graphics.RuntimeShader;
import android.graphics.Shader;
-import android.util.DisplayMetrics;
final class RippleShader extends RuntimeShader {
private static final String SHADER_UNIFORMS = "uniform vec2 in_origin;\n"
@@ -58,7 +57,7 @@
+ " float s = 0.0;\n"
+ " for (float i = 0; i < 4; i += 1) {\n"
+ " float l = i * 0.1;\n"
- + " float h = l + 0.025;\n"
+ + " float h = l + 0.05;\n"
+ " float o = sin(PI * (t + 0.35 * i));\n"
+ " s += threshold(n + o, l, h);\n"
+ " }\n"
@@ -70,7 +69,7 @@
+ " return 1. - smoothstep(1. - blurHalf, 1. + blurHalf, d / radius);\n"
+ "}\n"
+ "float softRing(vec2 uv, vec2 xy, float radius, float progress, float blur) {\n"
- + " float thickness = 0.3 * radius;\n"
+ + " float thickness = 0.05 * radius;\n"
+ " float currentRadius = radius * progress;\n"
+ " float circle_outer = softCircle(uv, xy, currentRadius + thickness, blur);\n"
+ " float circle_inner = softCircle(uv, xy, max(currentRadius - thickness, 0.), "
@@ -93,7 +92,7 @@
+ " return softCircle(coord, vec2(normal_radius), radius, radius * 50.0);\n"
+ "}\n"
+ "float turbulence(vec2 uv, float t) {\n"
- + " const vec2 scale = vec2(1.5);\n"
+ + " const vec2 scale = vec2(0.8);\n"
+ " uv = uv * scale;\n"
+ " float g1 = circle_grid(scale, uv, t, in_tCircle1, in_tRotation1, 0.17);\n"
+ " float g2 = circle_grid(scale, uv, t, in_tCircle2, in_tRotation2, 0.2);\n"
@@ -102,12 +101,12 @@
+ " return saturate(0.45 + 0.8 * v);\n"
+ "}\n";
private static final String SHADER_MAIN = "vec4 main(vec2 p) {\n"
- + " float fadeIn = subProgress(0., 0.1, in_progress);\n"
- + " float scaleIn = subProgress(0., 0.45, in_progress);\n"
- + " float fadeOutNoise = subProgress(0.5, 0.95, in_progress);\n"
- + " float fadeOutRipple = subProgress(0.5, 1., in_progress);\n"
- + " vec2 center = mix(in_touch, in_origin, scaleIn);\n"
- + " float ring = softRing(p, center, in_maxRadius, scaleIn, 0.45);\n"
+ + " float fadeIn = subProgress(0., 0.13, in_progress);\n"
+ + " float scaleIn = subProgress(0., 1.0, in_progress);\n"
+ + " float fadeOutNoise = subProgress(0.4, 0.5, in_progress);\n"
+ + " float fadeOutRipple = subProgress(0.4, 1., in_progress);\n"
+ + " vec2 center = mix(in_touch, in_origin, saturate(in_progress * 2.0));\n"
+ + " float ring = softRing(p, center, in_maxRadius, scaleIn, 1.);\n"
+ " float alpha = min(fadeIn, 1. - fadeOutNoise);\n"
+ " vec2 uv = p * in_resolutionScale;\n"
+ " vec2 densityUv = uv - mod(uv, in_noiseScale);\n"
@@ -115,7 +114,7 @@
+ " float sparkleAlpha = sparkles(densityUv, in_noisePhase) * ring * alpha "
+ "* turbulence;\n"
+ " float fade = min(fadeIn, 1. - fadeOutRipple);\n"
- + " float waveAlpha = softCircle(p, center, in_maxRadius * scaleIn, 0.2) * fade "
+ + " float waveAlpha = softCircle(p, center, in_maxRadius * scaleIn, 1.) * fade "
+ "* in_color.a;\n"
+ " vec4 waveColor = vec4(in_color.rgb * waveAlpha, waveAlpha);\n"
+ " vec4 sparkleColor = vec4(in_sparkleColor.rgb * in_sparkleColor.a, "
@@ -139,7 +138,7 @@
}
public void setRadius(float radius) {
- setUniform("in_maxRadius", radius);
+ setUniform("in_maxRadius", radius * 2.3f);
}
public void setOrigin(float x, float y) {
@@ -204,8 +203,8 @@
sparkleColor.green(), sparkleColor.blue(), sparkleColor.alpha()});
}
- public void setResolution(float w, float h, int density) {
- final float densityScale = density * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ public void setResolution(float w, float h) {
+ final float densityScale = 2.1f;
setUniform("in_resolutionScale", new float[] {1f / w, 1f / h});
setUniform("in_noiseScale", new float[] {densityScale / w, densityScale / h});
}
diff --git a/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml b/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
index ab02a2e6..c09ae53 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_manage_button.xml
@@ -22,7 +22,8 @@
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_marginTop="8dp"
- android:layout_marginLeft="8dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginBottom="8dp"
android:focusable="true"
android:text="@string/manage_bubbles_text"
android:textSize="@*android:dimen/text_size_body_2_material"
diff --git a/libs/WindowManager/Shell/res/layout/bubble_menu_view.xml b/libs/WindowManager/Shell/res/layout/bubble_menu_view.xml
deleted file mode 100644
index d19b653..0000000
--- a/libs/WindowManager/Shell/res/layout/bubble_menu_view.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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.
- -->
-<com.android.wm.shell.bubbles.BubbleMenuView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:background="#66000000"
- android:visibility="gone"
- android:id="@+id/bubble_menu_container"
- tools:ignore="MissingClass">
-
- <FrameLayout
- android:layout_height="@dimen/bubble_menu_item_height"
- android:layout_width="wrap_content"
- android:background="#FFFFFF"
- android:id="@+id/bubble_menu_view">
-
- <ImageView
- android:id="@*android:id/icon"
- android:layout_width="@dimen/bubble_grid_item_icon_width"
- android:layout_height="@dimen/bubble_grid_item_icon_height"
- android:layout_marginTop="@dimen/bubble_grid_item_icon_top_margin"
- android:layout_marginBottom="@dimen/bubble_grid_item_icon_bottom_margin"
- android:layout_marginLeft="@dimen/bubble_grid_item_icon_side_margin"
- android:layout_marginRight="@dimen/bubble_grid_item_icon_side_margin"
- android:scaleType="centerInside"
- android:tint="@color/bubbles_icon_tint"
- />
- </FrameLayout>
-</com.android.wm.shell.bubbles.BubbleMenuView>
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index 3a0e84a..69aa31e 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Slaan oor na volgende"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Slaan oor na vorige"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Verander grootte"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Hou vas"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Laat los"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Program sal dalk nie met verdeelde skerm werk nie."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Program steun nie verdeelde skerm nie."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Program sal dalk nie op \'n sekondêre skerm werk nie."</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index fe2ac92f..c754e3ca 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"ወደ ቀጣይ ዝለል"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"ወደ ቀዳሚ ዝለል"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"መጠን ይቀይሩ"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"መተግበሪያ ከተከፈለ ማያ ገጽ ጋር ላይሠራ ይችላል"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"መተግበሪያው የተከፈለ ማያ ገጽን አይደግፍም።"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"መተግበሪያ በሁለተኛ ማሳያ ላይ ላይሠራ ይችላል።"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 3c4149c..ac72a3d 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"التخطي إلى التالي"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"التخطي إلى السابق"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"تغيير الحجم"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"إخفاء"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"إظهار"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"قد لا يعمل التطبيق بشكل سليم في وضع \"تقسيم الشاشة\"."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"التطبيق لا يتيح تقسيم الشاشة."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"قد لا يعمل التطبيق على شاشة عرض ثانوية."</string>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index 450d48a..0e02541 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Növbətiyə keçin"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Əvvəlkinə keçin"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ölçüsünü dəyişin"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Güvənli məkanda saxlayın"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Güvənli məkandan çıxarın"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Tətbiq bölünmüş ekran ilə işləməyə bilər."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Tətbiq ekran bölünməsini dəstəkləmir."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Tətbiq ikinci ekranda işləməyə bilər."</string>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index cfc0bb5..358da25 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Pređi na sledeće"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Pređi na prethodno"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Promenite veličinu"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stavite u tajnu memoriju"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Uklonite iz tajne memorije"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija možda neće raditi sa podeljenim ekranom."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava podeljeni ekran."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće funkcionisati na sekundarnom ekranu."</string>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index cf13ba8..7a934cc 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Перайсці да наступнага"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Перайсці да папярэдняга"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Змяніць памер"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Схаваць"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Паказаць"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Праграма можа не працаваць у рэжыме падзеленага экрана."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Праграма не падтрымлівае функцыю дзялення экрана."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Праграма можа не працаваць на дадатковых экранах."</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index 772a2a1..02930b1 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Към следващия елемент"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Към предишния елемент"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Преоразмеряване"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Съхраняване"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Отмяна на съхраняването"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Приложението може да не работи в режим на разделен екран."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Приложението не поддържа разделен екран."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Възможно е приложението да не работи на алтернативни дисплеи."</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 1d850aa..14d90a4 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Preskoči na sljedeći"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Preskoči na prethodni"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Promjena veličine"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stavljanje u stash"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Vađenje iz stasha"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija možda neće raditi na podijeljenom ekranu."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava dijeljenje ekrana."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće raditi na sekundarnom ekranu."</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 5a870ef..9cffbdd 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Ves al següent"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Torna a l\'anterior"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Canvia la mida"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Amaga"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Deixa d\'amagar"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"És possible que l\'aplicació no funcioni amb la pantalla dividida."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'aplicació no admet la pantalla dividida."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"És possible que l\'aplicació no funcioni en una pantalla secundària."</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index 53f2b21..9b5206a 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Přeskočit na další"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Přeskočit na předchozí"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Změnit velikost"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Uložit"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Zrušit uložení"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikace v režimu rozdělené obrazovky nemusí fungovat."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikace nepodporuje režim rozdělené obrazovky."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikace na sekundárním displeji nemusí fungovat."</string>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index df0a9ce..a06abf1 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Gå videre til næste"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Gå til forrige"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Rediger størrelse"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Skjul"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Vis"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Appen fungerer muligvis ikke i opdelt skærm."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen understøtter ikke opdelt skærm."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen fungerer muligvis ikke på sekundære skærme."</string>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index a452583..0195f3d 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Vorwärts springen"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Rückwärts springen"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Größe anpassen"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"In Stash legen"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Aus Stash entfernen"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Die App funktioniert unter Umständen bei geteiltem Bildschirmmodus nicht."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Das Teilen des Bildschirms wird in dieser App nicht unterstützt."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Die App funktioniert auf einem sekundären Display möglicherweise nicht."</string>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index cca393e..fc397c5 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Μετάβαση στο επόμενο"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Μετάβαση στο προηγούμενο"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Αλλαγή μεγέθους"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Απόκρυψη"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Κατάργηση απόκρυψης"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Η εφαρμογή ενδέχεται να μην λειτουργεί με διαχωρισμό οθόνης."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Η εφαρμογή δεν υποστηρίζει διαχωρισμό οθόνης."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Η εφαρμογή ίσως να μην λειτουργήσει σε δευτερεύουσα οθόνη."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index cfb1a8f..a4f287f 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Skip to next"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Skip to previous"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index cfb1a8f..a4f287f 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Skip to next"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Skip to previous"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index cfb1a8f..a4f287f 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Skip to next"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Skip to previous"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index cfb1a8f..a4f287f 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Skip to next"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Skip to previous"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Resize"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index c7179d0..ebe41e8 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Siguiente"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Anterior"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Cambiar el tamaño"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Almacenar de manera segura"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Dejar de almacenar de manera segura"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Es posible que la app no funcione en el modo de pantalla dividida."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"La app no es compatible con la función de pantalla dividida."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Es posible que la app no funcione en una pantalla secundaria."</string>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index 72b3a83..23b0ed1 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Saltar al siguiente"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Volver al anterior"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Cambiar tamaño"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Esconder"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"No esconder"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Es posible que la aplicación no funcione con la pantalla dividida."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"La aplicación no admite la pantalla dividida."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Es posible que la aplicación no funcione en una pantalla secundaria."</string>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index 66fe35a..8330981 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Järgmise juurde"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Eelmise juurde"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Suuruse muutmine"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Pane hoidlasse"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Eemalda hoidlast"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Rakendus ei pruugi poolitatud ekraaniga töötada."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Rakendus ei toeta jagatud ekraani."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Rakendus ei pruugi teisesel ekraanil töötada."</string>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index e846f923..6649769 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Joan hurrengora"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Joan aurrekora"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Aldatu tamaina"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Gorde"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Ez gorde"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Baliteke aplikazioak ez funtzionatzea pantaila zatituan."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikazioak ez du onartzen pantaila zatitua"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Baliteke aplikazioak ez funtzionatzea bigarren mailako pantailetan."</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index 1359fe2..ca7d077e 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"رد شدن به بعدی"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"رد شدن به قبلی"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"تغییر اندازه"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"مخفیسازی"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"لغو مخفیسازی"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"ممکن است برنامه با «صفحهٔ دونیمه» کار نکند."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"برنامه از تقسیم صفحه پشتیبانی نمیکند."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ممکن است برنامه در نمایشگر ثانویه کار نکند."</string>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index dafaa8a..5f87163 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Siirry seuraavaan"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Siirry edelliseen"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Muuta kokoa"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Lisää turvasäilytykseen"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Poista turvasäilytyksestä"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Sovellus ei ehkä toimi jaetulla näytöllä."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Sovellus ei tue jaetun näytön tilaa."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Sovellus ei ehkä toimi toissijaisella näytöllä."</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 6045cfd..68df591 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Passer au suivant"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Revenir au précédent"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionner"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ajouter à la réserve"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Retirer de la réserve"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Il est possible que l\'application ne fonctionne pas en mode Écran partagé."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'application n\'est pas compatible avec l\'écran partagé."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Il est possible que l\'application ne fonctionne pas sur un écran secondaire."</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index 67b7a88..9117413 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Passer au contenu suivant"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Passer au contenu précédent"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionner"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Il est possible que l\'application ne fonctionne pas en mode Écran partagé."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Application incompatible avec l\'écran partagé."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Il est possible que l\'application ne fonctionne pas sur un écran secondaire."</string>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index 25da756..3583caf 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Ir ao seguinte"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Ir ao anterior"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Cambiar tamaño"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Esconder"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Non esconder"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Pode que a aplicación non funcione coa pantalla dividida."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"A aplicación non é compatible coa función de pantalla dividida."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É posible que a aplicación non funcione nunha pantalla secundaria."</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index f1f6caf..55a30f2 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"अगले पर जाएं"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"पिछले पर जाएं"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"आकार बदलें"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"छिपाएं"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"दिखाएं"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"ऐप्लिकेशन शायद स्प्लिट स्क्रीन मोड में काम न करे."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ऐप विभाजित स्क्रीन का समर्थन नहीं करता है."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"हो सकता है कि ऐप प्राइमरी (मुख्य) डिस्प्ले के अलावा बाकी दूसरे डिस्प्ले पर काम न करे."</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 197b92d..f6acb5c 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Preskoči na sljedeće"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Preskoči na prethodno"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Promjena veličine"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Sakrijte"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Poništite sakrivanje"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija možda neće funkcionirati s podijeljenim zaslonom."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava podijeljeni zaslon."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće funkcionirati na sekundarnom zaslonu."</string>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index 909e7ea..0c1c8a40 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Ugrás a következőre"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Ugrás az előzőre"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Átméretezés"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Félretevés"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Félretevés megszüntetése"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Lehet, hogy az alkalmazás nem működik osztott képernyős nézetben."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Az alkalmazás nem támogatja az osztott képernyős nézetet."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Előfordulhat, hogy az alkalmazás nem működik másodlagos kijelzőn."</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index a1de75e..36204c1 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Անցնել հաջորդին"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Վերադառնալ նախորդին"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Փոխել չափը"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Թաքցնել"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Ցուցադրել"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Հավելվածը չի կարող աշխատել տրոհված էկրանի ռեժիմում։"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Հավելվածը չի աջակցում էկրանի տրոհումը:"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Հավելվածը կարող է չաշխատել լրացուցիչ էկրանի վրա"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index 4659fab..de962c4 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Lewati ke berikutnya"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Lewati ke sebelumnya"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ubah ukuran"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Batalkan stash"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikasi mungkin tidak berfungsi dengan layar terpisah."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App tidak mendukung layar terpisah."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikasi mungkin tidak berfungsi pada layar sekunder."</string>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index e6580bf..c205d22 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Fara á næsta"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Fara á fyrra"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Breyta stærð"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Geymsla"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Taka úr geymslu"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Hugsanlega virkar forritið ekki með skjáskiptingu."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Forritið styður ekki að skjánum sé skipt."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Hugsanlegt er að forritið virki ekki á öðrum skjá."</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index cd182b1..34f75da 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Passa ai contenuti successivi"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Passa ai contenuti precedenti"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ridimensiona"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Accantona"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Annulla accantonamento"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"L\'app potrebbe non funzionare con lo schermo diviso."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'app non supporta la modalità Schermo diviso."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"L\'app potrebbe non funzionare su un display secondario."</string>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index bb0cdc4..b0c03ed 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"אפשר לדלג אל הבא"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"אפשר לדלג אל הקודם"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"שינוי גודל"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"הסתרה זמנית"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ביטול ההסתרה הזמנית"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"ייתכן שהאפליקציה לא תפעל במסך מפוצל."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"האפליקציה אינה תומכת במסך מפוצל."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ייתכן שהאפליקציה לא תפעל במסך משני."</string>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 230f91a..ef5ed00 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"次へスキップ"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"前へスキップ"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"サイズ変更"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"非表示"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"表示"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"アプリは分割画面では動作しないことがあります。"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"アプリで分割画面がサポートされていません。"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"アプリはセカンダリ ディスプレイでは動作しないことがあります。"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 39df248..af1377a 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"შემდეგზე გადასვლა"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"წინაზე გადასვლა"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ზომის შეცვლა"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"გადანახვა"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"გადანახვის გაუქმება"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"აპმა შეიძლება არ იმუშაოს გაყოფილი ეკრანის რეჟიმში."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ეკრანის გაყოფა არ არის მხარდაჭერილი აპის მიერ."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"აპმა შეიძლება არ იმუშაოს მეორეულ ეკრანზე."</string>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index 7bec5a7..76e4c73 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Келесіге өту"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Алдыңғысына оралу"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Өлшемін өзгерту"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Жасыру"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Көрсету"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Қолданба экранды бөлу режимінде жұмыс істемеуі мүмкін."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Қодланба бөлінген экранды қолдамайды."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Қолданба қосымша дисплейде жұмыс істемеуі мүмкін."</string>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 230ea09..c59d0fc 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"រំលងទៅបន្ទាប់"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"រំលងទៅក្រោយ"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ប្ដូរទំហំ"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"លាក់ជាបណ្ដោះអាសន្ន"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ឈប់លាក់ជាបណ្ដោះអាសន្ន"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"កម្មវិធីអាចនឹងមិនដំណើរការជាមួយមុខងារបំបែកអេក្រង់ទេ។"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"កម្មវិធីមិនគាំទ្រអេក្រង់បំបែកជាពីរទេ"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"កម្មវិធីនេះប្រហែលជាមិនដំណើរការនៅលើអេក្រង់បន្ទាប់បន្សំទេ។"</string>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 5b9384c..5e655b4 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"ಮುಂದಕ್ಕೆ ಸ್ಕಿಪ್ ಮಾಡಿ"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"ಹಿಂದಕ್ಕೆ ಸ್ಕಿಪ್ ಮಾಡಿ"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ಮರುಗಾತ್ರಗೊಳಿಸಿ"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"ಸ್ಟ್ಯಾಶ್ ಮಾಡಿ"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ಅನ್ಸ್ಟ್ಯಾಶ್ ಮಾಡಿ"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"ವಿಭಜಿಸಿದ ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ಆ್ಯಪ್ ಕೆಲಸ ಮಾಡದೇ ಇರಬಹುದು."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ಅಪ್ಲಿಕೇಶನ್ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ಸೆಕೆಂಡರಿ ಡಿಸ್ಪ್ಲೇಗಳಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್ ಕಾರ್ಯ ನಿರ್ವಹಿಸದೇ ಇರಬಹುದು."</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index 34b0937..af34ef4 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"다음으로 건너뛰기"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"이전으로 건너뛰기"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"크기 조절"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"숨기기"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"숨기기 취소"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"앱이 분할 화면에서 작동하지 않을 수 있습니다."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"앱이 화면 분할을 지원하지 않습니다."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"앱이 보조 디스플레이에서 작동하지 않을 수도 있습니다."</string>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index e2143ce..c16041d 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Кийинкисине өткөрүп жиберүү"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Мурункусуна өткөрүп жиберүү"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Өлчөмүн өзгөртүү"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Сейфке салуу"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Сейфтен чыгаруу"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Колдонмодо экран бөлүнбөшү мүмкүн."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Колдонмодо экран бөлүнбөйт."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Колдонмо кошумча экранда иштебей коюшу мүмкүн."</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index cbc0ea81..a578b0a 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"ຂ້າມໄປລາຍການໜ້າ"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"ຂ້າມໄປລາຍການກ່ອນນີ້"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ປ່ຽນຂະໜາດ"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"ເກັບໄວ້ບ່ອນເກັບສ່ວນຕົວ"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ເອົາອອກຈາກບ່ອນເກັບສ່ວນຕົວ"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"ແອັບອາດໃຊ້ບໍ່ໄດ້ກັບການແບ່ງໜ້າຈໍ."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ແອັບບໍ່ຮອງຮັບໜ້າຈໍແບບແຍກກັນ."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ແອັບອາດບໍ່ສາມາດໃຊ້ໄດ້ໃນໜ້າຈໍທີສອງ."</string>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index e6d0304..e037839 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Praleisti ir eiti į kitą"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Praleisti ir eiti į ankstesnį"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Pakeisti dydį"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Paslėpti"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Nebeslėpti"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Programa gali neveikti naudojant išskaidyto ekrano režimą."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Programoje nepalaikomas skaidytas ekranas."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Programa gali neveikti antriniame ekrane."</string>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index 181531e..05472e4 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Pāriet uz nākamo"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Pāriet uz iepriekšējo"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Mainīt lielumu"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Paslēpt"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Rādīt"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Iespējams, lietotne nedarbosies ekrāna sadalīšanas režīmā."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Lietotnē netiek atbalstīta ekrāna sadalīšana."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Lietotne, iespējams, nedarbosies sekundārajā displejā."</string>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index 788696e..9cb2c69 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Прескокни до следната"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Прескокни до претходната"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Промени големина"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Сокријте"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Прикажете"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Апликацијата може да не работи со поделен екран."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Апликацијата не поддржува поделен екран."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апликацијата може да не функционира на друг екран."</string>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index 347159f..0738ed2 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"അടുത്തതിലേക്ക് പോകുക"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"മുമ്പത്തേതിലേക്ക് പോകുക"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"വലുപ്പം മാറ്റുക"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"സ്റ്റാഷ് ചെയ്യൽ"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"അൺസ്റ്റാഷ് ചെയ്യൽ"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"സ്ക്രീൻ വിഭജന മോഡിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"സ്പ്ലിറ്റ്-സ്ക്രീനിനെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"രണ്ടാം ഡിസ്പ്ലേയിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല."</string>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index 881c6b4..68822cb 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Дараагийн медиад очих"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Өмнөх медиад очих"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Хэмжээг өөрчлөх"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Нуух"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Ил гаргах"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Апп хуваагдсан дэлгэц дээр ажиллахгүй байж болзошгүй."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Энэ апп нь дэлгэц хуваах тохиргоог дэмждэггүй."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апп хоёрдогч дэлгэцэд ажиллахгүй."</string>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index 70c9a02..2f33bfa 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Langkau ke seterusnya"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Langkau ke sebelumnya"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ubah saiz"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Sembunyikan"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Tunjukkan"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Apl mungkin tidak berfungsi dengan skrin pisah."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Apl tidak menyokong skrin pisah."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Apl mungkin tidak berfungsi pada paparan kedua."</string>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index 971caae..018ffc0 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"နောက်တစ်ခုသို့ ကျော်ရန်"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"ယခင်တစ်ခုသို့ ပြန်သွားရန်"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"အရွယ်အစားပြောင်းရန်"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"သိုဝှက်ရန်"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"မသိုဝှက်ရန်"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းဖြင့် အက်ပ်သည် အလုပ်မလုပ်ပါ။"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"အက်ပ်သည် မျက်နှာပြင်ခွဲပြရန် ပံ့ပိုးထားခြင်းမရှိပါ။"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ဤအက်ပ်အနေဖြင့် ဒုတိယဖန်သားပြင်ပေါ်တွင် အလုပ်လုပ်မည် မဟုတ်ပါ။"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index f1c532e..a23ad90 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Hopp til neste"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Hopp til forrige"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Endre størrelse"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Oppbevar"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Avslutt oppbevaring"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Det kan hende at appen ikke fungerer med delt skjerm."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen støtter ikke delt skjerm."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen fungerer kanskje ikke på en sekundær skjerm."</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index 8c39693..5b9b872 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"अर्कोमा जानुहोस्"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"अघिल्लोमा जानुहोस्"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"आकार बदल्नुहोस्"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"स्ट्यास गर्नुहोस्"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"अनस्ट्यास गर्नुहोस्"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"एप विभाजित स्क्रिनमा काम नगर्न सक्छ।"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"अनुप्रयोगले विभाजित-स्क्रिनलाई समर्थन गर्दैन।"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"यो एपले सहायक प्रदर्शनमा काम नगर्नसक्छ।"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 12c3125..69fc25a 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Doorgaan naar volgende"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Teruggaan naar vorige"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Formaat aanpassen"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Verbergen"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Niet meer verbergen"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"De app werkt mogelijk niet met gesplitst scherm."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App biedt geen ondersteuning voor gesplitst scherm."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App werkt mogelijk niet op een secundair scherm."</string>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index 73752a6..ac1e84a 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"ପରବର୍ତ୍ତୀକୁ ଯାଆନ୍ତୁ"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"ପୂର୍ବବର୍ତ୍ତୀକୁ ଛାଡ଼ନ୍ତୁ"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ରିସାଇଜ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"ଲୁଚାନ୍ତୁ"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ଦେଖାନ୍ତୁ"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"ସ୍ପ୍ଲିଟ୍-ସ୍କ୍ରିନରେ ଆପ୍ କାମ କରିନପାରେ।"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ଆପ୍ ସ୍ପ୍ଲିଟ୍-ସ୍କ୍ରୀନକୁ ସପୋର୍ଟ କରେ ନାହିଁ।"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ସେକେଣ୍ଡାରୀ ଡିସପ୍ଲେରେ ଆପ୍ କାମ ନକରିପାରେ।"</string>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index 9c68bc8..bf5b733c 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"ਅਗਲੇ \'ਤੇ ਜਾਓ"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"ਪਿਛਲੇ \'ਤੇ ਜਾਓ"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ਆਕਾਰ ਬਦਲੋ"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"ਸਟੈਸ਼"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ਅਣਸਟੈਸ਼"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ।"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ।"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸੈਕੰਡਰੀ ਡਿਸਪਲੇ \'ਤੇ ਕੰਮ ਨਾ ਕਰੇ।"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index 1499358..cd659ba 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Dalej"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Wstecz"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Zmień rozmiar"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Przenieś do schowka"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Zabierz ze schowka"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacja może nie działać przy podzielonym ekranie."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacja nie obsługuje dzielonego ekranu."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacja może nie działać na dodatkowym ekranie."</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index cfe2e4d..616e67e 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Pular para a próxima"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Pular para a anterior"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionar"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Adicionar ao Depósito"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Remover do Depósito"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"É possível que o app não funcione com a tela dividida."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"O app não é compatível com a divisão de tela."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É possível que o app não funcione em uma tela secundária."</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index 334af11..1f5b0ab 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Mudar para o seguinte"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Mudar para o anterior"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionar"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Armazenar"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Remover do armazenamento"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"A app pode não funcionar com o ecrã dividido."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"A app não é compatível com o ecrã dividido."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"A app pode não funcionar num ecrã secundário."</string>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index cfe2e4d..616e67e 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Pular para a próxima"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Pular para a anterior"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionar"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Adicionar ao Depósito"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Remover do Depósito"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"É possível que o app não funcione com a tela dividida."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"O app não é compatível com a divisão de tela."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É possível que o app não funcione em uma tela secundária."</string>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 8eea1cc..d694be1 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Treceți la următorul"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Treceți la cel anterior"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionați"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stocați"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Anulați stocarea"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Este posibil ca aplicația să nu funcționeze cu ecranul împărțit."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplicația nu acceptă ecranul împărțit."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Este posibil ca aplicația să nu funcționeze pe un ecran secundar."</string>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index 7723e4d..e9bfffb 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Перейти к следующему"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Перейти к предыдущему"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Изменить размер"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Скрыть"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Показать"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"В режиме разделения экрана приложение может работать нестабильно."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Приложение не поддерживает разделение экрана."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Приложение может не работать на дополнительном экране"</string>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index 1618a6b..ba178f0 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"ඊළඟ එකට පනින්න"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"පෙර එකට පනින්න"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ප්රතිප්රමාණ කරන්න"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"සඟවා තබන්න"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"සඟවා තැබීම ඉවත් කරන්න"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"යෙදුම බෙදුම් තිරය සමග ක්රියා නොකළ හැකිය"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"යෙදුම බෙදුණු-තිරය සඳහා සහාය නොදක්වයි."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"යෙදුම ද්විතියික සංදර්ශකයක ක්රියා නොකළ හැකිය."</string>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index 1986db2..e048ca1 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Preskočiť na ďalšie"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Preskočiť na predchádzajúce"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Zmeniť veľkosť"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Skryť"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Zrušiť skrytie"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikácia nemusí fungovať s rozdelenou obrazovkou."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikácia nepodporuje rozdelenú obrazovku."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikácia nemusí fungovať na sekundárnej obrazovke."</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index d42b99f..ed05908 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Preskoči na naslednjega"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Preskoči na prejšnjega"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Spremeni velikost"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Zakrij"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Razkrij"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija morda ne deluje v načinu razdeljenega zaslona."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podpira načina razdeljenega zaslona."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija morda ne bo delovala na sekundarnem zaslonu."</string>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index d884be7..13e830c 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Kalo te tjetra"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Kalo tek e mëparshmja"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ndrysho përmasat"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Fshih"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Mos e fshih"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacioni mund të mos funksionojë me ekranin e ndarë."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacioni nuk mbështet ekranin e ndarë."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacioni mund të mos funksionojë në një ekran dytësor."</string>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index 8449f27..be6857b 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Пређи на следеће"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Пређи на претходно"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Промените величину"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ставите у тајну меморију"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Уклоните из тајне меморије"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Апликација можда неће радити са подељеним екраном."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Апликација не подржава подељени екран."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апликација можда неће функционисати на секундарном екрану."</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 9ee6825..e61e69b 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Hoppa till nästa"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Hoppa till föregående"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Ändra storlek"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Utför stash"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Återställ stash"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Appen kanske inte fungerar med delad skärm."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen har inte stöd för delad skärm."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen kanske inte fungerar på en sekundär skärm."</string>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index bfaad28..476af11 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Ruka ufikie inayofuata"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Ruka ufikie iliyotangulia"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Badilisha ukubwa"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ficha"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Fichua"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Huenda programu isifanye kazi kwenye skrini inayogawanywa."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Programu haiwezi kutumia skrini iliyogawanywa."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Huenda programu isifanye kazi kwenye dirisha lingine."</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index eee0d69..bc27389 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"அடுத்ததற்குச் செல்"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"முந்தையதற்குச் செல்"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"அளவு மாற்று"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"திரைப் பிரிப்பு அம்சத்தில் ஆப்ஸ் செயல்படாமல் போகக்கூடும்."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"திரையைப் பிரிப்பதைப் ஆப்ஸ் ஆதரிக்கவில்லை."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"இரண்டாம்நிலைத் திரையில் ஆப்ஸ் வேலை செய்யாமல் போகக்கூடும்."</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 6d7d768..624b8b3 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"దాటవేసి తర్వాత దానికి వెళ్లు"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"దాటవేసి మునుపటి దానికి వెళ్లు"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"పరిమాణం మార్చు"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"స్టాచ్"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ఆన్స్టాచ్"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"స్క్రీన్ విభజనతో యాప్ పని చేయకపోవచ్చు."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"అనువర్తనంలో స్క్రీన్ విభజనకు మద్దతు లేదు."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ప్రత్యామ్నాయ డిస్ప్లేలో యాప్ పని చేయకపోవచ్చు."</string>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 63a172f..9017b3f 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"ข้ามไปรายการถัดไป"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"ข้ามไปรายการก่อนหน้า"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"ปรับขนาด"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"เก็บเข้าที่เก็บส่วนตัว"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"เอาออกจากที่เก็บส่วนตัว"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"แอปอาจใช้ไม่ได้กับโหมดแบ่งหน้าจอ"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"แอปไม่สนับสนุนการแยกหน้าจอ"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"แอปอาจไม่ทำงานในจอแสดงผลรอง"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 524856e..c484caf 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Lumaktaw sa susunod"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Lumaktaw sa nakaraan"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"I-resize"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"I-stash"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"I-unstash"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Posibleng hindi gumana ang app sa split screen."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Hindi sinusuportahan ng app ang split-screen."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Maaaring hindi gumana ang app sa pangalawang display."</string>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index 84e4a7b..ca856a1 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Sonrakine atla"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Öncekine atla"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Yeniden boyutlandır"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Depola"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Depolama"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Uygulama bölünmüş ekranda çalışmayabilir."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Uygulama bölünmüş ekranı desteklemiyor."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Uygulama ikincil ekranda çalışmayabilir."</string>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index ee753c0..08e8d29 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Перейти далі"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Перейти назад"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Змінити розмір"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Сховати"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Показати"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Додаток може не працювати в режимі розділеного екрана."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Додаток не підтримує розділення екрана."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Додаток може не працювати на додатковому екрані."</string>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 31a7fa2..06c0927 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"نظرانداز کرکے اگلے پر جائیں"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"نظرانداز کرکے پچھلے پر جائیں"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"سائز تبدیل کریں"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stash"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"ممکن ہے کہ ایپ اسپلٹ اسکرین کے ساتھ کام نہ کرے۔"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ایپ سپلٹ اسکرین کو سپورٹ نہیں کرتی۔"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ممکن ہے ایپ ثانوی ڈسپلے پر کام نہ کرے۔"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 959757f..6a873a3 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Keyingisiga o‘tish"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Avvalgisiga qaytish"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Oʻlchamini oʻzgartirish"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Berkitish"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Chiqarish"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Bu ilova ekranni ikkiga ajratish rejimini dastaklamaydi."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Bu ilova ekranni bo‘lish xususiyatini qo‘llab-quvvatlamaydi."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Bu ilova qo‘shimcha ekranda ishlamasligi mumkin."</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index f03ff06..4d4eebc 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Chuyển tới mục tiếp theo"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Chuyển về mục trước"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Đổi kích thước"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Ẩn"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Hiện"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Ứng dụng có thể không hoạt động với tính năng chia đôi màn hình."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Ứng dụng không hỗ trợ chia đôi màn hình."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Ứng dụng có thể không hoạt động trên màn hình phụ."</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index 15e8260..3b8c889 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"跳到下一个"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"跳到上一个"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"调整大小"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"隐藏"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"取消隐藏"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"应用可能无法在分屏模式下正常运行。"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"应用不支持分屏。"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"应用可能无法在辅显示屏上正常运行。"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index 94e6e08..9ba82b5 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"跳到下一個"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"跳到上一個"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"調整大小"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"保護"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"取消保護"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"應用程式可能無法在分割畫面中運作。"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"應用程式不支援分割畫面。"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"應用程式可能無法在次要顯示屏上運作。"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index 1ebeff5..0af8d24 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"跳到下一個"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"跳到上一個"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"調整大小"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"暫時隱藏"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"取消暫時隱藏"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"應用程式可能無法在分割畫面中運作。"</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"這個應用程式不支援分割畫面。"</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"應用程式可能無法在次要顯示器上運作。"</string>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index 0a43065..c8199c8 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -28,10 +28,8 @@
<string name="pip_skip_to_next" msgid="8403429188794867653">"Yeqela kokulandelayo"</string>
<string name="pip_skip_to_prev" msgid="7172158111196394092">"Yeqela kokwangaphambilini"</string>
<string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Shintsha usayizi"</string>
- <!-- no translation found for accessibility_action_pip_stash (4060775037619702641) -->
- <skip />
- <!-- no translation found for accessibility_action_pip_unstash (7467499339610437646) -->
- <skip />
+ <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Yenza isiteshi"</string>
+ <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Susa isiteshi"</string>
<string name="dock_forced_resizable" msgid="1749750436092293116">"Izinhlelo zokusebenza kungenzeka zingasebenzi ngesikrini esihlukanisiwe."</string>
<string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Uhlelo lokusebenza alusekeli isikrini esihlukanisiwe."</string>
<string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Uhlelo lokusebenza kungenzeka lungasebenzi kusibonisi sesibili."</string>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index f4c4d02..e32d325 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -85,13 +85,6 @@
<!-- The amount to inset the drop target regions from the edge of the display -->
<dimen name="drop_layout_display_margin">16dp</dimen>
- <!-- The menu grid size for bubble menu. -->
- <dimen name="bubble_grid_item_icon_width">20dp</dimen>
- <dimen name="bubble_grid_item_icon_height">20dp</dimen>
- <dimen name="bubble_grid_item_icon_top_margin">12dp</dimen>
- <dimen name="bubble_grid_item_icon_bottom_margin">4dp</dimen>
- <dimen name="bubble_grid_item_icon_side_margin">22dp</dimen>
-
<!-- How much each bubble is elevated. -->
<dimen name="bubble_elevation">1dp</dimen>
<!-- How much the bubble flyout text container is elevated. -->
@@ -109,7 +102,7 @@
<!-- Padding between status bar and bubbles when displayed in expanded state -->
<dimen name="bubble_padding_top">16dp</dimen>
<!-- Max amount of space between bubbles when expanded. -->
- <dimen name="bubble_max_spacing">16dp</dimen>
+ <dimen name="bubble_max_spacing">8dp</dimen>
<!-- Size of individual bubbles. -->
<dimen name="individual_bubble_size">60dp</dimen>
<!-- Size of bubble bitmap. -->
@@ -119,7 +112,7 @@
<!-- Size of the circle around the bubbles when they're in the dismiss target. -->
<dimen name="bubble_dismiss_encircle_size">52dp</dimen>
<!-- Padding around the view displayed when the bubble is expanded -->
- <dimen name="bubble_expanded_view_padding">4dp</dimen>
+ <dimen name="bubble_expanded_view_padding">16dp</dimen>
<!-- This should be at least the size of bubble_expanded_view_padding; it is used to include
a slight touch slop around the expanded view. -->
<dimen name="bubble_expanded_view_slop">8dp</dimen>
@@ -151,7 +144,7 @@
<!-- Extra padding around the dismiss target for bubbles -->
<dimen name="bubble_dismiss_slop">16dp</dimen>
<!-- Height of button allowing users to adjust settings for bubbles. -->
- <dimen name="bubble_manage_button_height">48dp</dimen>
+ <dimen name="bubble_manage_button_height">56dp</dimen>
<!-- Height of an item in the bubble manage menu. -->
<dimen name="bubble_menu_item_height">60dp</dimen>
<!-- Max width of the message bubble-->
@@ -164,12 +157,13 @@
<dimen name="bubble_stack_offset">10dp</dimen>
<!-- Offset between stack y and animation y for bubble swap. -->
<dimen name="bubble_swap_animation_offset">15dp</dimen>
- <!-- How far offscreen the bubble stack rests. Cuts off padding and part of icon bitmap. -->
- <dimen name="bubble_stack_offscreen">9dp</dimen>
+ <!-- How far offscreen the bubble stack rests. There's some padding around the bubble so
+ add 3dp to the desired overhang. -->
+ <dimen name="bubble_stack_offscreen">3dp</dimen>
<!-- How far down the screen the stack starts. -->
<dimen name="bubble_stack_starting_offset_y">120dp</dimen>
<!-- Space between the pointer triangle and the bubble expanded view -->
- <dimen name="bubble_pointer_margin">8dp</dimen>
+ <dimen name="bubble_pointer_margin">5dp</dimen>
<!-- Padding applied to the bubble dismiss target. Touches in this padding cause the bubbles to
snap to the dismiss target. -->
<dimen name="bubble_dismiss_target_padding_x">40dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 7dcedfe..0dd11fb7c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -613,6 +613,18 @@
}
}
+ /** For the overflow to be focusable & receive key events the flags must be update. **/
+ void updateWindowFlagsForOverflow(boolean showingOverflow) {
+ if (mStackView != null && mAddedToWindowManager) {
+ mWmLayoutParams.flags = showingOverflow
+ ? 0
+ : WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+ mWmLayoutParams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+ mWindowManager.updateViewLayout(mStackView, mWmLayoutParams);
+ }
+ }
+
/** Removes the BubbleStackView from the WindowManager if it's there. */
private void removeFromWindowManagerMaybe() {
if (!mAddedToWindowManager) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index f5c453d..158babe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -113,7 +113,6 @@
private ShapeDrawable mTopPointer;
private ShapeDrawable mLeftPointer;
private ShapeDrawable mRightPointer;
- private int mExpandedViewPadding;
private float mCornerRadius = 0f;
private int mBackgroundColorFloating;
@@ -349,7 +348,6 @@
Resources res = getResources();
mMinHeight = res.getDimensionPixelSize(R.dimen.bubble_expanded_default_height);
mOverflowHeight = res.getDimensionPixelSize(R.dimen.bubble_overflow_height);
- mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
updateFontSize();
@@ -667,13 +665,15 @@
? mExpandedViewContainerLocation[1] - mPositioner.getInsets().top
: 0;
int settingsHeight = mIsOverflow ? 0 : mManageButtonHeight;
+ int pointerHeight = mPositioner.showBubblesVertically()
+ ? mPointerWidth
+ : (int) (mPointerHeight - mPointerOverlap + mPointerMargin);
return mPositioner.getAvailableRect().height()
- expandedContainerY
- getPaddingTop()
- getPaddingBottom()
- settingsHeight
- - mPointerHeight
- - mPointerMargin;
+ - pointerHeight;
}
/**
@@ -721,15 +721,14 @@
: 0;
final float paddingRight = (showVertically && !onLeft)
? mPointerHeight - mPointerOverlap : 0;
- final int paddingTop = showVertically ? 0
- : mExpandedViewPadding;
- setPadding((int) paddingLeft, paddingTop, (int) paddingRight, 0);
+ final float paddingTop = showVertically ? 0
+ : mPointerHeight - mPointerOverlap;
+ setPadding((int) paddingLeft, (int) paddingTop, (int) paddingRight, 0);
final float expandedViewY = mPositioner.getExpandedViewY();
- final float bubbleSize = mPositioner.getBubbleBitmapSize();
final float bubbleCenter = showVertically
- ? bubblePosition + (bubbleSize / 2f) - expandedViewY
- : bubblePosition + (bubbleSize / 2f);
+ ? bubblePosition + (mPositioner.getBubbleSize() / 2f) - expandedViewY
+ : bubblePosition + (mPositioner.getBubbleBitmapSize() / 2f) - mPointerWidth;
// Post because we need the width of the view
post(() -> {
float pointerY;
@@ -741,7 +740,7 @@
: getWidth() - mPaddingRight - mPointerOverlap;
} else {
pointerY = mPointerOverlap;
- pointerX = bubbleCenter - mPaddingLeft - (mPointerWidth / 2f);
+ pointerX = bubbleCenter - (mPointerWidth / 2f);
}
mPointerView.setTranslationY(pointerY);
mPointerView.setTranslationX(pointerX);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
index 82849e2..ede4228 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
@@ -28,6 +28,7 @@
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -62,6 +63,15 @@
private RecyclerView mRecyclerView;
private List<Bubble> mOverflowBubbles = new ArrayList<>();
+ private View.OnKeyListener mKeyListener = (view, i, keyEvent) -> {
+ if (keyEvent.getAction() == KeyEvent.ACTION_UP
+ && keyEvent.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+ mController.collapseStack();
+ return true;
+ }
+ return false;
+ };
+
private class OverflowGridLayoutManager extends GridLayoutManager {
OverflowGridLayoutManager(Context context, int columns) {
super(context, columns);
@@ -104,6 +114,7 @@
public BubbleOverflowContainerView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ setFocusableInTouchMode(true);
}
public void setBubbleController(BubbleController controller) {
@@ -111,14 +122,10 @@
}
public void show() {
- setVisibility(View.VISIBLE);
+ requestFocus();
updateOverflow();
}
- public void hide() {
- setVisibility(View.INVISIBLE);
- }
-
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -130,6 +137,25 @@
mEmptyStateImage = findViewById(R.id.bubble_overflow_empty_state_image);
}
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (mController != null) {
+ // For the overflow to get key events (e.g. back press) we need to adjust the flags
+ mController.updateWindowFlagsForOverflow(true);
+ }
+ setOnKeyListener(mKeyListener);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (mController != null) {
+ mController.updateWindowFlagsForOverflow(false);
+ }
+ setOnKeyListener(null);
+ }
+
void updateOverflow() {
Resources res = getResources();
final int columns = res.getInteger(R.integer.bubbles_overflow_columns);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index ae1a053..65a0dda 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -72,12 +72,13 @@
private int mBubbleBitmapSize;
private int mExpandedViewLargeScreenWidth;
private int mExpandedViewPadding;
- private int mPointerHeight;
- private int mBubblePaddingTop;
+ private int mPointerMargin;
+ private float mPointerWidth;
+ private float mPointerHeight;
private PointF mPinLocation;
private PointF mRestingStackPosition;
- private int[] mLeftRightPadding = new int[2];
+ private int[] mPaddings = new int[4];
private boolean mIsLargeScreen;
private boolean mShowingInTaskbar;
@@ -154,8 +155,9 @@
mExpandedViewLargeScreenWidth = res.getDimensionPixelSize(
R.dimen.bubble_expanded_view_tablet_width);
mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
+ mPointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
- mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
+ mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);
if (mShowingInTaskbar) {
adjustForTaskbar();
}
@@ -251,30 +253,32 @@
final boolean isLargeOrOverflow = mIsLargeScreen || isOverflow;
if (showBubblesVertically()) {
if (!onLeft) {
- rightPadding += mPointerHeight + mBubbleSize;
+ rightPadding += mBubbleSize - mPointerHeight;
leftPadding += isLargeOrOverflow
? (mPositionRect.width() - rightPadding - mExpandedViewLargeScreenWidth)
: 0;
} else {
- //TODO: pointer height should be padding between pointer & bubbles here & above
- leftPadding += mPointerHeight + mBubbleSize;
+ leftPadding += mBubbleSize - mPointerHeight;
rightPadding += isLargeOrOverflow
? (mPositionRect.width() - leftPadding - mExpandedViewLargeScreenWidth)
: 0;
}
}
- mLeftRightPadding[0] = leftPadding;
- mLeftRightPadding[1] = rightPadding;
- return mLeftRightPadding;
+ // [left, top, right, bottom]
+ mPaddings[0] = leftPadding;
+ mPaddings[1] = showBubblesVertically() ? 0 : mPointerMargin;
+ mPaddings[2] = rightPadding;
+ mPaddings[3] = 0;
+ return mPaddings;
}
/** Calculates the y position of the expanded view when it is expanded. */
public float getExpandedViewY() {
final int top = getAvailableRect().top;
if (showBubblesVertically()) {
- return top + mExpandedViewPadding;
+ return top - mPointerWidth;
} else {
- return top + mBubbleSize + mBubblePaddingTop;
+ return top + mBubbleSize + mPointerMargin;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 64a3b8f..219e837 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -247,7 +247,6 @@
private int mBubbleElevation;
private int mBubbleTouchPadding;
private int mExpandedViewPadding;
- private int mPointerHeight;
private int mCornerRadius;
private int mImeOffset;
@Nullable private BubbleViewProvider mExpandedBubble;
@@ -767,7 +766,6 @@
mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
mBubbleElevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
mBubbleTouchPadding = res.getDimensionPixelSize(R.dimen.bubble_touch_padding);
- mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
mImeOffset = res.getDimensionPixelSize(R.dimen.pip_ime_offset);
mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
@@ -2169,13 +2167,6 @@
}
}
- /**
- */
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- return super.onInterceptTouchEvent(ev);
- }
-
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() != MotionEvent.ACTION_DOWN && ev.getActionIndex() != mPointerIndexDown) {
@@ -2700,7 +2691,7 @@
&& BubbleOverflow.KEY.equals(mExpandedBubble.getKey());
int[] paddings = mPositioner.getExpandedViewPadding(
mStackAnimationController.isStackOnLeftSide(), isOverflowExpanded);
- mExpandedViewContainer.setPadding(paddings[0], 0, paddings[1], 0);
+ mExpandedViewContainer.setPadding(paddings[0], paddings[1], paddings[2], paddings[3]);
if (mIsExpansionAnimating) {
mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index 48bd894..7f55403 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -208,7 +208,6 @@
Resources res = mLayout.getContext().getResources();
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
mStackOffsetPx = res.getDimensionPixelSize(R.dimen.bubble_stack_offset);
- mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
mBubbleSizePx = mPositioner.getBubbleSize();
mBubblesMaxRendered = res.getInteger(R.integer.bubbles_max_rendered);
mBubblesMaxSpace = res.getDimensionPixelSize(R.dimen.bubble_max_spacing);
@@ -276,8 +275,8 @@
boolean onLeft = mCollapsePoint != null
&& mCollapsePoint.x < (availableRect.width() / 2f);
float translationX = onLeft
- ? availableRect.left + mExpandedViewPadding
- : availableRect.right - mBubbleSizePx - mExpandedViewPadding;
+ ? availableRect.left
+ : availableRect.right - mBubbleSizePx;
path.lineTo(translationX, getBubbleXOrYForOrientation(index));
} else {
path.lineTo(getBubbleXOrYForOrientation(index), expandedY);
@@ -290,7 +289,7 @@
path.lineTo(stackedX, expandedY);
// Then, draw a line down to the stack position.
- path.lineTo(stackedX, mCollapsePoint.y + index * mStackOffsetPx);
+ path.lineTo(stackedX, mCollapsePoint.y + Math.min(index, 1) * mStackOffsetPx);
}
// The lead bubble should be the bubble with the longest distance to travel when we're
@@ -509,7 +508,7 @@
}
@Override
- float getOffsetForChainedPropertyAnimation(DynamicAnimation.ViewProperty property) {
+ float getOffsetForChainedPropertyAnimation(DynamicAnimation.ViewProperty property, int index) {
return 0;
}
@@ -621,8 +620,8 @@
&& mCollapsePoint.x < (availableRect.width() / 2f);
animationForChild(bubble)
.translationX(onLeft
- ? availableRect.left + mExpandedViewPadding
- : availableRect.right - mBubbleSizePx - mExpandedViewPadding)
+ ? availableRect.left
+ : availableRect.right - mBubbleSizePx)
.translationY(getBubbleXOrYForOrientation(i))
.start();
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
index 0618d5d..4ec2c8d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayout.java
@@ -117,7 +117,8 @@
* This is used for things like maintaining the 'stack' effect in Bubbles, where bubbles
* stack off to the left or right side slightly.
*/
- abstract float getOffsetForChainedPropertyAnimation(DynamicAnimation.ViewProperty property);
+ abstract float getOffsetForChainedPropertyAnimation(
+ DynamicAnimation.ViewProperty property, int index);
/**
* Returns the SpringForce to be used for the given child view's property animation. Despite
@@ -496,7 +497,7 @@
// setting up animations for all children when setActiveController is called.
if (mController != null && !isReorder) {
for (DynamicAnimation.ViewProperty property : mController.getAnimatedProperties()) {
- setUpAnimationForChild(property, child, index);
+ setUpAnimationForChild(property, child);
}
mController.onChildAdded(child, index);
@@ -536,23 +537,22 @@
/** Sets up SpringAnimations of the given property for each child view in the layout. */
private void setUpAnimationsForProperty(DynamicAnimation.ViewProperty property) {
for (int i = 0; i < getChildCount(); i++) {
- setUpAnimationForChild(property, getChildAt(i), i);
+ setUpAnimationForChild(property, getChildAt(i));
}
}
/** Constructs a SpringAnimation of the given property for a child view. */
- private void setUpAnimationForChild(
- DynamicAnimation.ViewProperty property, View child, int index) {
+ private void setUpAnimationForChild(DynamicAnimation.ViewProperty property, View child) {
SpringAnimation newAnim = new SpringAnimation(child, property);
newAnim.addUpdateListener((animation, value, velocity) -> {
final int indexOfChild = indexOfChild(child);
final int nextAnimInChain = mController.getNextAnimationInChain(property, indexOfChild);
-
if (nextAnimInChain == PhysicsAnimationController.NONE || indexOfChild < 0) {
return;
}
- final float offset = mController.getOffsetForChainedPropertyAnimation(property);
+ final float offset = mController.getOffsetForChainedPropertyAnimation(property,
+ nextAnimInChain);
if (nextAnimInChain < getChildCount()) {
final SpringAnimation nextAnim = getSpringAnimationAtIndex(
property, nextAnimInChain);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
index 578f87f..6209051 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
@@ -709,14 +709,16 @@
@Override
- float getOffsetForChainedPropertyAnimation(DynamicAnimation.ViewProperty property) {
+ float getOffsetForChainedPropertyAnimation(DynamicAnimation.ViewProperty property, int index) {
if (property.equals(DynamicAnimation.TRANSLATION_Y)) {
// If we're in the dismiss target, have the bubbles pile on top of each other with no
// offset.
if (isStackStuckToTarget()) {
return 0f;
} else {
- return mStackOffset;
+ // We only show the first two bubbles in the stack & the rest hide behind them
+ // so they don't need an offset.
+ return index > 1 ? 0f : mStackOffset;
}
} else {
return 0f;
@@ -825,7 +827,7 @@
private void moveToFinalIndex(View view, int newIndex,
Runnable finishReorder) {
final ViewPropertyAnimator animator = view.animate()
- .translationY(getStackPosition().y + newIndex * mStackOffset)
+ .translationY(getStackPosition().y + Math.min(newIndex, 1) * mStackOffset)
.setDuration(BUBBLE_SWAP_DURATION)
.withEndAction(() -> {
view.setTag(R.id.reorder_animator_tag, null);
@@ -912,8 +914,9 @@
if (mLayout.getChildCount() > 0) {
property.setValue(mLayout.getChildAt(0), value);
if (mLayout.getChildCount() > 1) {
+ float newValue = value + getOffsetForChainedPropertyAnimation(property, 0);
animationForChildAtIndex(1)
- .property(property, value + getOffsetForChainedPropertyAnimation(property))
+ .property(property, newValue)
.start();
}
}
@@ -935,12 +938,12 @@
// Since we're not using the chained animations, apply the offsets manually.
final float xOffset = getOffsetForChainedPropertyAnimation(
- DynamicAnimation.TRANSLATION_X);
+ DynamicAnimation.TRANSLATION_X, 0);
final float yOffset = getOffsetForChainedPropertyAnimation(
- DynamicAnimation.TRANSLATION_Y);
+ DynamicAnimation.TRANSLATION_Y, 0);
for (int i = 0; i < mLayout.getChildCount(); i++) {
- mLayout.getChildAt(i).setTranslationX(pos.x + (i * xOffset));
- mLayout.getChildAt(i).setTranslationY(pos.y + (i * yOffset));
+ mLayout.getChildAt(i).setTranslationX(pos.x + (Math.min(i, 1) * xOffset));
+ mLayout.getChildAt(i).setTranslationY(pos.y + (Math.min(i, 1) * yOffset));
}
}
}
@@ -960,7 +963,7 @@
}
final float yOffset =
- getOffsetForChainedPropertyAnimation(DynamicAnimation.TRANSLATION_Y);
+ getOffsetForChainedPropertyAnimation(DynamicAnimation.TRANSLATION_Y, 0);
float endY = mStackPosition.y + yOffset * index;
float endX = mStackPosition.x;
if (mPositioner.showBubblesVertically()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 187e104..1a03ebd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -277,8 +277,9 @@
// waiting for setContentView before relayoutWindow
SplashScreenView contentView = viewSupplier.get();
final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
- // if record == null, either the starting window added fail or removed already.
- if (record != null) {
+ // If record == null, either the starting window added fail or removed already.
+ // Do not add this view if the token is mismatch.
+ if (record != null && appToken == record.mAppToken) {
// if view == null then creation of content view was failed.
if (contentView != null) {
try {
@@ -297,15 +298,16 @@
try {
final WindowManager wm = context.getSystemService(WindowManager.class);
- postAddWindow(taskId, appToken, rootLayout, wm, params);
-
- // We use the splash screen worker thread to create SplashScreenView while adding the
- // window, as otherwise Choreographer#doFrame might be delayed on this thread.
- // And since Choreographer#doFrame won't happen immediately after adding the window, if
- // the view is not added to the PhoneWindow on the first #doFrame, the view will not be
- // rendered on the first frame. So here we need to synchronize the view on the window
- // before first round relayoutWindow, which will happen after insets animation.
- mChoreographer.postCallback(CALLBACK_INSETS_ANIMATION, setViewSynchronized, null);
+ if (postAddWindow(taskId, appToken, rootLayout, wm, params)) {
+ // We use the splash screen worker thread to create SplashScreenView while adding
+ // the window, as otherwise Choreographer#doFrame might be delayed on this thread.
+ // And since Choreographer#doFrame won't happen immediately after adding the window,
+ // if the view is not added to the PhoneWindow on the first #doFrame, the view will
+ // not be rendered on the first frame. So here we need to synchronize the view on
+ // the window before first round relayoutWindow, which will happen after insets
+ // animation.
+ mChoreographer.postCallback(CALLBACK_INSETS_ANIMATION, setViewSynchronized, null);
+ }
} catch (RuntimeException e) {
// don't crash if something else bad happens, for example a
// failure loading resources because we are loading from an app
@@ -347,7 +349,8 @@
final int taskId = startingWindowInfo.taskInfo.taskId;
final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
snapshot, mSplashScreenExecutor, () -> removeWindowNoAnimate(taskId));
- final StartingWindowRecord tView = new StartingWindowRecord(null/* decorView */, surface);
+ final StartingWindowRecord tView = new StartingWindowRecord(appToken,
+ null/* decorView */, surface);
mStartingWindowRecords.put(taskId, tView);
}
@@ -372,6 +375,7 @@
if (preView != null && preView.mContentView != null
&& preView.mContentView.isCopyable()) {
parcelable = new SplashScreenViewParcelable(preView.mContentView);
+ preView.mContentView.onCopied();
} else {
parcelable = null;
}
@@ -382,7 +386,7 @@
ActivityTaskManager.getInstance().onSplashScreenViewCopyFinished(taskId, parcelable);
}
- protected void postAddWindow(int taskId, IBinder appToken, View view, WindowManager wm,
+ protected boolean postAddWindow(int taskId, IBinder appToken, View view, WindowManager wm,
WindowManager.LayoutParams params) {
boolean shouldSaveView = true;
try {
@@ -401,12 +405,13 @@
}
if (shouldSaveView) {
removeWindowNoAnimate(taskId);
- saveSplashScreenRecord(taskId, view);
+ saveSplashScreenRecord(appToken, taskId, view);
}
+ return shouldSaveView;
}
- private void saveSplashScreenRecord(int taskId, View view) {
- final StartingWindowRecord tView = new StartingWindowRecord(view,
+ private void saveSplashScreenRecord(IBinder appToken, int taskId, View view) {
+ final StartingWindowRecord tView = new StartingWindowRecord(appToken, view,
null/* TaskSnapshotWindow */);
mStartingWindowRecords.put(taskId, tView);
}
@@ -468,12 +473,15 @@
* Record the view or surface for a starting window.
*/
private static class StartingWindowRecord {
+ private final IBinder mAppToken;
private final View mDecorView;
private final TaskSnapshotWindow mTaskSnapshotWindow;
private SplashScreenView mContentView;
private boolean mSetSplashScreen;
- StartingWindowRecord(View decorView, TaskSnapshotWindow taskSnapshotWindow) {
+ StartingWindowRecord(IBinder appToken, View decorView,
+ TaskSnapshotWindow taskSnapshotWindow) {
+ mAppToken = appToken;
mDecorView = decorView;
mTaskSnapshotWindow = taskSnapshotWindow;
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
index b5198bb..ef9f742 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestCannotPairNonResizeableApps.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.wm.shell.flicker.appPairsDividerIsInvisible
import com.android.wm.shell.flicker.helpers.AppPairsHelper
@@ -47,6 +48,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
class AppPairsTestCannotPairNonResizeableApps(
testSpec: FlickerTestParameter
) : AppPairsTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
index 614530b..db63c4c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestPairPrimaryAndSecondaryApps.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.traces.layers.getVisibleBounds
import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER
@@ -42,6 +43,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
class AppPairsTestPairPrimaryAndSecondaryApps(
testSpec: FlickerTestParameter
) : AppPairsTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
index f2a375b..c8d3423 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.wm.shell.flicker.appPairsDividerIsVisible
import com.android.wm.shell.flicker.helpers.AppPairsHelper
@@ -47,6 +48,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
class AppPairsTestSupportPairNonResizeableApps(
testSpec: FlickerTestParameter
) : AppPairsTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
index 87ad8de..83df836 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestUnpairPrimaryAndSecondaryApps.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.traces.layers.getVisibleBounds
import com.android.wm.shell.flicker.APP_PAIR_SPLIT_DIVIDER
@@ -42,6 +43,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
class AppPairsTestUnpairPrimaryAndSecondaryApps(
testSpec: FlickerTestParameter
) : AppPairsTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
index a988148..c875c00 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsInAppPairsMode.kt
@@ -24,6 +24,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.setRotation
@@ -46,6 +47,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
class RotateTwoLaunchedAppsInAppPairsMode(
testSpec: FlickerTestParameter
) : RotateTwoLaunchedAppsTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
index 3396b90..c3360ca 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/RotateTwoLaunchedAppsRotateAndEnterAppPairsMode.kt
@@ -24,6 +24,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.setRotation
@@ -48,6 +49,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
class RotateTwoLaunchedAppsRotateAndEnterAppPairsMode(
testSpec: FlickerTestParameter
) : RotateTwoLaunchedAppsTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
index dbbbcd2..4f12f2b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenDockActivity.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.HOME_WINDOW_TITLE
+import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
@@ -47,6 +48,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
class EnterSplitScreenDockActivity(
testSpec: FlickerTestParameter
) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
index 3ae6cfa..85ded8a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenLaunchToSide.kt
@@ -22,6 +22,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
@@ -48,6 +49,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
class EnterSplitScreenLaunchToSide(
testSpec: FlickerTestParameter
) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
index c18c122..e958bf3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenNotSupportNonResizable.kt
@@ -22,6 +22,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.canSplitScreen
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
@@ -49,6 +50,7 @@
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@Group1
class EnterSplitScreenNotSupportNonResizable(
testSpec: FlickerTestParameter
) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
index d5b9a13..d3acc82 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterSplitScreenSupportNonResizable.kt
@@ -22,6 +22,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
@@ -48,6 +49,7 @@
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@Group2
class EnterSplitScreenSupportNonResizable(
testSpec: FlickerTestParameter
) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
index faf7aa7..bad4683 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottom.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.appWindowBecomesInVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.exitSplitScreenFromBottom
@@ -47,6 +48,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class ExitLegacySplitScreenFromBottom(
testSpec: FlickerTestParameter
) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
index 8845777..76dcd8b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.appWindowBecomesInVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
@@ -48,6 +49,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class ExitPrimarySplitScreenShowSecondaryFullscreen(
testSpec: FlickerTestParameter
) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
index 612018e..d0a64b3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentNotSupportNonResizable.kt
@@ -22,6 +22,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.appWindowBecomesInVisible
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
@@ -51,6 +52,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class LegacySplitScreenFromIntentNotSupportNonResizable(
testSpec: FlickerTestParameter
) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
index 65062f9..c26c05f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromIntentSupportNonResizable.kt
@@ -22,6 +22,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
@@ -49,6 +50,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class LegacySplitScreenFromIntentSupportNonResizable(
testSpec: FlickerTestParameter
) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
index 3720787..fb17589 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentNotSupportNonResizable.kt
@@ -22,6 +22,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.appWindowBecomesInVisible
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
@@ -52,6 +53,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class LegacySplitScreenFromRecentNotSupportNonResizable(
testSpec: FlickerTestParameter
) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
index 61ebcd2..a9c28ef 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenFromRecentSupportNonResizable.kt
@@ -22,6 +22,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
@@ -50,6 +51,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class LegacySplitScreenFromRecentSupportNonResizable(
testSpec: FlickerTestParameter
) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
index 976668e..a4d2ab5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
@@ -24,6 +24,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.focusDoesNotChange
@@ -57,6 +58,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class LegacySplitScreenToLauncher(
testSpec: FlickerTestParameter
) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
index 69520c2..05eb5f4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.focusChanges
@@ -48,6 +49,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class OpenAppToLegacySplitScreen(
testSpec: FlickerTestParameter
) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
index ecbb887..3e83b63 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
@@ -25,6 +25,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -61,6 +62,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 159096424)
+@Group2
class ResizeLegacySplitScreen(
testSpec: FlickerTestParameter
) : LegacySplitScreenTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
index 0b4cb0f..58482ea 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppAndEnterSplitScreen.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
@@ -50,6 +51,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class RotateOneLaunchedAppAndEnterSplitScreen(
testSpec: FlickerTestParameter
) : LegacySplitScreenRotateTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
index 8909e97..06828d6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppInSplitScreenMode.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
@@ -50,6 +51,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class RotateOneLaunchedAppInSplitScreenMode(
testSpec: FlickerTestParameter
) : LegacySplitScreenRotateTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
index e850b60..f8e32bf 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppAndEnterSplitScreen.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
@@ -52,6 +53,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class RotateTwoLaunchedAppAndEnterSplitScreen(
testSpec: FlickerTestParameter
) : LegacySplitScreenRotateTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
index cae2338..cb246ca 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppInSplitScreenMode.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.appWindowBecomesVisible
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
@@ -52,6 +53,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class RotateTwoLaunchedAppInSplitScreenMode(
testSpec: FlickerTestParameter
) : LegacySplitScreenRotateTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
index 1ba1f3b..00e50e7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
@@ -22,6 +22,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.wm.shell.flicker.helpers.FixedAppHelper
import org.junit.FixMethodOrder
@@ -38,6 +39,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
class EnterExitPipTest(
testSpec: FlickerTestParameter
) : PipTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index 95672f4..b6af260 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import org.junit.FixMethodOrder
import org.junit.Test
@@ -38,6 +39,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = buildTransition(eachRun = true, stringExtras = emptyMap()) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index 33ddec37..3a1456e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.wm.shell.flicker.helpers.FixedAppHelper
@@ -44,6 +45,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
class EnterPipToOtherOrientationTest(
testSpec: FlickerTestParameter
) : PipTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
index f290b90..cf84a2c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
@@ -20,6 +20,7 @@
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import org.junit.FixMethodOrder
import org.junit.Test
@@ -35,6 +36,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
class PipCloseWithDismissButtonTest(testSpec: FlickerTestParameter) : PipCloseTransition(testSpec) {
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
index 4440262..524a1b4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
@@ -22,6 +22,7 @@
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerRotatesScales
@@ -39,6 +40,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
class PipCloseWithSwipeTest(testSpec: FlickerTestParameter) : PipCloseTransition(testSpec) {
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index 4633960..d88f94d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -22,6 +22,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.setRotation
@@ -42,6 +43,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
private val imeApp = ImeAppHelper(instrumentation)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
index afba508..6833b96 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
@@ -46,6 +47,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 161435597)
+@Group3
class PipLegacySplitScreenTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
private val imeApp = ImeAppHelper(instrumentation)
private val testApp = FixedAppHelper(instrumentation)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index fb7dac3..d531af2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.WindowUtils
@@ -46,6 +47,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
private val fixedApp = FixedAppHelper(instrumentation)
private val startingBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt
index 84f66fc..1294ac9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.wm.shell.flicker.helpers.FixedAppHelper
import com.google.common.truth.Truth
@@ -40,6 +41,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
class PipShelfHeightTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
private val taplInstrumentation = LauncherInstrumentation()
private val testApp = FixedAppHelper(instrumentation)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
index f7f658e..55e5c41 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
@@ -22,6 +22,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.setRotation
@@ -40,6 +41,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
class PipToAppTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = buildTransition(eachRun = true) { configuration ->
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index 1e7d08b..1f58bb2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
@@ -43,6 +44,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
class SetRequestedOrientationWhilePinnedTest(
testSpec: FlickerTestParameter
) : PipTransition(testSpec) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTest.java
index c4edbb2..964711e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTest.java
@@ -249,7 +249,7 @@
Mockito.verify(mTestableController, Mockito.never())
.getNextAnimationInChain(eq(DynamicAnimation.SCALE_X), anyInt());
Mockito.verify(mTestableController, Mockito.never())
- .getOffsetForChainedPropertyAnimation(eq(DynamicAnimation.SCALE_X));
+ .getOffsetForChainedPropertyAnimation(eq(DynamicAnimation.SCALE_X), anyInt());
// Make sure we asked the new controller about its animated properties, and configuration
// options.
@@ -258,7 +258,7 @@
Mockito.verify(secondController, Mockito.atLeastOnce())
.getNextAnimationInChain(eq(DynamicAnimation.SCALE_X), anyInt());
Mockito.verify(secondController, Mockito.atLeastOnce())
- .getOffsetForChainedPropertyAnimation(eq(DynamicAnimation.SCALE_X));
+ .getOffsetForChainedPropertyAnimation(eq(DynamicAnimation.SCALE_X), anyInt());
mLayout.setActiveController(mTestableController);
mTestableController.animationForChildAtIndex(0)
@@ -271,7 +271,7 @@
Mockito.verify(secondController, Mockito.never())
.getNextAnimationInChain(eq(DynamicAnimation.TRANSLATION_X), anyInt());
Mockito.verify(secondController, Mockito.never())
- .getOffsetForChainedPropertyAnimation(eq(DynamicAnimation.TRANSLATION_X));
+ .getOffsetForChainedPropertyAnimation(eq(DynamicAnimation.TRANSLATION_X), anyInt());
}
@@ -479,7 +479,8 @@
}
@Override
- float getOffsetForChainedPropertyAnimation(DynamicAnimation.ViewProperty property) {
+ float getOffsetForChainedPropertyAnimation(DynamicAnimation.ViewProperty property,
+ int index) {
return mOffsetForProperty.getOrDefault(property, 0f);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTestCase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTestCase.java
index a7a7db8..48ae296 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTestCase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/PhysicsAnimationLayoutTestCase.java
@@ -258,8 +258,9 @@
}
@Override
- float getOffsetForChainedPropertyAnimation(DynamicAnimation.ViewProperty property) {
- return mWrappedController.getOffsetForChainedPropertyAnimation(property);
+ float getOffsetForChainedPropertyAnimation(DynamicAnimation.ViewProperty property,
+ int index) {
+ return mWrappedController.getOffsetForChainedPropertyAnimation(property, index);
}
@Override
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index 2623535..4e3e133 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -83,11 +83,12 @@
}
@Override
- protected void postAddWindow(int taskId, IBinder appToken,
+ protected boolean postAddWindow(int taskId, IBinder appToken,
View view, WindowManager wm, WindowManager.LayoutParams params) {
// listen for addView
mAddWindowForTask = taskId;
mViewThemeResId = view.getContext().getThemeResId();
+ return true;
}
@Override
diff --git a/libs/androidfw/OWNERS b/libs/androidfw/OWNERS
index bc056df..610fd80 100644
--- a/libs/androidfw/OWNERS
+++ b/libs/androidfw/OWNERS
@@ -1,6 +1,7 @@
set noparent
toddke@google.com
rtmitchell@google.com
+patb@google.com
per-file CursorWindow.cpp=omakoto@google.com
per-file LocaleDataTables.cpp=vichang@google.com,ngeoffray@google.com,nikitai@google.com
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index c6ab8a2..d8715db 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -671,6 +671,7 @@
"tests/unit/SkiaPipelineTests.cpp",
"tests/unit/SkiaRenderPropertiesTests.cpp",
"tests/unit/SkiaCanvasTests.cpp",
+ "tests/unit/StretchEffectTests.cpp",
"tests/unit/StringUtilsTests.cpp",
"tests/unit/TestUtilsTests.cpp",
"tests/unit/ThreadBaseTests.cpp",
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index 859a555..db3a108 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -24,10 +24,10 @@
#include <GrDirectContext.h>
#include <SkCanvas.h>
#include <SkImage.h>
+#include <gui/TraceUtils.h>
#include <utils/GLUtils.h>
#include <utils/NdkUtils.h>
#include <utils/Trace.h>
-#include <utils/TraceUtils.h>
#include <thread>
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index a9b129f..8a8b418 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -19,6 +19,7 @@
#include <sync/sync.h>
#include <system/window.h>
+#include <gui/TraceUtils.h>
#include "DeferredLayerUpdater.h"
#include "Properties.h"
#include "hwui/Bitmap.h"
@@ -28,7 +29,6 @@
#include "utils/Color.h"
#include "utils/MathUtils.h"
#include "utils/NdkUtils.h"
-#include "utils/TraceUtils.h"
using namespace android::uirenderer::renderthread;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index ded7994..9a9e6d4 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -27,9 +27,9 @@
#include "DamageAccumulator.h"
#include "pipeline/skia/SkiaDisplayList.h"
#endif
+#include <gui/TraceUtils.h>
#include "utils/MathUtils.h"
#include "utils/StringUtils.h"
-#include "utils/TraceUtils.h"
#include <SkPathOps.h>
#include <algorithm>
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 4a21ad6..55f434f 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -30,8 +30,8 @@
#include "renderthread/RenderThread.h"
#endif
+#include <gui/TraceUtils.h>
#include "utils/Macros.h"
-#include "utils/TraceUtils.h"
#include "utils/VectorDrawableUtils.h"
namespace android {
diff --git a/libs/hwui/effects/StretchEffect.h b/libs/hwui/effects/StretchEffect.h
index a92ef5b..64fb2bf 100644
--- a/libs/hwui/effects/StretchEffect.h
+++ b/libs/hwui/effects/StretchEffect.h
@@ -110,8 +110,7 @@
}
bool requiresLayer() const {
- return !(isEmpty() ||
- Properties::getStretchEffectBehavior() == StretchEffectBehavior::UniformScale);
+ return !isEmpty();
}
private:
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp
index 0d3d3e3..876f5c8 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.cpp
+++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp
@@ -19,7 +19,7 @@
#include "AnimatedImageThread.h"
#endif
-#include "utils/TraceUtils.h"
+#include <gui/TraceUtils.h>
#include "pipeline/skia/SkiaUtils.h"
#include <SkPicture.h>
diff --git a/libs/hwui/jni/Typeface.cpp b/libs/hwui/jni/Typeface.cpp
index f928baa..ee7b260 100644
--- a/libs/hwui/jni/Typeface.cpp
+++ b/libs/hwui/jni/Typeface.cpp
@@ -15,19 +15,19 @@
*/
#define ATRACE_TAG ATRACE_TAG_VIEW
-#include "FontUtils.h"
-#include "GraphicsJNI.h"
-#include "fonts/Font.h"
-#include <nativehelper/ScopedPrimitiveArray.h>
-#include <nativehelper/ScopedUtfChars.h>
-#include "SkData.h"
-#include "SkTypeface.h"
+#include <gui/TraceUtils.h>
#include <hwui/Typeface.h>
#include <minikin/FontCollection.h>
#include <minikin/FontFamily.h>
#include <minikin/FontFileParser.h>
#include <minikin/SystemFonts.h>
-#include <utils/TraceUtils.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
+#include "FontUtils.h"
+#include "GraphicsJNI.h"
+#include "SkData.h"
+#include "SkTypeface.h"
+#include "fonts/Font.h"
#include <mutex>
#include <unordered_map>
@@ -37,7 +37,6 @@
#endif
using namespace android;
-using android::uirenderer::TraceUtils;
static inline Typeface* toTypeface(jlong ptr) {
return reinterpret_cast<Typeface*>(ptr);
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index 82bc5a1..4289c45 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -24,6 +24,7 @@
#include <Properties.h>
#include <RootRenderNode.h>
#include <dlfcn.h>
+#include <gui/TraceUtils.h>
#include <inttypes.h>
#include <media/NdkImage.h>
#include <media/NdkImageReader.h>
@@ -39,7 +40,6 @@
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
-#include <utils/TraceUtils.h>
#include <pthread.h>
diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp
index 002bd83..e1da169 100644
--- a/libs/hwui/jni/android_graphics_RenderNode.cpp
+++ b/libs/hwui/jni/android_graphics_RenderNode.cpp
@@ -26,8 +26,8 @@
#endif
#include <TreeInfo.h>
#include <effects/StretchEffect.h>
+#include <gui/TraceUtils.h>
#include <hwui/Paint.h>
-#include <utils/TraceUtils.h>
namespace android {
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index c8247e7..d7546d8 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -16,11 +16,11 @@
#include "RenderNodeDrawable.h"
#include <SkPaintFilterCanvas.h>
-#include "StretchMask.h"
+#include <gui/TraceUtils.h>
#include "RenderNode.h"
#include "SkiaDisplayList.h"
+#include "StretchMask.h"
#include "TransformCanvas.h"
-#include "utils/TraceUtils.h"
#include <include/effects/SkImageFilters.h>
diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp
index 3baff7e..c482fc1 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.cpp
+++ b/libs/hwui/pipeline/skia/ShaderCache.cpp
@@ -16,6 +16,7 @@
#include "ShaderCache.h"
#include <GrDirectContext.h>
+#include <gui/TraceUtils.h>
#include <log/log.h>
#include <openssl/sha.h>
#include <algorithm>
@@ -23,7 +24,6 @@
#include <thread>
#include "FileBlobCache.h"
#include "Properties.h"
-#include "utils/TraceUtils.h"
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 50eea31..a78cd83 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -16,6 +16,7 @@
#include "SkiaOpenGLPipeline.h"
+#include <gui/TraceUtils.h>
#include "DeferredLayerUpdater.h"
#include "LayerDrawable.h"
#include "LightingInfo.h"
@@ -27,7 +28,6 @@
#include "renderthread/EglManager.h"
#include "renderthread/Frame.h"
#include "utils/GLUtils.h"
-#include "utils/TraceUtils.h"
#include <GLES3/gl3.h>
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 1f73ac9..039b0f9 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -31,13 +31,13 @@
#include <sstream>
+#include <gui/TraceUtils.h>
#include "LightingInfo.h"
#include "VectorDrawable.h"
#include "thread/CommonPool.h"
#include "tools/SkSharingProc.h"
#include "utils/Color.h"
#include "utils/String8.h"
-#include "utils/TraceUtils.h"
using namespace android::uirenderer::renderthread;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 30a3fc5..0e4a1f9 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -16,6 +16,7 @@
#include "SkiaVulkanPipeline.h"
+#include <gui/TraceUtils.h>
#include "DeferredLayerUpdater.h"
#include "LightingInfo.h"
#include "Readback.h"
@@ -25,7 +26,6 @@
#include "VkInteropFunctorDrawable.h"
#include "renderstate/RenderState.h"
#include "renderthread/Frame.h"
-#include "utils/TraceUtils.h"
#include <SkSurface.h>
#include <SkTypes.h>
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
index 6efe176..8abf4534 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -21,9 +21,9 @@
#include <SkAndroidFrameworkUtils.h>
#include <SkImage.h>
#include <SkM44.h>
+#include <gui/TraceUtils.h>
#include <utils/Color.h>
#include <utils/Trace.h>
-#include <utils/TraceUtils.h>
#include <vk/GrVkTypes.h>
#include <thread>
#include "renderthread/RenderThread.h"
diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
index bae11f7..ddfb66f 100644
--- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
@@ -21,11 +21,11 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES3/gl3.h>
+#include <gui/TraceUtils.h>
#include <private/hwui/DrawGlInfo.h>
#include <utils/Color.h>
#include <utils/GLUtils.h>
#include <utils/Trace.h>
-#include <utils/TraceUtils.h>
#include <thread>
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index c1f61e08..d317305 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -26,6 +26,7 @@
#include <cstdlib>
#include <functional>
+#include <gui/TraceUtils.h>
#include "../Properties.h"
#include "AnimationContext.h"
#include "Frame.h"
@@ -39,7 +40,6 @@
#include "thread/CommonPool.h"
#include "utils/GLUtils.h"
#include "utils/TimeUtils.h"
-#include "utils/TraceUtils.h"
#define TRIM_MEMORY_COMPLETE 80
#define TRIM_MEMORY_UI_HIDDEN 20
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 8448b87..5c4b901 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -16,8 +16,8 @@
#include "DrawFrameTask.h"
+#include <gui/TraceUtils.h>
#include <utils/Log.h>
-#include <utils/TraceUtils.h>
#include <algorithm>
#include "../DeferredLayerUpdater.h"
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 95aa29d..ac19a15 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -16,6 +16,7 @@
#include "RenderProxy.h"
+#include <gui/TraceUtils.h>
#include "DeferredLayerUpdater.h"
#include "DisplayList.h"
#include "Properties.h"
@@ -27,7 +28,6 @@
#include "renderthread/RenderThread.h"
#include "utils/Macros.h"
#include "utils/TimeUtils.h"
-#include "utils/TraceUtils.h"
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index a648f98..4ba7748 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -16,6 +16,7 @@
#include "RenderThread.h"
+#include <gui/TraceUtils.h>
#include "../HardwareBitmapUploader.h"
#include "CanvasContext.h"
#include "DeviceInfo.h"
@@ -29,7 +30,6 @@
#include "pipeline/skia/SkiaVulkanPipeline.h"
#include "renderstate/RenderState.h"
#include "utils/TimeUtils.h"
-#include "utils/TraceUtils.h"
#include <GrContextOptions.h>
#include <gl/GrGLInterface.h>
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 07146e8..5a71833 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -29,11 +29,11 @@
#include <cstring>
+#include <gui/TraceUtils.h>
#include "Properties.h"
#include "RenderThread.h"
#include "pipeline/skia/ShaderCache.h"
#include "renderstate/RenderState.h"
-#include "utils/TraceUtils.h"
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index c559425..01a2ec5 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -20,9 +20,9 @@
#include <SkSurface.h>
#include <algorithm>
+#include <gui/TraceUtils.h>
#include "VulkanManager.h"
#include "utils/Color.h"
-#include "utils/TraceUtils.h"
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index b640b90..de2c621 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <gui/TraceUtils.h>
#include "AnimationContext.h"
#include "RenderNode.h"
#include "renderthread/RenderProxy.h"
@@ -21,7 +22,6 @@
#include "tests/common/TestContext.h"
#include "tests/common/TestScene.h"
#include "tests/common/scenes/TestSceneBase.h"
-#include "utils/TraceUtils.h"
#include <benchmark/benchmark.h>
#include <gui/Surface.h>
diff --git a/libs/hwui/tests/unit/StretchEffectTests.cpp b/libs/hwui/tests/unit/StretchEffectTests.cpp
new file mode 100644
index 0000000..f5e20a1
--- /dev/null
+++ b/libs/hwui/tests/unit/StretchEffectTests.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include <gtest/gtest.h>
+#include <effects/StretchEffect.h>
+#include "tests/common/TestUtils.h"
+#include "Properties.h"
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(StretchEffect, noStretchDirectionDoesNotRequireLayer) {
+ Properties::setStretchEffectBehavior(StretchEffectBehavior::ShaderHWUI);
+ auto stretchEffect = StretchEffect({.fX = 0.f, .fY = 0.f}, 100.f, 100.f);
+ ASSERT_FALSE(stretchEffect.requiresLayer());
+
+ Properties::setStretchEffectBehavior(StretchEffectBehavior::UniformScale);
+ ASSERT_FALSE(stretchEffect.requiresLayer());
+}
+
+TEST(StretchEffect, horizontalStretchRequiresLayer) {
+ Properties::setStretchEffectBehavior(StretchEffectBehavior::ShaderHWUI);
+ auto stretchEffect = StretchEffect({.fX = 1.f, .fY = 0.f}, 100.f, 100.f);
+ ASSERT_TRUE(stretchEffect.requiresLayer());
+
+ Properties::setStretchEffectBehavior(StretchEffectBehavior::UniformScale);
+ ASSERT_TRUE(stretchEffect.requiresLayer());
+}
+
+TEST(StretchEffect, verticalStretchRequiresLayer) {
+ Properties::setStretchEffectBehavior(StretchEffectBehavior::ShaderHWUI);
+
+ auto stretchEffect = StretchEffect({.fX = 0.f, .fY = 1.f}, 100.f, 100.f);
+ ASSERT_TRUE(stretchEffect.requiresLayer());
+
+ Properties::setStretchEffectBehavior(StretchEffectBehavior::UniformScale);
+ ASSERT_TRUE(stretchEffect.requiresLayer());
+}
+
+TEST(StretchEffect, bidirectionalStretchRequiresLayer) {
+ Properties::setStretchEffectBehavior(StretchEffectBehavior::ShaderHWUI);
+
+ auto stretchEffect = StretchEffect({.fX = 1.f, .fY = 1.f}, 100.f, 100.f);
+ ASSERT_TRUE(stretchEffect.requiresLayer());
+
+ Properties::setStretchEffectBehavior(StretchEffectBehavior::UniformScale);
+ ASSERT_TRUE(stretchEffect.requiresLayer());
+}
\ No newline at end of file
diff --git a/libs/hwui/utils/TraceUtils.h b/libs/hwui/utils/TraceUtils.h
deleted file mode 100644
index e61b4be..0000000
--- a/libs/hwui/utils/TraceUtils.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-#ifndef TRACE_UTILS_H
-#define TRACE_UTILS_H
-
-#include <cutils/trace.h>
-#include <utils/Trace.h>
-
-#define ATRACE_FORMAT(fmt, ...) \
- TraceUtils::TraceEnder __traceEnder = \
- (TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__), TraceUtils::TraceEnder())
-
-#define ATRACE_FORMAT_BEGIN(fmt, ...) TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__)
-
-namespace android {
-namespace uirenderer {
-
-class TraceUtils {
-public:
- class TraceEnder {
- public:
- ~TraceEnder() { ATRACE_END(); }
- };
-
- static void atraceFormatBegin(const char* fmt, ...) {
- if (CC_LIKELY(!ATRACE_ENABLED())) return;
-
- const int BUFFER_SIZE = 256;
- va_list ap;
- char buf[BUFFER_SIZE];
-
- va_start(ap, fmt);
- vsnprintf(buf, BUFFER_SIZE, fmt, ap);
- va_end(ap);
-
- ATRACE_BEGIN(buf);
- }
-
-}; // class TraceUtils
-
-} /* namespace uirenderer */
-} /* namespace android */
-
-#endif /* TRACE_UTILS_H */
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 6fa6536..c9e4e0a 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -41,6 +41,7 @@
import android.location.provider.ProviderProperties;
import android.os.Bundle;
import android.os.ICancellationSignal;
+import android.os.PackageTagsList;
/**
* System private API for talking with the location service.
@@ -133,5 +134,5 @@
// used by gts tests to verify whitelists
String[] getBackgroundThrottlingWhitelist();
- String[] getIgnoreSettingsWhitelist();
+ PackageTagsList getIgnoreSettingsAllowlist();
}
diff --git a/location/java/android/location/LocationDeviceConfig.java b/location/java/android/location/LocationDeviceConfig.java
new file mode 100644
index 0000000..c55eed9
--- /dev/null
+++ b/location/java/android/location/LocationDeviceConfig.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location;
+
+/**
+ * DeviceConfig keys within the location namespace.
+ *
+ * @hide
+ */
+public final class LocationDeviceConfig {
+
+ /**
+ * Package/tag combinations that are allowedlisted for ignoring location settings (may retrieve
+ * location even when user location settings are off, and may ignore throttling, etc), for
+ * emergency purposes only.
+ *
+ * <p>Package/tag combinations are separated by commas (","), and with in each combination is a
+ * package name followed by 0 or more attribution tags, separated by semicolons (";"). If a
+ * package is followed by 0 attribution tags, this is interpreted the same as the wildcard
+ * value. There are two special interpreted values for attribution tags, the wildcard value
+ * ("*") which represents all attribution tags, and the null value ("null"), which is converted
+ * to the null string (since attribution tags may be null). This format implies that attribution
+ * tags which should be on this list may not contain semicolons.
+ *
+ * <p>Examples of valid entries:
+ *
+ * <ul>
+ * <li>android</li>
+ * <li>android;*</li>
+ * <li>android;*,com.example.app;null;my_attr</li>
+ * <li>android;*,com.example.app;null;my_attr,com.example.otherapp;my_attr</li>
+ * </ul>
+ */
+ public static final String IGNORE_SETTINGS_ALLOWLIST = "ignore_settings_allowlist";
+
+ private LocationDeviceConfig() {}
+}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 7c2f540..ae44c5e 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -58,6 +58,7 @@
import android.os.ICancellationSignal;
import android.os.IRemoteCallback;
import android.os.Looper;
+import android.os.PackageTagsList;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -447,12 +448,23 @@
}
/**
+ * @deprecated Do not use.
+ * @hide
+ */
+ @Deprecated
+ @TestApi
+ public @NonNull String[] getIgnoreSettingsWhitelist() {
+ return new String[0];
+ }
+
+ /**
+ * For testing purposes only.
* @hide
*/
@TestApi
- public @NonNull String[] getIgnoreSettingsWhitelist() {
+ public @NonNull PackageTagsList getIgnoreSettingsAllowlist() {
try {
- return mService.getIgnoreSettingsWhitelist();
+ return mService.getIgnoreSettingsAllowlist();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1811,6 +1823,7 @@
* @deprecated Use {@link #isProviderPackage(String, String, String)} instead.
*
* @hide
+ * @removed
*/
@Deprecated
@SystemApi
diff --git a/location/java/android/location/SatellitePvt.java b/location/java/android/location/SatellitePvt.java
index bb9ae6e..794a8d0 100644
--- a/location/java/android/location/SatellitePvt.java
+++ b/location/java/android/location/SatellitePvt.java
@@ -399,13 +399,6 @@
}
/**
- * Gets a bitmask of fields present in this object
- */
- public int getFlags() {
- return mFlags;
- }
-
- /**
* Returns a {@link PositionEcef} object that contains estimates of the satellite
* position fields in ECEF coordinate frame.
*/
@@ -536,18 +529,6 @@
private double mTropoDelayMeters;
/**
- * Sets a bitmask of fields present in this object
- *
- * @param flags int flags
- * @return Builder builder object
- */
- @NonNull
- public Builder setFlags(int flags) {
- mFlags = flags;
- return this;
- }
-
- /**
* Set position ECEF.
*
* @param positionEcef position ECEF object
@@ -557,6 +538,7 @@
public Builder setPositionEcef(
@NonNull PositionEcef positionEcef) {
mPositionEcef = positionEcef;
+ updateFlags();
return this;
}
@@ -570,6 +552,7 @@
public Builder setVelocityEcef(
@NonNull VelocityEcef velocityEcef) {
mVelocityEcef = velocityEcef;
+ updateFlags();
return this;
}
@@ -583,9 +566,16 @@
public Builder setClockInfo(
@NonNull ClockInfo clockInfo) {
mClockInfo = clockInfo;
+ updateFlags();
return this;
}
+ private void updateFlags() {
+ if (mPositionEcef != null && mVelocityEcef != null && mClockInfo != null) {
+ mFlags = (byte) (mFlags | HAS_POSITION_VELOCITY_CLOCK_INFO);
+ }
+ }
+
/**
* Set ionospheric delay in meters.
*
@@ -593,8 +583,10 @@
* @return Builder builder object
*/
@NonNull
- public Builder setIonoDelayMeters(@FloatRange() double ionoDelayMeters) {
+ public Builder setIonoDelayMeters(
+ @FloatRange(from = 0.0f, to = 100.0f) double ionoDelayMeters) {
mIonoDelayMeters = ionoDelayMeters;
+ mFlags = (byte) (mFlags | HAS_IONO);
return this;
}
@@ -605,8 +597,10 @@
* @return Builder builder object
*/
@NonNull
- public Builder setTropoDelayMeters(@FloatRange() double tropoDelayMeters) {
+ public Builder setTropoDelayMeters(
+ @FloatRange(from = 0.0f, to = 100.0f) double tropoDelayMeters) {
mTropoDelayMeters = tropoDelayMeters;
+ mFlags = (byte) (mFlags | HAS_TROPO);
return this;
}
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 79d505e..f8297bc 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -405,9 +405,11 @@
*/
public void play() {
if (mLocalPlayer != null) {
- // do not play ringtones if stream volume is 0
- // (typically because ringer mode is silent).
- if (mAudioManager.getStreamVolume(
+ // Play ringtones if stream volume is over 0 or if it is a haptic-only ringtone
+ // (typically because ringer mode is vibrate).
+ boolean isHapticOnly = AudioManager.hasHapticChannels(mUri)
+ && !mAudioAttributes.areHapticChannelsMuted() && mVolume == 0;
+ if (isHapticOnly || mAudioManager.getStreamVolume(
AudioAttributes.toLegacyStreamType(mAudioAttributes)) != 0) {
startLocalPlayer();
}
diff --git a/packages/Connectivity/OWNERS b/packages/Connectivity/OWNERS
deleted file mode 100644
index 48e54da..0000000
--- a/packages/Connectivity/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-set noparent
-
-include platform/frameworks/base:/services/core/java/com/android/server/net/OWNERS
diff --git a/packages/Connectivity/TEST_MAPPING b/packages/Connectivity/TEST_MAPPING
deleted file mode 100644
index 94f9232..0000000
--- a/packages/Connectivity/TEST_MAPPING
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "imports": [
- {
- "path": "frameworks/base/core/java/android/net"
- },
- {
- "path": "packages/modules/NetworkStack"
- },
- {
- "path": "packages/modules/CaptivePortalLogin"
- },
- {
- "path": "packages/modules/Connectivity"
- },
- {
- "path": "packages/modules/Connectivity/Tethering"
- }
- ]
-}
\ No newline at end of file
diff --git a/packages/Connectivity/framework/Android.bp b/packages/Connectivity/framework/Android.bp
deleted file mode 100644
index 6eb8348..0000000
--- a/packages/Connectivity/framework/Android.bp
+++ /dev/null
@@ -1,165 +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 {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-filegroup {
- name: "framework-connectivity-internal-sources",
- srcs: [
- "src/**/*.java",
- "src/**/*.aidl",
- ],
- path: "src",
- visibility: [
- "//visibility:private",
- ],
-}
-
-filegroup {
- name: "framework-connectivity-aidl-export-sources",
- srcs: [
- "aidl-export/**/*.aidl",
- ],
- path: "aidl-export",
- visibility: [
- "//visibility:private",
- ],
-}
-
-// TODO: use a java_library in the bootclasspath instead
-filegroup {
- name: "framework-connectivity-sources",
- srcs: [
- ":framework-connectivity-internal-sources",
- ":framework-connectivity-aidl-export-sources",
- ],
- visibility: [
- "//frameworks/base",
- "//packages/modules/Connectivity:__subpackages__",
- ],
-}
-
-java_library {
- name: "framework-connectivity-annotations",
- sdk_version: "module_current",
- srcs: [
- "src/android/net/ConnectivityAnnotations.java",
- ],
- libs: [
- "framework-annotations-lib",
- "framework-connectivity",
- ],
- visibility: [
- "//frameworks/base:__subpackages__",
- "//packages/modules/Connectivity:__subpackages__",
- ],
-}
-
-java_sdk_library {
- name: "framework-connectivity",
- sdk_version: "module_current",
- min_sdk_version: "30",
- defaults: ["framework-module-defaults"],
- installable: true,
- srcs: [
- ":framework-connectivity-sources",
- ":net-utils-framework-common-srcs",
- ],
- aidl: {
- include_dirs: [
- // Include directories for parcelables that are part of the stable API, and need a
- // one-line "parcelable X" .aidl declaration to be used in AIDL interfaces.
- // TODO(b/180293679): remove these dependencies as they should not be necessary once
- // the module builds against API (the parcelable declarations exist in framework.aidl)
- "frameworks/base/core/java", // For framework parcelables
- "frameworks/native/aidl/binder", // For PersistableBundle.aidl
- ],
- },
- impl_only_libs: [
- // TODO (b/183097033) remove once module_current includes core_platform
- "stable.core.platform.api.stubs",
- "framework-tethering.stubs.module_lib",
- "framework-wifi.stubs.module_lib",
- "net-utils-device-common",
- ],
- libs: [
- "unsupportedappusage",
- ],
- jarjar_rules: "jarjar-rules.txt",
- permitted_packages: ["android.net"],
- impl_library_visibility: [
- "//packages/modules/Connectivity/Tethering/apex",
- // In preparation for future move
- "//packages/modules/Connectivity/apex",
- "//packages/modules/Connectivity/service",
- "//frameworks/base/packages/Connectivity/service",
- "//frameworks/base",
-
- // Tests using hidden APIs
- "//cts/tests/netlegacy22.api",
- "//external/sl4a:__subpackages__",
- "//frameworks/base/packages/Connectivity/tests:__subpackages__",
- "//frameworks/libs/net/common/testutils",
- "//frameworks/libs/net/common/tests:__subpackages__",
- "//frameworks/opt/telephony/tests/telephonytests",
- "//packages/modules/CaptivePortalLogin/tests",
- "//packages/modules/Connectivity/Tethering/tests:__subpackages__",
- "//packages/modules/Connectivity/tests:__subpackages__",
- "//packages/modules/NetworkStack/tests:__subpackages__",
- "//packages/modules/Wifi/service/tests/wifitests",
- ],
- apex_available: [
- "com.android.tethering",
- ],
-}
-
-cc_library_shared {
- name: "libframework-connectivity-jni",
- min_sdk_version: "30",
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-unused-parameter",
- // Don't warn about S API usage even with
- // min_sdk 30: the library is only loaded
- // on S+ devices
- "-Wno-unguarded-availability",
- "-Wthread-safety",
- ],
- srcs: [
- "jni/android_net_NetworkUtils.cpp",
- "jni/onload.cpp",
- ],
- shared_libs: [
- "libandroid",
- "liblog",
- "libnativehelper",
- ],
- header_libs: [
- "dnsproxyd_protocol_headers",
- ],
- stl: "none",
- apex_available: [
- "com.android.tethering",
- ],
-}
diff --git a/packages/Connectivity/framework/aidl-export/android/net/CaptivePortalData.aidl b/packages/Connectivity/framework/aidl-export/android/net/CaptivePortalData.aidl
deleted file mode 100644
index 1d57ee7..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/CaptivePortalData.aidl
+++ /dev/null
@@ -1,19 +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 android.net;
-
-@JavaOnlyStableParcelable parcelable CaptivePortalData;
diff --git a/packages/Connectivity/framework/aidl-export/android/net/ConnectivityDiagnosticsManager.aidl b/packages/Connectivity/framework/aidl-export/android/net/ConnectivityDiagnosticsManager.aidl
deleted file mode 100644
index 82ba0ca..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/ConnectivityDiagnosticsManager.aidl
+++ /dev/null
@@ -1,21 +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.net;
-
-parcelable ConnectivityDiagnosticsManager.ConnectivityReport;
-parcelable ConnectivityDiagnosticsManager.DataStallReport;
\ No newline at end of file
diff --git a/packages/Connectivity/framework/aidl-export/android/net/DhcpInfo.aidl b/packages/Connectivity/framework/aidl-export/android/net/DhcpInfo.aidl
deleted file mode 100644
index 29cd21f..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/DhcpInfo.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * 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.
- */
-
-package android.net;
-
-parcelable DhcpInfo;
diff --git a/packages/Connectivity/framework/aidl-export/android/net/IpConfiguration.aidl b/packages/Connectivity/framework/aidl-export/android/net/IpConfiguration.aidl
deleted file mode 100644
index 7a30f0e..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/IpConfiguration.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-parcelable IpConfiguration;
diff --git a/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl b/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl
deleted file mode 100644
index 3495efc..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- *
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-// @JavaOnlyStableParcelable only affects the parcelable when built as stable aidl (aidl_interface
-// build rule).
-@JavaOnlyStableParcelable parcelable IpPrefix;
diff --git a/packages/Connectivity/framework/aidl-export/android/net/KeepalivePacketData.aidl b/packages/Connectivity/framework/aidl-export/android/net/KeepalivePacketData.aidl
deleted file mode 100644
index d456b53..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/KeepalivePacketData.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-parcelable KeepalivePacketData;
diff --git a/packages/Connectivity/framework/aidl-export/android/net/LinkAddress.aidl b/packages/Connectivity/framework/aidl-export/android/net/LinkAddress.aidl
deleted file mode 100644
index 9c804db..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/LinkAddress.aidl
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- *
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-@JavaOnlyStableParcelable parcelable LinkAddress;
-
diff --git a/packages/Connectivity/framework/aidl-export/android/net/LinkProperties.aidl b/packages/Connectivity/framework/aidl-export/android/net/LinkProperties.aidl
deleted file mode 100644
index a8b3c7b..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/LinkProperties.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-**
-** Copyright (C) 2010 The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.net;
-
-@JavaOnlyStableParcelable parcelable LinkProperties;
diff --git a/packages/Connectivity/framework/aidl-export/android/net/MacAddress.aidl b/packages/Connectivity/framework/aidl-export/android/net/MacAddress.aidl
deleted file mode 100644
index 48a18a7..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/MacAddress.aidl
+++ /dev/null
@@ -1,20 +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 android.net;
-
-@JavaOnlyStableParcelable parcelable MacAddress;
diff --git a/packages/Connectivity/framework/aidl-export/android/net/Network.aidl b/packages/Connectivity/framework/aidl-export/android/net/Network.aidl
deleted file mode 100644
index 05622025b..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/Network.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-**
-** Copyright (C) 2014 The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.net;
-
-@JavaOnlyStableParcelable parcelable Network;
diff --git a/packages/Connectivity/framework/aidl-export/android/net/NetworkAgentConfig.aidl b/packages/Connectivity/framework/aidl-export/android/net/NetworkAgentConfig.aidl
deleted file mode 100644
index cb70bdd..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/NetworkAgentConfig.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-parcelable NetworkAgentConfig;
diff --git a/packages/Connectivity/framework/aidl-export/android/net/NetworkCapabilities.aidl b/packages/Connectivity/framework/aidl-export/android/net/NetworkCapabilities.aidl
deleted file mode 100644
index 01d3286..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/NetworkCapabilities.aidl
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
-**
-** Copyright (C) 2014 The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.net;
-
-@JavaOnlyStableParcelable parcelable NetworkCapabilities;
-
diff --git a/packages/Connectivity/framework/aidl-export/android/net/NetworkInfo.aidl b/packages/Connectivity/framework/aidl-export/android/net/NetworkInfo.aidl
deleted file mode 100644
index f501873..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/NetworkInfo.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2007, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-parcelable NetworkInfo;
diff --git a/packages/Connectivity/framework/aidl-export/android/net/NetworkRequest.aidl b/packages/Connectivity/framework/aidl-export/android/net/NetworkRequest.aidl
deleted file mode 100644
index 508defc..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/NetworkRequest.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-parcelable NetworkRequest;
-
diff --git a/packages/Connectivity/framework/aidl-export/android/net/NetworkScore.aidl b/packages/Connectivity/framework/aidl-export/android/net/NetworkScore.aidl
deleted file mode 100644
index af12dcf..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/NetworkScore.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-parcelable NetworkScore;
-
diff --git a/packages/Connectivity/framework/aidl-export/android/net/OemNetworkPreferences.aidl b/packages/Connectivity/framework/aidl-export/android/net/OemNetworkPreferences.aidl
deleted file mode 100644
index 2b6a4ce..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/OemNetworkPreferences.aidl
+++ /dev/null
@@ -1,19 +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.net;
-
-parcelable OemNetworkPreferences;
diff --git a/packages/Connectivity/framework/aidl-export/android/net/ProxyInfo.aidl b/packages/Connectivity/framework/aidl-export/android/net/ProxyInfo.aidl
deleted file mode 100644
index a5d0c12..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/ProxyInfo.aidl
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
-**
-** Copyright (C) 2010 The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.net;
-
-@JavaOnlyStableParcelable parcelable ProxyInfo;
-
diff --git a/packages/Connectivity/framework/aidl-export/android/net/QosFilterParcelable.aidl b/packages/Connectivity/framework/aidl-export/android/net/QosFilterParcelable.aidl
deleted file mode 100644
index 312d635..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/QosFilterParcelable.aidl
+++ /dev/null
@@ -1,21 +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.net;
-
-parcelable QosFilterParcelable;
-
diff --git a/packages/Connectivity/framework/aidl-export/android/net/QosSocketInfo.aidl b/packages/Connectivity/framework/aidl-export/android/net/QosSocketInfo.aidl
deleted file mode 100644
index 476c090..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/QosSocketInfo.aidl
+++ /dev/null
@@ -1,21 +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.net;
-
-parcelable QosSocketInfo;
-
diff --git a/packages/Connectivity/framework/aidl-export/android/net/RouteInfo.aidl b/packages/Connectivity/framework/aidl-export/android/net/RouteInfo.aidl
deleted file mode 100644
index 7af9fda..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/RouteInfo.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-@JavaOnlyStableParcelable parcelable RouteInfo;
diff --git a/packages/Connectivity/framework/aidl-export/android/net/StaticIpConfiguration.aidl b/packages/Connectivity/framework/aidl-export/android/net/StaticIpConfiguration.aidl
deleted file mode 100644
index 8aac701..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/StaticIpConfiguration.aidl
+++ /dev/null
@@ -1,20 +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 android.net;
-
-@JavaOnlyStableParcelable parcelable StaticIpConfiguration;
\ No newline at end of file
diff --git a/packages/Connectivity/framework/aidl-export/android/net/TestNetworkInterface.aidl b/packages/Connectivity/framework/aidl-export/android/net/TestNetworkInterface.aidl
deleted file mode 100644
index e1f4f9f..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/TestNetworkInterface.aidl
+++ /dev/null
@@ -1,20 +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 android.net;
-
-/** @hide */
-parcelable TestNetworkInterface;
diff --git a/packages/Connectivity/framework/aidl-export/android/net/apf/ApfCapabilities.aidl b/packages/Connectivity/framework/aidl-export/android/net/apf/ApfCapabilities.aidl
deleted file mode 100644
index 7c4d4c2..0000000
--- a/packages/Connectivity/framework/aidl-export/android/net/apf/ApfCapabilities.aidl
+++ /dev/null
@@ -1,20 +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 android.net.apf;
-
-@JavaOnlyStableParcelable parcelable ApfCapabilities;
\ No newline at end of file
diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt
deleted file mode 100644
index 33f4d14..0000000
--- a/packages/Connectivity/framework/api/current.txt
+++ /dev/null
@@ -1,476 +0,0 @@
-// Signature format: 2.0
-package android.net {
-
- public class CaptivePortal implements android.os.Parcelable {
- method public int describeContents();
- method public void ignoreNetwork();
- method public void reportCaptivePortalDismissed();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortal> CREATOR;
- }
-
- public class ConnectivityDiagnosticsManager {
- method public void registerConnectivityDiagnosticsCallback(@NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
- method public void unregisterConnectivityDiagnosticsCallback(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
- }
-
- public abstract static class ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback {
- ctor public ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback();
- method public void onConnectivityReportAvailable(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityReport);
- method public void onDataStallSuspected(@NonNull android.net.ConnectivityDiagnosticsManager.DataStallReport);
- method public void onNetworkConnectivityReported(@NonNull android.net.Network, boolean);
- }
-
- public static final class ConnectivityDiagnosticsManager.ConnectivityReport implements android.os.Parcelable {
- ctor public ConnectivityDiagnosticsManager.ConnectivityReport(@NonNull android.net.Network, long, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
- method public int describeContents();
- method @NonNull public android.os.PersistableBundle getAdditionalInfo();
- method @NonNull public android.net.LinkProperties getLinkProperties();
- method @NonNull public android.net.Network getNetwork();
- method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
- method public long getReportTimestamp();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.ConnectivityReport> CREATOR;
- field public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttempted";
- field public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = "networkProbesSucceeded";
- field public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
- field public static final int NETWORK_PROBE_DNS = 4; // 0x4
- field public static final int NETWORK_PROBE_FALLBACK = 32; // 0x20
- field public static final int NETWORK_PROBE_HTTP = 8; // 0x8
- field public static final int NETWORK_PROBE_HTTPS = 16; // 0x10
- field public static final int NETWORK_PROBE_PRIVATE_DNS = 64; // 0x40
- field public static final int NETWORK_VALIDATION_RESULT_INVALID = 0; // 0x0
- field public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2; // 0x2
- field public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3; // 0x3
- field public static final int NETWORK_VALIDATION_RESULT_VALID = 1; // 0x1
- }
-
- public static final class ConnectivityDiagnosticsManager.DataStallReport implements android.os.Parcelable {
- ctor public ConnectivityDiagnosticsManager.DataStallReport(@NonNull android.net.Network, long, int, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
- method public int describeContents();
- method public int getDetectionMethod();
- method @NonNull public android.net.LinkProperties getLinkProperties();
- method @NonNull public android.net.Network getNetwork();
- method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
- method public long getReportTimestamp();
- method @NonNull public android.os.PersistableBundle getStallDetails();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.DataStallReport> CREATOR;
- field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1
- field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2
- field public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts";
- field public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS = "tcpMetricsCollectionPeriodMillis";
- field public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate";
- }
-
- public class ConnectivityManager {
- method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
- method public boolean bindProcessToNetwork(@Nullable android.net.Network);
- method @NonNull public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull android.net.IpSecManager.UdpEncapsulationSocket, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
- method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork();
- method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
- method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
- method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
- method @Deprecated public boolean getBackgroundDataSetting();
- method @Nullable public android.net.Network getBoundNetworkForProcess();
- method public int getConnectionOwnerUid(int, @NonNull java.net.InetSocketAddress, @NonNull java.net.InetSocketAddress);
- method @Nullable public android.net.ProxyInfo getDefaultProxy();
- method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.LinkProperties getLinkProperties(@Nullable android.net.Network);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getMultipathPreference(@Nullable android.net.Network);
- method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkCapabilities getNetworkCapabilities(@Nullable android.net.Network);
- method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(int);
- method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(@Nullable android.net.Network);
- method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getNetworkPreference();
- method @Nullable public byte[] getNetworkWatchlistConfigHash();
- method @Deprecated @Nullable public static android.net.Network getProcessDefaultNetwork();
- method public int getRestrictBackgroundStatus();
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public boolean isActiveNetworkMetered();
- method public boolean isDefaultNetworkActive();
- method @Deprecated public static boolean isNetworkTypeValid(int);
- method public void registerBestMatchingNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent);
- method public void releaseNetworkRequest(@NonNull android.app.PendingIntent);
- method public void removeDefaultNetworkActiveListener(@NonNull android.net.ConnectivityManager.OnNetworkActiveListener);
- method @Deprecated public void reportBadNetwork(@Nullable android.net.Network);
- method public void reportNetworkConnectivity(@Nullable android.net.Network, boolean);
- method public boolean requestBandwidthUpdate(@NonNull android.net.Network);
- method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
- method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, int);
- method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler, int);
- method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent);
- method @Deprecated public void setNetworkPreference(int);
- method @Deprecated public static boolean setProcessDefaultNetwork(@Nullable android.net.Network);
- method public void unregisterNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
- method public void unregisterNetworkCallback(@NonNull android.app.PendingIntent);
- field @Deprecated public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
- field public static final String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL";
- field public static final String ACTION_RESTRICT_BACKGROUND_CHANGED = "android.net.conn.RESTRICT_BACKGROUND_CHANGED";
- field @Deprecated public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
- field @Deprecated public static final int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
- field public static final String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
- field public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
- field @Deprecated public static final String EXTRA_EXTRA_INFO = "extraInfo";
- field @Deprecated public static final String EXTRA_IS_FAILOVER = "isFailover";
- field public static final String EXTRA_NETWORK = "android.net.extra.NETWORK";
- field @Deprecated public static final String EXTRA_NETWORK_INFO = "networkInfo";
- field public static final String EXTRA_NETWORK_REQUEST = "android.net.extra.NETWORK_REQUEST";
- field @Deprecated public static final String EXTRA_NETWORK_TYPE = "networkType";
- field public static final String EXTRA_NO_CONNECTIVITY = "noConnectivity";
- field @Deprecated public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
- field public static final String EXTRA_REASON = "reason";
- field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1
- field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4
- field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2
- field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
- field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
- field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
- field @Deprecated public static final int TYPE_BLUETOOTH = 7; // 0x7
- field @Deprecated public static final int TYPE_DUMMY = 8; // 0x8
- field @Deprecated public static final int TYPE_ETHERNET = 9; // 0x9
- field @Deprecated public static final int TYPE_MOBILE = 0; // 0x0
- field @Deprecated public static final int TYPE_MOBILE_DUN = 4; // 0x4
- field @Deprecated public static final int TYPE_MOBILE_HIPRI = 5; // 0x5
- field @Deprecated public static final int TYPE_MOBILE_MMS = 2; // 0x2
- field @Deprecated public static final int TYPE_MOBILE_SUPL = 3; // 0x3
- field @Deprecated public static final int TYPE_VPN = 17; // 0x11
- field @Deprecated public static final int TYPE_WIFI = 1; // 0x1
- field @Deprecated public static final int TYPE_WIMAX = 6; // 0x6
- }
-
- public static class ConnectivityManager.NetworkCallback {
- ctor public ConnectivityManager.NetworkCallback();
- ctor public ConnectivityManager.NetworkCallback(int);
- method public void onAvailable(@NonNull android.net.Network);
- method public void onBlockedStatusChanged(@NonNull android.net.Network, boolean);
- method public void onCapabilitiesChanged(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities);
- method public void onLinkPropertiesChanged(@NonNull android.net.Network, @NonNull android.net.LinkProperties);
- method public void onLosing(@NonNull android.net.Network, int);
- method public void onLost(@NonNull android.net.Network);
- method public void onUnavailable();
- field public static final int FLAG_INCLUDE_LOCATION_INFO = 1; // 0x1
- }
-
- public static interface ConnectivityManager.OnNetworkActiveListener {
- method public void onNetworkActive();
- }
-
- public class DhcpInfo implements android.os.Parcelable {
- ctor public DhcpInfo();
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.DhcpInfo> CREATOR;
- field public int dns1;
- field public int dns2;
- field public int gateway;
- field public int ipAddress;
- field public int leaseDuration;
- field public int netmask;
- field public int serverAddress;
- }
-
- public final class DnsResolver {
- method @NonNull public static android.net.DnsResolver getInstance();
- method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>);
- method public void query(@Nullable android.net.Network, @NonNull String, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>);
- method public void rawQuery(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>);
- method public void rawQuery(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>);
- field public static final int CLASS_IN = 1; // 0x1
- field public static final int ERROR_PARSE = 0; // 0x0
- field public static final int ERROR_SYSTEM = 1; // 0x1
- field public static final int FLAG_EMPTY = 0; // 0x0
- field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4
- field public static final int FLAG_NO_CACHE_STORE = 2; // 0x2
- field public static final int FLAG_NO_RETRY = 1; // 0x1
- field public static final int TYPE_A = 1; // 0x1
- field public static final int TYPE_AAAA = 28; // 0x1c
- }
-
- public static interface DnsResolver.Callback<T> {
- method public void onAnswer(@NonNull T, int);
- method public void onError(@NonNull android.net.DnsResolver.DnsException);
- }
-
- public static class DnsResolver.DnsException extends java.lang.Exception {
- field public final int code;
- }
-
- public class InetAddresses {
- method public static boolean isNumericAddress(@NonNull String);
- method @NonNull public static java.net.InetAddress parseNumericAddress(@NonNull String);
- }
-
- public final class IpPrefix implements android.os.Parcelable {
- method public boolean contains(@NonNull java.net.InetAddress);
- method public int describeContents();
- method @NonNull public java.net.InetAddress getAddress();
- method @IntRange(from=0, to=128) public int getPrefixLength();
- method @NonNull public byte[] getRawAddress();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
- }
-
- public class LinkAddress implements android.os.Parcelable {
- method public int describeContents();
- method public java.net.InetAddress getAddress();
- method public int getFlags();
- method @IntRange(from=0, to=128) public int getPrefixLength();
- method public int getScope();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkAddress> CREATOR;
- }
-
- public final class LinkProperties implements android.os.Parcelable {
- ctor public LinkProperties();
- method public boolean addRoute(@NonNull android.net.RouteInfo);
- method public void clear();
- method public int describeContents();
- method @Nullable public java.net.Inet4Address getDhcpServerAddress();
- method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
- method @Nullable public String getDomains();
- method @Nullable public android.net.ProxyInfo getHttpProxy();
- method @Nullable public String getInterfaceName();
- method @NonNull public java.util.List<android.net.LinkAddress> getLinkAddresses();
- method public int getMtu();
- method @Nullable public android.net.IpPrefix getNat64Prefix();
- method @Nullable public String getPrivateDnsServerName();
- method @NonNull public java.util.List<android.net.RouteInfo> getRoutes();
- method public boolean isPrivateDnsActive();
- method public boolean isWakeOnLanSupported();
- method public void setDhcpServerAddress(@Nullable java.net.Inet4Address);
- method public void setDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
- method public void setDomains(@Nullable String);
- method public void setHttpProxy(@Nullable android.net.ProxyInfo);
- method public void setInterfaceName(@Nullable String);
- method public void setLinkAddresses(@NonNull java.util.Collection<android.net.LinkAddress>);
- method public void setMtu(int);
- method public void setNat64Prefix(@Nullable android.net.IpPrefix);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkProperties> CREATOR;
- }
-
- public final class MacAddress implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public static android.net.MacAddress fromBytes(@NonNull byte[]);
- method @NonNull public static android.net.MacAddress fromString(@NonNull String);
- method public int getAddressType();
- method @Nullable public java.net.Inet6Address getLinkLocalIpv6FromEui48Mac();
- method public boolean isLocallyAssigned();
- method public boolean matches(@NonNull android.net.MacAddress, @NonNull android.net.MacAddress);
- method @NonNull public byte[] toByteArray();
- method @NonNull public String toOuiString();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.net.MacAddress BROADCAST_ADDRESS;
- field @NonNull public static final android.os.Parcelable.Creator<android.net.MacAddress> CREATOR;
- field public static final int TYPE_BROADCAST = 3; // 0x3
- field public static final int TYPE_MULTICAST = 2; // 0x2
- field public static final int TYPE_UNICAST = 1; // 0x1
- }
-
- public class Network implements android.os.Parcelable {
- method public void bindSocket(java.net.DatagramSocket) throws java.io.IOException;
- method public void bindSocket(java.net.Socket) throws java.io.IOException;
- method public void bindSocket(java.io.FileDescriptor) throws java.io.IOException;
- method public int describeContents();
- method public static android.net.Network fromNetworkHandle(long);
- method public java.net.InetAddress[] getAllByName(String) throws java.net.UnknownHostException;
- method public java.net.InetAddress getByName(String) throws java.net.UnknownHostException;
- method public long getNetworkHandle();
- method public javax.net.SocketFactory getSocketFactory();
- method public java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException;
- method public java.net.URLConnection openConnection(java.net.URL, java.net.Proxy) throws java.io.IOException;
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.Network> CREATOR;
- }
-
- public final class NetworkCapabilities implements android.os.Parcelable {
- ctor public NetworkCapabilities();
- ctor public NetworkCapabilities(android.net.NetworkCapabilities);
- method public int describeContents();
- method @NonNull public int[] getCapabilities();
- method public int getLinkDownstreamBandwidthKbps();
- method public int getLinkUpstreamBandwidthKbps();
- method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
- method public int getOwnerUid();
- method public int getSignalStrength();
- method @Nullable public android.net.TransportInfo getTransportInfo();
- method public boolean hasCapability(int);
- method public boolean hasTransport(int);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkCapabilities> CREATOR;
- field public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17; // 0x11
- field public static final int NET_CAPABILITY_CBS = 5; // 0x5
- field public static final int NET_CAPABILITY_DUN = 2; // 0x2
- field public static final int NET_CAPABILITY_EIMS = 10; // 0xa
- field public static final int NET_CAPABILITY_ENTERPRISE = 29; // 0x1d
- field public static final int NET_CAPABILITY_FOREGROUND = 19; // 0x13
- field public static final int NET_CAPABILITY_FOTA = 3; // 0x3
- field public static final int NET_CAPABILITY_HEAD_UNIT = 32; // 0x20
- field public static final int NET_CAPABILITY_IA = 7; // 0x7
- field public static final int NET_CAPABILITY_IMS = 4; // 0x4
- field public static final int NET_CAPABILITY_INTERNET = 12; // 0xc
- field public static final int NET_CAPABILITY_MCX = 23; // 0x17
- field public static final int NET_CAPABILITY_MMS = 0; // 0x0
- field public static final int NET_CAPABILITY_NOT_CONGESTED = 20; // 0x14
- field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
- field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
- field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
- field public static final int NET_CAPABILITY_NOT_SUSPENDED = 21; // 0x15
- field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
- field public static final int NET_CAPABILITY_RCS = 8; // 0x8
- field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
- field public static final int NET_CAPABILITY_TEMPORARILY_NOT_METERED = 25; // 0x19
- field public static final int NET_CAPABILITY_TRUSTED = 14; // 0xe
- field public static final int NET_CAPABILITY_VALIDATED = 16; // 0x10
- field public static final int NET_CAPABILITY_WIFI_P2P = 6; // 0x6
- field public static final int NET_CAPABILITY_XCAP = 9; // 0x9
- field public static final int SIGNAL_STRENGTH_UNSPECIFIED = -2147483648; // 0x80000000
- field public static final int TRANSPORT_BLUETOOTH = 2; // 0x2
- field public static final int TRANSPORT_CELLULAR = 0; // 0x0
- field public static final int TRANSPORT_ETHERNET = 3; // 0x3
- field public static final int TRANSPORT_LOWPAN = 6; // 0x6
- field public static final int TRANSPORT_USB = 8; // 0x8
- field public static final int TRANSPORT_VPN = 4; // 0x4
- field public static final int TRANSPORT_WIFI = 1; // 0x1
- field public static final int TRANSPORT_WIFI_AWARE = 5; // 0x5
- }
-
- @Deprecated public class NetworkInfo implements android.os.Parcelable {
- ctor @Deprecated public NetworkInfo(int, int, @Nullable String, @Nullable String);
- method @Deprecated public int describeContents();
- method @Deprecated @NonNull public android.net.NetworkInfo.DetailedState getDetailedState();
- method @Deprecated public String getExtraInfo();
- method @Deprecated public String getReason();
- method @Deprecated public android.net.NetworkInfo.State getState();
- method @Deprecated public int getSubtype();
- method @Deprecated public String getSubtypeName();
- method @Deprecated public int getType();
- method @Deprecated public String getTypeName();
- method @Deprecated public boolean isAvailable();
- method @Deprecated public boolean isConnected();
- method @Deprecated public boolean isConnectedOrConnecting();
- method @Deprecated public boolean isFailover();
- method @Deprecated public boolean isRoaming();
- method @Deprecated public void setDetailedState(@NonNull android.net.NetworkInfo.DetailedState, @Nullable String, @Nullable String);
- method @Deprecated public void writeToParcel(android.os.Parcel, int);
- field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
- }
-
- @Deprecated public enum NetworkInfo.DetailedState {
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState AUTHENTICATING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState BLOCKED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CAPTIVE_PORTAL_CHECK;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState FAILED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState IDLE;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState OBTAINING_IPADDR;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SCANNING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SUSPENDED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState VERIFYING_POOR_LINK;
- }
-
- @Deprecated public enum NetworkInfo.State {
- enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTING;
- enum_constant @Deprecated public static final android.net.NetworkInfo.State SUSPENDED;
- enum_constant @Deprecated public static final android.net.NetworkInfo.State UNKNOWN;
- }
-
- public class NetworkRequest implements android.os.Parcelable {
- method public boolean canBeSatisfiedBy(@Nullable android.net.NetworkCapabilities);
- method public int describeContents();
- method @NonNull public int[] getCapabilities();
- method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
- method @NonNull public int[] getTransportTypes();
- method public boolean hasCapability(int);
- method public boolean hasTransport(int);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkRequest> CREATOR;
- }
-
- public static class NetworkRequest.Builder {
- ctor public NetworkRequest.Builder();
- ctor public NetworkRequest.Builder(@NonNull android.net.NetworkRequest);
- method public android.net.NetworkRequest.Builder addCapability(int);
- method public android.net.NetworkRequest.Builder addTransportType(int);
- method public android.net.NetworkRequest build();
- method @NonNull public android.net.NetworkRequest.Builder clearCapabilities();
- method public android.net.NetworkRequest.Builder removeCapability(int);
- method public android.net.NetworkRequest.Builder removeTransportType(int);
- method @NonNull public android.net.NetworkRequest.Builder setIncludeOtherUidNetworks(boolean);
- method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
- method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
- }
-
- public class ParseException extends java.lang.RuntimeException {
- ctor public ParseException(@NonNull String);
- ctor public ParseException(@NonNull String, @NonNull Throwable);
- field public String response;
- }
-
- public class ProxyInfo implements android.os.Parcelable {
- ctor public ProxyInfo(@Nullable android.net.ProxyInfo);
- method public static android.net.ProxyInfo buildDirectProxy(String, int);
- method public static android.net.ProxyInfo buildDirectProxy(String, int, java.util.List<java.lang.String>);
- method public static android.net.ProxyInfo buildPacProxy(android.net.Uri);
- method @NonNull public static android.net.ProxyInfo buildPacProxy(@NonNull android.net.Uri, int);
- method public int describeContents();
- method public String[] getExclusionList();
- method public String getHost();
- method public android.net.Uri getPacFileUrl();
- method public int getPort();
- method public boolean isValid();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR;
- }
-
- public final class RouteInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.net.IpPrefix getDestination();
- method @Nullable public java.net.InetAddress getGateway();
- method @Nullable public String getInterface();
- method public boolean hasGateway();
- method public boolean isDefaultRoute();
- method public boolean matches(java.net.InetAddress);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.RouteInfo> CREATOR;
- }
-
- public abstract class SocketKeepalive implements java.lang.AutoCloseable {
- method public final void close();
- method public final void start(@IntRange(from=0xa, to=0xe10) int);
- method public final void stop();
- field public static final int ERROR_HARDWARE_ERROR = -31; // 0xffffffe1
- field public static final int ERROR_INSUFFICIENT_RESOURCES = -32; // 0xffffffe0
- field public static final int ERROR_INVALID_INTERVAL = -24; // 0xffffffe8
- field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
- field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
- field public static final int ERROR_INVALID_NETWORK = -20; // 0xffffffec
- field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
- field public static final int ERROR_INVALID_SOCKET = -25; // 0xffffffe7
- field public static final int ERROR_SOCKET_NOT_IDLE = -26; // 0xffffffe6
- field public static final int ERROR_UNSUPPORTED = -30; // 0xffffffe2
- }
-
- public static class SocketKeepalive.Callback {
- ctor public SocketKeepalive.Callback();
- method public void onDataReceived();
- method public void onError(int);
- method public void onStarted();
- method public void onStopped();
- }
-
- public interface TransportInfo {
- }
-
-}
-
diff --git a/packages/Connectivity/framework/api/lint-baseline.txt b/packages/Connectivity/framework/api/lint-baseline.txt
deleted file mode 100644
index 2f4004a..0000000
--- a/packages/Connectivity/framework/api/lint-baseline.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-// Baseline format: 1.0
-VisiblySynchronized: android.net.NetworkInfo#toString():
- Internal locks must not be exposed (synchronizing on this or class is still
- externally observable): method android.net.NetworkInfo.toString()
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
deleted file mode 100644
index 6c454bc..0000000
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ /dev/null
@@ -1,179 +0,0 @@
-// Signature format: 2.0
-package android.net {
-
- public final class ConnectivityFrameworkInitializer {
- method public static void registerServiceWrappers();
- }
-
- public class ConnectivityManager {
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void factoryReset();
- method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshots();
- method @Nullable public android.net.ProxyInfo getGlobalProxy();
- method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange();
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackForUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
- method @Deprecated public boolean requestRouteToHostAddress(int, java.net.InetAddress);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptPartialConnectivity(@NonNull android.net.Network, boolean, boolean);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptUnvalidated(@NonNull android.net.Network, boolean, boolean);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network);
- method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>);
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void startCaptivePortalApp(@NonNull android.net.Network);
- method public void systemReady();
- field public static final String ACTION_CLEAR_DNS_CACHE = "android.net.action.CLEAR_DNS_CACHE";
- field public static final String ACTION_PROMPT_LOST_VALIDATION = "android.net.action.PROMPT_LOST_VALIDATION";
- field public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY = "android.net.action.PROMPT_PARTIAL_CONNECTIVITY";
- field public static final String ACTION_PROMPT_UNVALIDATED = "android.net.action.PROMPT_UNVALIDATED";
- field public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 262144; // 0x40000
- field public static final int BLOCKED_METERED_REASON_DATA_SAVER = 65536; // 0x10000
- field public static final int BLOCKED_METERED_REASON_MASK = -65536; // 0xffff0000
- field public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 131072; // 0x20000
- field public static final int BLOCKED_REASON_APP_STANDBY = 4; // 0x4
- field public static final int BLOCKED_REASON_BATTERY_SAVER = 1; // 0x1
- field public static final int BLOCKED_REASON_DOZE = 2; // 0x2
- field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10
- field public static final int BLOCKED_REASON_NONE = 0; // 0x0
- field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
- field public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0; // 0x0
- field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1
- }
-
- public static class ConnectivityManager.NetworkCallback {
- method public void onBlockedStatusChanged(@NonNull android.net.Network, int);
- }
-
- public class ConnectivitySettingsManager {
- method public static void clearGlobalProxy(@NonNull android.content.Context);
- method @NonNull public static java.util.Set<java.lang.String> getAppsAllowedOnRestrictedNetworks(@NonNull android.content.Context);
- method @Nullable public static String getCaptivePortalHttpUrl(@NonNull android.content.Context);
- method public static int getCaptivePortalMode(@NonNull android.content.Context, int);
- method @NonNull public static java.time.Duration getConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
- method @NonNull public static android.util.Range<java.lang.Integer> getDnsResolverSampleRanges(@NonNull android.content.Context);
- method @NonNull public static java.time.Duration getDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
- method public static int getDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, int);
- method @Nullable public static android.net.ProxyInfo getGlobalProxy(@NonNull android.content.Context);
- method @NonNull public static java.time.Duration getMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
- method public static boolean getMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
- method @NonNull public static java.util.Set<java.lang.Integer> getMobileDataPreferredUids(@NonNull android.content.Context);
- method public static int getNetworkAvoidBadWifi(@NonNull android.content.Context);
- method @Nullable public static String getNetworkMeteredMultipathPreference(@NonNull android.content.Context);
- method public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, int);
- method @NonNull public static java.time.Duration getNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
- method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context);
- method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context);
- method public static int getPrivateDnsMode(@NonNull android.content.Context);
- method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean);
- method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
- method public static void setAppsAllowedOnRestrictedNetworks(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.String>);
- method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String);
- method public static void setCaptivePortalMode(@NonNull android.content.Context, int);
- method public static void setConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
- method public static void setDnsResolverSampleRanges(@NonNull android.content.Context, @NonNull android.util.Range<java.lang.Integer>);
- method public static void setDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
- method public static void setDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, @IntRange(from=0, to=100) int);
- method public static void setGlobalProxy(@NonNull android.content.Context, @NonNull android.net.ProxyInfo);
- method public static void setMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
- method public static void setMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
- method public static void setMobileDataPreferredUids(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.Integer>);
- method public static void setNetworkAvoidBadWifi(@NonNull android.content.Context, int);
- method public static void setNetworkMeteredMultipathPreference(@NonNull android.content.Context, @NonNull String);
- method public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, @IntRange(from=0) int);
- method public static void setNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
- method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull int);
- method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String);
- method public static void setPrivateDnsMode(@NonNull android.content.Context, int);
- method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean);
- method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
- field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2
- field public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; // 0x0
- field public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; // 0x1
- field public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2; // 0x2
- field public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0; // 0x0
- field public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1; // 0x1
- field public static final int PRIVATE_DNS_MODE_OFF = 1; // 0x1
- field public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; // 0x2
- field public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; // 0x3
- }
-
- public final class NetworkAgentConfig implements android.os.Parcelable {
- method @Nullable public String getSubscriberId();
- method public boolean isBypassableVpn();
- }
-
- public static final class NetworkAgentConfig.Builder {
- method @NonNull public android.net.NetworkAgentConfig.Builder setBypassableVpn(boolean);
- method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
- }
-
- public final class NetworkCapabilities implements android.os.Parcelable {
- method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids();
- method public boolean hasForbiddenCapability(int);
- field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL
- field public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1L; // 0x1L
- field public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 2L; // 0x2L
- field public static final long REDACT_FOR_NETWORK_SETTINGS = 4L; // 0x4L
- field public static final long REDACT_NONE = 0L; // 0x0L
- field public static final int TRANSPORT_TEST = 7; // 0x7
- }
-
- public static final class NetworkCapabilities.Builder {
- method @NonNull public android.net.NetworkCapabilities.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
- }
-
- public class NetworkRequest implements android.os.Parcelable {
- method @NonNull public int[] getForbiddenCapabilities();
- method public boolean hasForbiddenCapability(int);
- }
-
- public static class NetworkRequest.Builder {
- method @NonNull public android.net.NetworkRequest.Builder addForbiddenCapability(int);
- method @NonNull public android.net.NetworkRequest.Builder removeForbiddenCapability(int);
- method @NonNull public android.net.NetworkRequest.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
- }
-
- public final class TestNetworkInterface implements android.os.Parcelable {
- ctor public TestNetworkInterface(@NonNull android.os.ParcelFileDescriptor, @NonNull String);
- method public int describeContents();
- method @NonNull public android.os.ParcelFileDescriptor getFileDescriptor();
- method @NonNull public String getInterfaceName();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkInterface> CREATOR;
- }
-
- public class TestNetworkManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_TEST_NETWORKS) public android.net.TestNetworkInterface createTapInterface();
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_TEST_NETWORKS) public android.net.TestNetworkInterface createTunInterface(@NonNull java.util.Collection<android.net.LinkAddress>);
- method @RequiresPermission(android.Manifest.permission.MANAGE_TEST_NETWORKS) public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder);
- method @RequiresPermission(android.Manifest.permission.MANAGE_TEST_NETWORKS) public void teardownTestNetwork(@NonNull android.net.Network);
- field public static final String TEST_TAP_PREFIX = "testtap";
- }
-
- public final class TestNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
- ctor public TestNetworkSpecifier(@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.TestNetworkSpecifier> CREATOR;
- }
-
- public interface TransportInfo {
- method public default long getApplicableRedactions();
- method @NonNull public default android.net.TransportInfo makeCopy(long);
- }
-
- public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
- ctor public VpnTransportInfo(int, @Nullable String);
- method public int describeContents();
- method @Nullable public String getSessionId();
- method public int getType();
- method @NonNull public android.net.VpnTransportInfo makeCopy(long);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR;
- }
-
-}
-
diff --git a/packages/Connectivity/framework/api/module-lib-removed.txt b/packages/Connectivity/framework/api/module-lib-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/packages/Connectivity/framework/api/module-lib-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/packages/Connectivity/framework/api/removed.txt b/packages/Connectivity/framework/api/removed.txt
deleted file mode 100644
index 303a1e61..0000000
--- a/packages/Connectivity/framework/api/removed.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-// Signature format: 2.0
-package android.net {
-
- public class ConnectivityManager {
- method @Deprecated public boolean requestRouteToHost(int, int);
- method @Deprecated public int startUsingNetworkFeature(int, String);
- method @Deprecated public int stopUsingNetworkFeature(int, String);
- }
-
-}
-
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
deleted file mode 100644
index d1d51da..0000000
--- a/packages/Connectivity/framework/api/system-current.txt
+++ /dev/null
@@ -1,505 +0,0 @@
-// Signature format: 2.0
-package android.net {
-
- public class CaptivePortal implements android.os.Parcelable {
- method @Deprecated public void logEvent(int, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void reevaluateNetwork();
- method public void useNetwork();
- field public static final int APP_REQUEST_REEVALUATION_REQUIRED = 100; // 0x64
- field public static final int APP_RETURN_DISMISSED = 0; // 0x0
- field public static final int APP_RETURN_UNWANTED = 1; // 0x1
- field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2
- }
-
- public final class CaptivePortalData implements android.os.Parcelable {
- method public int describeContents();
- method public long getByteLimit();
- method public long getExpiryTimeMillis();
- method public long getRefreshTimeMillis();
- method @Nullable public android.net.Uri getUserPortalUrl();
- method public int getUserPortalUrlSource();
- method @Nullable public CharSequence getVenueFriendlyName();
- method @Nullable public android.net.Uri getVenueInfoUrl();
- method public int getVenueInfoUrlSource();
- method public boolean isCaptive();
- method public boolean isSessionExtendable();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final int CAPTIVE_PORTAL_DATA_SOURCE_OTHER = 0; // 0x0
- field public static final int CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT = 1; // 0x1
- field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortalData> CREATOR;
- }
-
- public static class CaptivePortalData.Builder {
- ctor public CaptivePortalData.Builder();
- ctor public CaptivePortalData.Builder(@Nullable android.net.CaptivePortalData);
- method @NonNull public android.net.CaptivePortalData build();
- method @NonNull public android.net.CaptivePortalData.Builder setBytesRemaining(long);
- method @NonNull public android.net.CaptivePortalData.Builder setCaptive(boolean);
- method @NonNull public android.net.CaptivePortalData.Builder setExpiryTime(long);
- method @NonNull public android.net.CaptivePortalData.Builder setRefreshTime(long);
- method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean);
- method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri);
- method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri, int);
- method @NonNull public android.net.CaptivePortalData.Builder setVenueFriendlyName(@Nullable CharSequence);
- method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri);
- method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri, int);
- }
-
- public class ConnectivityManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull android.os.ParcelFileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
- method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCaptivePortalServerUrl();
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
- method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
- method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull java.util.concurrent.Executor, @NonNull android.net.QosCallback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
- method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
- method @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE) public void setOemNetworkPreference(@NonNull android.net.OemNetworkPreferences, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi();
- method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
- method public void unregisterQosCallback(@NonNull android.net.QosCallback);
- method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
- field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
- field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
- field public static final int TETHERING_BLUETOOTH = 2; // 0x2
- field public static final int TETHERING_USB = 1; // 0x1
- field public static final int TETHERING_WIFI = 0; // 0x0
- field @Deprecated public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd
- field @Deprecated public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
- field @Deprecated public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
- field public static final int TYPE_NONE = -1; // 0xffffffff
- field @Deprecated public static final int TYPE_PROXY = 16; // 0x10
- field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
- }
-
- @Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback {
- ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback();
- method @Deprecated public void onTetheringFailed();
- method @Deprecated public void onTetheringStarted();
- }
-
- @Deprecated public static interface ConnectivityManager.OnTetheringEntitlementResultListener {
- method @Deprecated public void onTetheringEntitlementResult(int);
- }
-
- @Deprecated public abstract static class ConnectivityManager.OnTetheringEventCallback {
- ctor @Deprecated public ConnectivityManager.OnTetheringEventCallback();
- method @Deprecated public void onUpstreamChanged(@Nullable android.net.Network);
- }
-
- public final class InvalidPacketException extends java.lang.Exception {
- ctor public InvalidPacketException(int);
- method public int getError();
- field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
- field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
- field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
- }
-
- public final class IpConfiguration implements android.os.Parcelable {
- ctor public IpConfiguration();
- ctor public IpConfiguration(@NonNull android.net.IpConfiguration);
- method public int describeContents();
- method @Nullable public android.net.ProxyInfo getHttpProxy();
- method @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment();
- method @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings();
- method @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration();
- method public void setHttpProxy(@Nullable android.net.ProxyInfo);
- method public void setIpAssignment(@NonNull android.net.IpConfiguration.IpAssignment);
- method public void setProxySettings(@NonNull android.net.IpConfiguration.ProxySettings);
- method public void setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.IpConfiguration> CREATOR;
- }
-
- public enum IpConfiguration.IpAssignment {
- enum_constant public static final android.net.IpConfiguration.IpAssignment DHCP;
- enum_constant public static final android.net.IpConfiguration.IpAssignment STATIC;
- enum_constant public static final android.net.IpConfiguration.IpAssignment UNASSIGNED;
- }
-
- public enum IpConfiguration.ProxySettings {
- enum_constant public static final android.net.IpConfiguration.ProxySettings NONE;
- enum_constant public static final android.net.IpConfiguration.ProxySettings PAC;
- enum_constant public static final android.net.IpConfiguration.ProxySettings STATIC;
- enum_constant public static final android.net.IpConfiguration.ProxySettings UNASSIGNED;
- }
-
- public final class IpPrefix implements android.os.Parcelable {
- ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
- ctor public IpPrefix(@NonNull String);
- }
-
- public class KeepalivePacketData {
- ctor protected KeepalivePacketData(@NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull byte[]) throws android.net.InvalidPacketException;
- method @NonNull public java.net.InetAddress getDstAddress();
- method public int getDstPort();
- method @NonNull public byte[] getPacket();
- method @NonNull public java.net.InetAddress getSrcAddress();
- method public int getSrcPort();
- }
-
- public class LinkAddress implements android.os.Parcelable {
- ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
- ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long);
- ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
- ctor public LinkAddress(@NonNull String);
- ctor public LinkAddress(@NonNull String, int, int);
- method public long getDeprecationTime();
- method public long getExpirationTime();
- method public boolean isGlobalPreferred();
- method public boolean isIpv4();
- method public boolean isIpv6();
- method public boolean isSameAddressAs(@Nullable android.net.LinkAddress);
- field public static final long LIFETIME_PERMANENT = 9223372036854775807L; // 0x7fffffffffffffffL
- field public static final long LIFETIME_UNKNOWN = -1L; // 0xffffffffffffffffL
- }
-
- public final class LinkProperties implements android.os.Parcelable {
- ctor public LinkProperties(@Nullable android.net.LinkProperties);
- ctor public LinkProperties(@Nullable android.net.LinkProperties, boolean);
- method public boolean addDnsServer(@NonNull java.net.InetAddress);
- method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
- method public boolean addPcscfServer(@NonNull java.net.InetAddress);
- method @NonNull public java.util.List<java.net.InetAddress> getAddresses();
- method @NonNull public java.util.List<java.lang.String> getAllInterfaceNames();
- method @NonNull public java.util.List<android.net.LinkAddress> getAllLinkAddresses();
- method @NonNull public java.util.List<android.net.RouteInfo> getAllRoutes();
- method @Nullable public android.net.Uri getCaptivePortalApiUrl();
- method @Nullable public android.net.CaptivePortalData getCaptivePortalData();
- method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
- method @Nullable public String getTcpBufferSizes();
- method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
- method public boolean hasGlobalIpv6Address();
- method public boolean hasIpv4Address();
- method public boolean hasIpv4DefaultRoute();
- method public boolean hasIpv4DnsServer();
- method public boolean hasIpv6DefaultRoute();
- method public boolean hasIpv6DnsServer();
- method public boolean isIpv4Provisioned();
- method public boolean isIpv6Provisioned();
- method public boolean isProvisioned();
- method public boolean isReachable(@NonNull java.net.InetAddress);
- method public boolean removeDnsServer(@NonNull java.net.InetAddress);
- method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
- method public boolean removeRoute(@NonNull android.net.RouteInfo);
- method public void setCaptivePortalApiUrl(@Nullable android.net.Uri);
- method public void setCaptivePortalData(@Nullable android.net.CaptivePortalData);
- method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
- method public void setPrivateDnsServerName(@Nullable String);
- method public void setTcpBufferSizes(@Nullable String);
- method public void setUsePrivateDns(boolean);
- method public void setValidatedPrivateDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
- }
-
- 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 public int getNetId();
- method @NonNull public android.net.Network getPrivateDnsBypassingCopy();
- }
-
- public abstract class NetworkAgent {
- ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
- ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkScore, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
- method @Nullable public android.net.Network getNetwork();
- method public void markConnected();
- method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
- method public void onAutomaticReconnectDisabled();
- method public void onBandwidthUpdateRequested();
- method public void onNetworkCreated();
- method public void onNetworkDestroyed();
- method public void onNetworkUnwanted();
- method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
- method public void onQosCallbackUnregistered(int);
- method public void onRemoveKeepalivePacketFilter(int);
- method public void onSaveAcceptUnvalidated(boolean);
- method public void onSignalStrengthThresholdsUpdated(@NonNull int[]);
- method public void onStartSocketKeepalive(int, @NonNull java.time.Duration, @NonNull android.net.KeepalivePacketData);
- method public void onStopSocketKeepalive(int);
- method public void onValidationStatus(int, @Nullable android.net.Uri);
- method @NonNull public android.net.Network register();
- method public final void sendLinkProperties(@NonNull android.net.LinkProperties);
- method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
- method public final void sendNetworkScore(@NonNull android.net.NetworkScore);
- method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
- method public final void sendQosCallbackError(int, int);
- method public final void sendQosSessionAvailable(int, int, @NonNull android.net.QosSessionAttributes);
- method public final void sendQosSessionLost(int, int, int);
- method public final void sendSocketKeepaliveEvent(int, int);
- method @Deprecated public void setLegacySubtype(int, @NonNull String);
- method public void setLingerDuration(@NonNull java.time.Duration);
- method public void setTeardownDelayMillis(@IntRange(from=0, to=0x1388) int);
- method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
- method public void unregister();
- field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2
- field public static final int VALIDATION_STATUS_VALID = 1; // 0x1
- }
-
- public final class NetworkAgentConfig implements android.os.Parcelable {
- method public int describeContents();
- method public int getLegacyType();
- method @NonNull public String getLegacyTypeName();
- method public boolean isExplicitlySelected();
- method public boolean isPartialConnectivityAcceptable();
- method public boolean isUnvalidatedConnectivityAcceptable();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkAgentConfig> CREATOR;
- }
-
- public static final class NetworkAgentConfig.Builder {
- ctor public NetworkAgentConfig.Builder();
- method @NonNull public android.net.NetworkAgentConfig build();
- method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean);
- method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyExtraInfo(@NonNull String);
- method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubType(int);
- method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubTypeName(@NonNull String);
- method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyType(int);
- method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyTypeName(@NonNull String);
- method @NonNull public android.net.NetworkAgentConfig.Builder setNat64DetectionEnabled(boolean);
- method @NonNull public android.net.NetworkAgentConfig.Builder setPartialConnectivityAcceptable(boolean);
- method @NonNull public android.net.NetworkAgentConfig.Builder setProvisioningNotificationEnabled(boolean);
- method @NonNull public android.net.NetworkAgentConfig.Builder setUnvalidatedConnectivityAcceptable(boolean);
- }
-
- public final class NetworkCapabilities implements android.os.Parcelable {
- method @NonNull public int[] getAdministratorUids();
- method @Nullable public static String getCapabilityCarrierName(int);
- method @Nullable public String getSsid();
- method @NonNull public java.util.Set<java.lang.Integer> getSubscriptionIds();
- method @NonNull public int[] getTransportTypes();
- method public boolean isPrivateDnsBroken();
- method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
- field public static final int NET_CAPABILITY_BIP = 31; // 0x1f
- field public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; // 0x1c
- field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
- field public static final int NET_CAPABILITY_OEM_PRIVATE = 26; // 0x1a
- field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18
- field public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; // 0x1b
- field public static final int NET_CAPABILITY_VSIM = 30; // 0x1e
- }
-
- public static final class NetworkCapabilities.Builder {
- ctor public NetworkCapabilities.Builder();
- ctor public NetworkCapabilities.Builder(@NonNull android.net.NetworkCapabilities);
- method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int);
- method @NonNull public android.net.NetworkCapabilities.Builder addTransportType(int);
- method @NonNull public android.net.NetworkCapabilities build();
- method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int);
- method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]);
- method @NonNull public android.net.NetworkCapabilities.Builder setLinkDownstreamBandwidthKbps(int);
- method @NonNull public android.net.NetworkCapabilities.Builder setLinkUpstreamBandwidthKbps(int);
- method @NonNull public android.net.NetworkCapabilities.Builder setNetworkSpecifier(@Nullable android.net.NetworkSpecifier);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setOwnerUid(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorPackageName(@Nullable String);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorUid(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkCapabilities.Builder setSignalStrength(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
- method @NonNull public android.net.NetworkCapabilities.Builder setSubscriptionIds(@NonNull java.util.Set<java.lang.Integer>);
- method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
- method @NonNull public static android.net.NetworkCapabilities.Builder withoutDefaultCapabilities();
- }
-
- public class NetworkProvider {
- ctor public NetworkProvider(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void declareNetworkRequestUnfulfillable(@NonNull android.net.NetworkRequest);
- method public int getProviderId();
- method public void onNetworkRequestWithdrawn(@NonNull android.net.NetworkRequest);
- method public void onNetworkRequested(@NonNull android.net.NetworkRequest, @IntRange(from=0, to=99) int, int);
- method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void registerNetworkOffer(@NonNull android.net.NetworkScore, @NonNull android.net.NetworkCapabilities, @NonNull java.util.concurrent.Executor, @NonNull android.net.NetworkProvider.NetworkOfferCallback);
- method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void unregisterNetworkOffer(@NonNull android.net.NetworkProvider.NetworkOfferCallback);
- field public static final int ID_NONE = -1; // 0xffffffff
- }
-
- public static interface NetworkProvider.NetworkOfferCallback {
- method public void onNetworkNeeded(@NonNull android.net.NetworkRequest);
- method public void onNetworkUnneeded(@NonNull android.net.NetworkRequest);
- }
-
- public class NetworkReleasedException extends java.lang.Exception {
- }
-
- public class NetworkRequest implements android.os.Parcelable {
- method @Nullable public String getRequestorPackageName();
- method public int getRequestorUid();
- }
-
- public static class NetworkRequest.Builder {
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
- method @NonNull public android.net.NetworkRequest.Builder setSubscriptionIds(@NonNull java.util.Set<java.lang.Integer>);
- }
-
- public final class NetworkScore implements android.os.Parcelable {
- method public int describeContents();
- method public int getKeepConnectedReason();
- method public int getLegacyInt();
- method public boolean isExiting();
- method public boolean isTransportPrimary();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkScore> CREATOR;
- field public static final int KEEP_CONNECTED_FOR_HANDOVER = 1; // 0x1
- field public static final int KEEP_CONNECTED_NONE = 0; // 0x0
- }
-
- public static final class NetworkScore.Builder {
- ctor public NetworkScore.Builder();
- method @NonNull public android.net.NetworkScore build();
- method @NonNull public android.net.NetworkScore.Builder setExiting(boolean);
- method @NonNull public android.net.NetworkScore.Builder setKeepConnectedReason(int);
- method @NonNull public android.net.NetworkScore.Builder setLegacyInt(int);
- method @NonNull public android.net.NetworkScore.Builder setTransportPrimary(boolean);
- }
-
- public final class OemNetworkPreferences implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getNetworkPreferences();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.OemNetworkPreferences> CREATOR;
- field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID = 1; // 0x1
- field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK = 2; // 0x2
- field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY = 3; // 0x3
- field public static final int OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY = 4; // 0x4
- field public static final int OEM_NETWORK_PREFERENCE_UNINITIALIZED = 0; // 0x0
- }
-
- public static final class OemNetworkPreferences.Builder {
- ctor public OemNetworkPreferences.Builder();
- ctor public OemNetworkPreferences.Builder(@NonNull android.net.OemNetworkPreferences);
- method @NonNull public android.net.OemNetworkPreferences.Builder addNetworkPreference(@NonNull String, int);
- method @NonNull public android.net.OemNetworkPreferences build();
- method @NonNull public android.net.OemNetworkPreferences.Builder clearNetworkPreference(@NonNull String);
- }
-
- public abstract class QosCallback {
- ctor public QosCallback();
- method public void onError(@NonNull android.net.QosCallbackException);
- method public void onQosSessionAvailable(@NonNull android.net.QosSession, @NonNull android.net.QosSessionAttributes);
- method public void onQosSessionLost(@NonNull android.net.QosSession);
- }
-
- public static class QosCallback.QosCallbackRegistrationException extends java.lang.RuntimeException {
- }
-
- public final class QosCallbackException extends java.lang.Exception {
- }
-
- public abstract class QosFilter {
- method @NonNull public abstract android.net.Network getNetwork();
- method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int);
- method public abstract boolean matchesRemoteAddress(@NonNull java.net.InetAddress, int, int);
- }
-
- public final class QosSession implements android.os.Parcelable {
- ctor public QosSession(int, int);
- method public int describeContents();
- method public int getSessionId();
- method public int getSessionType();
- method public long getUniqueId();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
- field public static final int TYPE_EPS_BEARER = 1; // 0x1
- field public static final int TYPE_NR_BEARER = 2; // 0x2
- }
-
- public interface QosSessionAttributes {
- }
-
- public final class QosSocketInfo implements android.os.Parcelable {
- ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.Socket) throws java.io.IOException;
- method public int describeContents();
- method @NonNull public java.net.InetSocketAddress getLocalSocketAddress();
- method @NonNull public android.net.Network getNetwork();
- method @Nullable public java.net.InetSocketAddress getRemoteSocketAddress();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR;
- }
-
- public final class RouteInfo implements android.os.Parcelable {
- ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
- ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
- method public int getMtu();
- method public int getType();
- field public static final int RTN_THROW = 9; // 0x9
- field public static final int RTN_UNICAST = 1; // 0x1
- field public static final int RTN_UNREACHABLE = 7; // 0x7
- }
-
- public abstract class SocketKeepalive implements java.lang.AutoCloseable {
- field public static final int ERROR_NO_SUCH_SLOT = -33; // 0xffffffdf
- field public static final int SUCCESS = 0; // 0x0
- }
-
- public class SocketLocalAddressChangedException extends java.lang.Exception {
- }
-
- public class SocketNotBoundException extends java.lang.Exception {
- }
-
- public final class StaticIpConfiguration implements android.os.Parcelable {
- ctor public StaticIpConfiguration();
- ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
- method public void addDnsServer(@NonNull java.net.InetAddress);
- method public void clear();
- method public int describeContents();
- method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
- method @Nullable public String getDomains();
- method @Nullable public java.net.InetAddress getGateway();
- method @Nullable public android.net.LinkAddress getIpAddress();
- method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(@Nullable String);
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
- }
-
- public static final class StaticIpConfiguration.Builder {
- ctor public StaticIpConfiguration.Builder();
- method @NonNull public android.net.StaticIpConfiguration build();
- method @NonNull public android.net.StaticIpConfiguration.Builder setDnsServers(@NonNull Iterable<java.net.InetAddress>);
- method @NonNull public android.net.StaticIpConfiguration.Builder setDomains(@Nullable String);
- method @NonNull public android.net.StaticIpConfiguration.Builder setGateway(@Nullable java.net.InetAddress);
- method @NonNull public android.net.StaticIpConfiguration.Builder setIpAddress(@Nullable android.net.LinkAddress);
- }
-
- public final class TcpKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable {
- ctor public TcpKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[], int, int, int, int, int, int) throws android.net.InvalidPacketException;
- method public int describeContents();
- method public int getIpTos();
- method public int getIpTtl();
- method public int getTcpAck();
- method public int getTcpSeq();
- method public int getTcpWindow();
- method public int getTcpWindowScale();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TcpKeepalivePacketData> CREATOR;
- }
-
-}
-
-package android.net.apf {
-
- public final class ApfCapabilities implements android.os.Parcelable {
- ctor public ApfCapabilities(int, int, int);
- method public int describeContents();
- method public static boolean getApfDrop8023Frames();
- method @NonNull public static int[] getApfEtherTypeBlackList();
- method public boolean hasDataAccess();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
- field public final int apfPacketFormat;
- field public final int apfVersionSupported;
- field public final int maximumApfProgramSize;
- }
-
-}
-
diff --git a/packages/Connectivity/framework/api/system-lint-baseline.txt b/packages/Connectivity/framework/api/system-lint-baseline.txt
deleted file mode 100644
index 9a97707..0000000
--- a/packages/Connectivity/framework/api/system-lint-baseline.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Baseline format: 1.0
diff --git a/packages/Connectivity/framework/api/system-removed.txt b/packages/Connectivity/framework/api/system-removed.txt
deleted file mode 100644
index d802177..0000000
--- a/packages/Connectivity/framework/api/system-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/packages/Connectivity/framework/jarjar-rules.txt b/packages/Connectivity/framework/jarjar-rules.txt
deleted file mode 100644
index 2e5848c..0000000
--- a/packages/Connectivity/framework/jarjar-rules.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-rule com.android.net.module.util.** android.net.connectivity.framework.util.@1
-rule android.net.NetworkFactory* android.net.connectivity.framework.NetworkFactory@1
diff --git a/packages/Connectivity/framework/jni/android_net_NetworkUtils.cpp b/packages/Connectivity/framework/jni/android_net_NetworkUtils.cpp
deleted file mode 100644
index 7478b3e..0000000
--- a/packages/Connectivity/framework/jni/android_net_NetworkUtils.cpp
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#define LOG_TAG "NetworkUtils"
-
-#include <android/file_descriptor_jni.h>
-#include <android/multinetwork.h>
-#include <linux/filter.h>
-#include <linux/tcp.h>
-#include <netinet/in.h>
-#include <string.h>
-
-#include <DnsProxydProtocol.h> // NETID_USE_LOCAL_NAMESERVERS
-#include <nativehelper/JNIPlatformHelp.h>
-#include <utils/Log.h>
-
-#include "jni.h"
-
-#define NETUTILS_PKG_NAME "android/net/NetworkUtils"
-
-namespace android {
-
-constexpr int MAXPACKETSIZE = 8 * 1024;
-// FrameworkListener limits the size of commands to 4096 bytes.
-constexpr int MAXCMDSIZE = 4096;
-
-static volatile jclass class_Network = 0;
-static volatile jmethodID method_fromNetworkHandle = 0;
-
-static inline jclass FindClassOrDie(JNIEnv* env, const char* class_name) {
- jclass clazz = env->FindClass(class_name);
- LOG_ALWAYS_FATAL_IF(clazz == NULL, "Unable to find class %s", class_name);
- return clazz;
-}
-
-template <typename T>
-static inline T MakeGlobalRefOrDie(JNIEnv* env, T in) {
- jobject res = env->NewGlobalRef(in);
- LOG_ALWAYS_FATAL_IF(res == NULL, "Unable to create global reference.");
- return static_cast<T>(res);
-}
-
-static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
-{
- struct sock_filter filter_code[] = {
- // Reject all.
- BPF_STMT(BPF_RET | BPF_K, 0)
- };
- struct sock_fprog filter = {
- sizeof(filter_code) / sizeof(filter_code[0]),
- filter_code,
- };
-
- int fd = AFileDescriptor_getFd(env, javaFd);
- if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
- }
-}
-
-static void android_net_utils_detachBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
-{
- int optval_ignored = 0;
- int fd = AFileDescriptor_getFd(env, javaFd);
- if (setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, &optval_ignored, sizeof(optval_ignored)) !=
- 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(SO_DETACH_FILTER): %s", strerror(errno));
- }
-}
-
-static jboolean android_net_utils_bindProcessToNetworkHandle(JNIEnv *env, jobject thiz,
- jlong netHandle)
-{
- return (jboolean) !android_setprocnetwork(netHandle);
-}
-
-static jlong android_net_utils_getBoundNetworkHandleForProcess(JNIEnv *env, jobject thiz)
-{
- net_handle_t network;
- if (android_getprocnetwork(&network) != 0) {
- jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
- "android_getprocnetwork(): %s", strerror(errno));
- return NETWORK_UNSPECIFIED;
- }
- return (jlong) network;
-}
-
-static jboolean android_net_utils_bindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz,
- jint netId, jlong netHandle)
-{
- return (jboolean) !android_setprocdns(netHandle);
-}
-
-static jint android_net_utils_bindSocketToNetworkHandle(JNIEnv *env, jobject thiz, jobject javaFd,
- jlong netHandle) {
- return android_setsocknetwork(netHandle, AFileDescriptor_getFd(env, javaFd));
-}
-
-static bool checkLenAndCopy(JNIEnv* env, const jbyteArray& addr, int len, void* dst)
-{
- if (env->GetArrayLength(addr) != len) {
- return false;
- }
- env->GetByteArrayRegion(addr, 0, len, reinterpret_cast<jbyte*>(dst));
- return true;
-}
-
-static jobject android_net_utils_resNetworkQuery(JNIEnv *env, jobject thiz, jlong netHandle,
- jstring dname, jint ns_class, jint ns_type, jint flags) {
- const jsize javaCharsCount = env->GetStringLength(dname);
- const jsize byteCountUTF8 = env->GetStringUTFLength(dname);
-
- // Only allow dname which could be simply formatted to UTF8.
- // In native layer, res_mkquery would re-format the input char array to packet.
- char queryname[byteCountUTF8 + 1];
- memset(queryname, 0, (byteCountUTF8 + 1) * sizeof(char));
-
- env->GetStringUTFRegion(dname, 0, javaCharsCount, queryname);
- int fd = android_res_nquery(netHandle, queryname, ns_class, ns_type, flags);
-
- if (fd < 0) {
- jniThrowErrnoException(env, "resNetworkQuery", -fd);
- return nullptr;
- }
-
- return jniCreateFileDescriptor(env, fd);
-}
-
-static jobject android_net_utils_resNetworkSend(JNIEnv *env, jobject thiz, jlong netHandle,
- jbyteArray msg, jint msgLen, jint flags) {
- uint8_t data[MAXCMDSIZE];
-
- checkLenAndCopy(env, msg, msgLen, data);
- int fd = android_res_nsend(netHandle, data, msgLen, flags);
-
- if (fd < 0) {
- jniThrowErrnoException(env, "resNetworkSend", -fd);
- return nullptr;
- }
-
- return jniCreateFileDescriptor(env, fd);
-}
-
-static jobject android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) {
- int fd = AFileDescriptor_getFd(env, javaFd);
- int rcode;
- uint8_t buf[MAXPACKETSIZE] = {0};
-
- int res = android_res_nresult(fd, &rcode, buf, MAXPACKETSIZE);
- jniSetFileDescriptorOfFD(env, javaFd, -1);
- if (res < 0) {
- jniThrowErrnoException(env, "resNetworkResult", -res);
- return nullptr;
- }
-
- jbyteArray answer = env->NewByteArray(res);
- if (answer == nullptr) {
- jniThrowErrnoException(env, "resNetworkResult", ENOMEM);
- return nullptr;
- } else {
- env->SetByteArrayRegion(answer, 0, res, reinterpret_cast<jbyte*>(buf));
- }
-
- jclass class_DnsResponse = env->FindClass("android/net/DnsResolver$DnsResponse");
- jmethodID ctor = env->GetMethodID(class_DnsResponse, "<init>", "([BI)V");
-
- return env->NewObject(class_DnsResponse, ctor, answer, rcode);
-}
-
-static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) {
- int fd = AFileDescriptor_getFd(env, javaFd);
- android_res_cancel(fd);
- jniSetFileDescriptorOfFD(env, javaFd, -1);
-}
-
-static jobject android_net_utils_getDnsNetwork(JNIEnv *env, jobject thiz) {
- net_handle_t dnsNetHandle = NETWORK_UNSPECIFIED;
- if (int res = android_getprocdns(&dnsNetHandle) < 0) {
- jniThrowErrnoException(env, "getDnsNetwork", -res);
- return nullptr;
- }
-
- if (method_fromNetworkHandle == 0) {
- // This may be called multiple times concurrently but that is fine
- class_Network = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/net/Network"));
- method_fromNetworkHandle = env->GetStaticMethodID(class_Network, "fromNetworkHandle",
- "(J)Landroid/net/Network;");
- }
- return env->CallStaticObjectMethod(class_Network, method_fromNetworkHandle,
- static_cast<jlong>(dnsNetHandle));
-}
-
-static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) {
- if (javaFd == NULL) {
- jniThrowNullPointerException(env, NULL);
- return NULL;
- }
-
- int fd = AFileDescriptor_getFd(env, javaFd);
- struct tcp_repair_window trw = {};
- socklen_t size = sizeof(trw);
-
- // Obtain the parameters of the TCP repair window.
- int rc = getsockopt(fd, IPPROTO_TCP, TCP_REPAIR_WINDOW, &trw, &size);
- if (rc == -1) {
- jniThrowErrnoException(env, "getsockopt : TCP_REPAIR_WINDOW", errno);
- return NULL;
- }
-
- struct tcp_info tcpinfo = {};
- socklen_t tcpinfo_size = sizeof(tcp_info);
-
- // Obtain the window scale from the tcp info structure. This contains a scale factor that
- // should be applied to the window size.
- rc = getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcpinfo, &tcpinfo_size);
- if (rc == -1) {
- jniThrowErrnoException(env, "getsockopt : TCP_INFO", errno);
- return NULL;
- }
-
- jclass class_TcpRepairWindow = env->FindClass("android/net/TcpRepairWindow");
- jmethodID ctor = env->GetMethodID(class_TcpRepairWindow, "<init>", "(IIIIII)V");
-
- return env->NewObject(class_TcpRepairWindow, ctor, trw.snd_wl1, trw.snd_wnd, trw.max_window,
- trw.rcv_wnd, trw.rcv_wup, tcpinfo.tcpi_rcv_wscale);
-}
-
-// ----------------------------------------------------------------------------
-
-/*
- * JNI registration.
- */
-// clang-format off
-static const JNINativeMethod gNetworkUtilMethods[] = {
- /* name, signature, funcPtr */
- { "bindProcessToNetworkHandle", "(J)Z", (void*) android_net_utils_bindProcessToNetworkHandle },
- { "getBoundNetworkHandleForProcess", "()J", (void*) android_net_utils_getBoundNetworkHandleForProcess },
- { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
- { "bindSocketToNetworkHandle", "(Ljava/io/FileDescriptor;J)I", (void*) android_net_utils_bindSocketToNetworkHandle },
- { "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter },
- { "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter },
- { "getTcpRepairWindow", "(Ljava/io/FileDescriptor;)Landroid/net/TcpRepairWindow;", (void*) android_net_utils_getTcpRepairWindow },
- { "resNetworkSend", "(J[BII)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkSend },
- { "resNetworkQuery", "(JLjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery },
- { "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult },
- { "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel },
- { "getDnsNetwork", "()Landroid/net/Network;", (void*) android_net_utils_getDnsNetwork },
-};
-// clang-format on
-
-int register_android_net_NetworkUtils(JNIEnv* env)
-{
- return jniRegisterNativeMethods(env, NETUTILS_PKG_NAME, gNetworkUtilMethods,
- NELEM(gNetworkUtilMethods));
-}
-
-}; // namespace android
diff --git a/packages/Connectivity/framework/jni/onload.cpp b/packages/Connectivity/framework/jni/onload.cpp
deleted file mode 100644
index 435f434..0000000
--- a/packages/Connectivity/framework/jni/onload.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <nativehelper/JNIHelp.h>
-#include <log/log.h>
-
-namespace android {
-
-int register_android_net_NetworkUtils(JNIEnv* env);
-
-extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
- JNIEnv *env;
- if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
- ALOGE("GetEnv failed");
- return JNI_ERR;
- }
-
- if (register_android_net_NetworkUtils(env) < 0) {
- return JNI_ERR;
- }
-
- return JNI_VERSION_1_6;
-}
-
-};
\ No newline at end of file
diff --git a/packages/Connectivity/framework/lint-baseline.xml b/packages/Connectivity/framework/lint-baseline.xml
deleted file mode 100644
index df37ae8..0000000
--- a/packages/Connectivity/framework/lint-baseline.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `new android.net.ParseException`"
- errorLine1=" ParseException pe = new ParseException(e.reason, e.getCause());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/Connectivity/framework/src/android/net/DnsResolver.java"
- line="301"
- column="37"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback`"
- errorLine1=" protected class ActiveDataSubscriptionIdListener extends TelephonyCallback"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java"
- line="96"
- column="62"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener`"
- errorLine1=" implements TelephonyCallback.ActiveDataSubscriptionIdListener {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java"
- line="97"
- column="24"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#registerTelephonyCallback`"
- errorLine1=" ctx.getSystemService(TelephonyManager.class).registerTelephonyCallback("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java"
- line="126"
- column="54"/>
- </issue>
-
-</issues>
diff --git a/packages/Connectivity/framework/src/android/net/CaptivePortal.java b/packages/Connectivity/framework/src/android/net/CaptivePortal.java
deleted file mode 100644
index 4a7b601..0000000
--- a/packages/Connectivity/framework/src/android/net/CaptivePortal.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed urnder the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-
-/**
- * A class allowing apps handling the {@link ConnectivityManager#ACTION_CAPTIVE_PORTAL_SIGN_IN}
- * activity to indicate to the system different outcomes of captive portal sign in. This class is
- * passed as an extra named {@link ConnectivityManager#EXTRA_CAPTIVE_PORTAL} with the
- * {@code ACTION_CAPTIVE_PORTAL_SIGN_IN} activity.
- */
-public class CaptivePortal implements Parcelable {
- /**
- * Response code from the captive portal application, indicating that the portal was dismissed
- * and the network should be re-validated.
- * @see ICaptivePortal#appResponse(int)
- * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
- * @hide
- */
- @SystemApi
- public static final int APP_RETURN_DISMISSED = 0;
- /**
- * Response code from the captive portal application, indicating that the user did not login and
- * does not want to use the captive portal network.
- * @see ICaptivePortal#appResponse(int)
- * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
- * @hide
- */
- @SystemApi
- public static final int APP_RETURN_UNWANTED = 1;
- /**
- * Response code from the captive portal application, indicating that the user does not wish to
- * login but wants to use the captive portal network as-is.
- * @see ICaptivePortal#appResponse(int)
- * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
- * @hide
- */
- @SystemApi
- public static final int APP_RETURN_WANTED_AS_IS = 2;
- /** Event offset of request codes from captive portal application. */
- private static final int APP_REQUEST_BASE = 100;
- /**
- * Request code from the captive portal application, indicating that the network condition may
- * have changed and the network should be re-validated.
- * @see ICaptivePortal#appRequest(int)
- * @see android.net.INetworkMonitor#forceReevaluation(int)
- * @hide
- */
- @SystemApi
- public static final int APP_REQUEST_REEVALUATION_REQUIRED = APP_REQUEST_BASE + 0;
-
- private final IBinder mBinder;
-
- /** @hide */
- public CaptivePortal(@NonNull IBinder binder) {
- mBinder = binder;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeStrongBinder(mBinder);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<CaptivePortal> CREATOR
- = new Parcelable.Creator<CaptivePortal>() {
- @Override
- public CaptivePortal createFromParcel(Parcel in) {
- return new CaptivePortal(in.readStrongBinder());
- }
-
- @Override
- public CaptivePortal[] newArray(int size) {
- return new CaptivePortal[size];
- }
- };
-
- /**
- * Indicate to the system that the captive portal has been
- * dismissed. In response the framework will re-evaluate the network's
- * connectivity and might take further action thereafter.
- */
- public void reportCaptivePortalDismissed() {
- try {
- ICaptivePortal.Stub.asInterface(mBinder).appResponse(APP_RETURN_DISMISSED);
- } catch (RemoteException e) {
- }
- }
-
- /**
- * Indicate to the system that the user does not want to pursue signing in to the
- * captive portal and the system should continue to prefer other networks
- * without captive portals for use as the default active data network. The
- * system will not retest the network for a captive portal so as to avoid
- * disturbing the user with further sign in to network notifications.
- */
- public void ignoreNetwork() {
- try {
- ICaptivePortal.Stub.asInterface(mBinder).appResponse(APP_RETURN_UNWANTED);
- } catch (RemoteException e) {
- }
- }
-
- /**
- * Indicate to the system the user wants to use this network as is, even though
- * the captive portal is still in place. The system will treat the network
- * as if it did not have a captive portal when selecting the network to use
- * as the default active data network. This may result in this network
- * becoming the default active data network, which could disrupt network
- * connectivity for apps because the captive portal is still in place.
- * @hide
- */
- @SystemApi
- public void useNetwork() {
- try {
- ICaptivePortal.Stub.asInterface(mBinder).appResponse(APP_RETURN_WANTED_AS_IS);
- } catch (RemoteException e) {
- }
- }
-
- /**
- * Request that the system reevaluates the captive portal status.
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- public void reevaluateNetwork() {
- try {
- ICaptivePortal.Stub.asInterface(mBinder).appRequest(APP_REQUEST_REEVALUATION_REQUIRED);
- } catch (RemoteException e) {
- }
- }
-
- /**
- * Log a captive portal login event.
- * @param eventId one of the CAPTIVE_PORTAL_LOGIN_* constants in metrics_constants.proto.
- * @param packageName captive portal application package name.
- * @hide
- * @deprecated The event will not be logged in Android S and above. The
- * caller is migrating to statsd.
- */
- @Deprecated
- @SystemApi
- public void logEvent(int eventId, @NonNull String packageName) {
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/CaptivePortalData.java b/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
deleted file mode 100644
index 53aa1b9..0000000
--- a/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
+++ /dev/null
@@ -1,379 +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 android.net;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
-
-/**
- * Metadata sent by captive portals, see https://www.ietf.org/id/draft-ietf-capport-api-03.txt.
- * @hide
- */
-@SystemApi
-public final class CaptivePortalData implements Parcelable {
- private final long mRefreshTimeMillis;
- @Nullable
- private final Uri mUserPortalUrl;
- @Nullable
- private final Uri mVenueInfoUrl;
- private final boolean mIsSessionExtendable;
- private final long mByteLimit;
- private final long mExpiryTimeMillis;
- private final boolean mCaptive;
- private final String mVenueFriendlyName;
- private final int mVenueInfoUrlSource;
- private final int mUserPortalUrlSource;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = {"CAPTIVE_PORTAL_DATA_SOURCE_"}, value = {
- CAPTIVE_PORTAL_DATA_SOURCE_OTHER,
- CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT})
- public @interface CaptivePortalDataSource {}
-
- /**
- * Source of information: Other (default)
- */
- public static final int CAPTIVE_PORTAL_DATA_SOURCE_OTHER = 0;
-
- /**
- * Source of information: Wi-Fi Passpoint
- */
- public static final int CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT = 1;
-
- private CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl,
- boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive,
- CharSequence venueFriendlyName, int venueInfoUrlSource, int userPortalUrlSource) {
- mRefreshTimeMillis = refreshTimeMillis;
- mUserPortalUrl = userPortalUrl;
- mVenueInfoUrl = venueInfoUrl;
- mIsSessionExtendable = isSessionExtendable;
- mByteLimit = byteLimit;
- mExpiryTimeMillis = expiryTimeMillis;
- mCaptive = captive;
- mVenueFriendlyName = venueFriendlyName == null ? null : venueFriendlyName.toString();
- mVenueInfoUrlSource = venueInfoUrlSource;
- mUserPortalUrlSource = userPortalUrlSource;
- }
-
- private CaptivePortalData(Parcel p) {
- this(p.readLong(), p.readParcelable(null), p.readParcelable(null), p.readBoolean(),
- p.readLong(), p.readLong(), p.readBoolean(), p.readString(), p.readInt(),
- p.readInt());
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeLong(mRefreshTimeMillis);
- dest.writeParcelable(mUserPortalUrl, 0);
- dest.writeParcelable(mVenueInfoUrl, 0);
- dest.writeBoolean(mIsSessionExtendable);
- dest.writeLong(mByteLimit);
- dest.writeLong(mExpiryTimeMillis);
- dest.writeBoolean(mCaptive);
- dest.writeString(mVenueFriendlyName);
- dest.writeInt(mVenueInfoUrlSource);
- dest.writeInt(mUserPortalUrlSource);
- }
-
- /**
- * A builder to create new {@link CaptivePortalData}.
- */
- public static class Builder {
- private long mRefreshTime;
- private Uri mUserPortalUrl;
- private Uri mVenueInfoUrl;
- private boolean mIsSessionExtendable;
- private long mBytesRemaining = -1;
- private long mExpiryTime = -1;
- private boolean mCaptive;
- private CharSequence mVenueFriendlyName;
- private @CaptivePortalDataSource int mVenueInfoUrlSource = CAPTIVE_PORTAL_DATA_SOURCE_OTHER;
- private @CaptivePortalDataSource int mUserPortalUrlSource =
- CAPTIVE_PORTAL_DATA_SOURCE_OTHER;
-
- /**
- * Create an empty builder.
- */
- public Builder() {}
-
- /**
- * Create a builder copying all data from existing {@link CaptivePortalData}.
- */
- public Builder(@Nullable CaptivePortalData data) {
- if (data == null) return;
- setRefreshTime(data.mRefreshTimeMillis)
- .setUserPortalUrl(data.mUserPortalUrl, data.mUserPortalUrlSource)
- .setVenueInfoUrl(data.mVenueInfoUrl, data.mVenueInfoUrlSource)
- .setSessionExtendable(data.mIsSessionExtendable)
- .setBytesRemaining(data.mByteLimit)
- .setExpiryTime(data.mExpiryTimeMillis)
- .setCaptive(data.mCaptive)
- .setVenueFriendlyName(data.mVenueFriendlyName);
- }
-
- /**
- * Set the time at which data was last refreshed, as per {@link System#currentTimeMillis()}.
- */
- @NonNull
- public Builder setRefreshTime(long refreshTime) {
- mRefreshTime = refreshTime;
- return this;
- }
-
- /**
- * Set the URL to be used for users to login to the portal, if captive.
- */
- @NonNull
- public Builder setUserPortalUrl(@Nullable Uri userPortalUrl) {
- return setUserPortalUrl(userPortalUrl, CAPTIVE_PORTAL_DATA_SOURCE_OTHER);
- }
-
- /**
- * Set the URL to be used for users to login to the portal, if captive, and the source of
- * the data, see {@link CaptivePortalDataSource}
- */
- @NonNull
- public Builder setUserPortalUrl(@Nullable Uri userPortalUrl,
- @CaptivePortalDataSource int source) {
- mUserPortalUrl = userPortalUrl;
- mUserPortalUrlSource = source;
- return this;
- }
-
- /**
- * Set the URL that can be used by users to view information about the network venue.
- */
- @NonNull
- public Builder setVenueInfoUrl(@Nullable Uri venueInfoUrl) {
- return setVenueInfoUrl(venueInfoUrl, CAPTIVE_PORTAL_DATA_SOURCE_OTHER);
- }
-
- /**
- * Set the URL that can be used by users to view information about the network venue, and
- * the source of the data, see {@link CaptivePortalDataSource}
- */
- @NonNull
- public Builder setVenueInfoUrl(@Nullable Uri venueInfoUrl,
- @CaptivePortalDataSource int source) {
- mVenueInfoUrl = venueInfoUrl;
- mVenueInfoUrlSource = source;
- return this;
- }
-
- /**
- * Set whether the portal supports extending a user session on the portal URL page.
- */
- @NonNull
- public Builder setSessionExtendable(boolean sessionExtendable) {
- mIsSessionExtendable = sessionExtendable;
- return this;
- }
-
- /**
- * Set the number of bytes remaining on the network before the portal closes.
- */
- @NonNull
- public Builder setBytesRemaining(long bytesRemaining) {
- mBytesRemaining = bytesRemaining;
- return this;
- }
-
- /**
- * Set the time at the session will expire, as per {@link System#currentTimeMillis()}.
- */
- @NonNull
- public Builder setExpiryTime(long expiryTime) {
- mExpiryTime = expiryTime;
- return this;
- }
-
- /**
- * Set whether the network is captive (portal closed).
- */
- @NonNull
- public Builder setCaptive(boolean captive) {
- mCaptive = captive;
- return this;
- }
-
- /**
- * Set the venue friendly name.
- */
- @NonNull
- public Builder setVenueFriendlyName(@Nullable CharSequence venueFriendlyName) {
- mVenueFriendlyName = venueFriendlyName;
- return this;
- }
-
- /**
- * Create a new {@link CaptivePortalData}.
- */
- @NonNull
- public CaptivePortalData build() {
- return new CaptivePortalData(mRefreshTime, mUserPortalUrl, mVenueInfoUrl,
- mIsSessionExtendable, mBytesRemaining, mExpiryTime, mCaptive,
- mVenueFriendlyName, mVenueInfoUrlSource,
- mUserPortalUrlSource);
- }
- }
-
- /**
- * Get the time at which data was last refreshed, as per {@link System#currentTimeMillis()}.
- */
- public long getRefreshTimeMillis() {
- return mRefreshTimeMillis;
- }
-
- /**
- * Get the URL to be used for users to login to the portal, or extend their session if
- * {@link #isSessionExtendable()} is true.
- */
- @Nullable
- public Uri getUserPortalUrl() {
- return mUserPortalUrl;
- }
-
- /**
- * Get the URL that can be used by users to view information about the network venue.
- */
- @Nullable
- public Uri getVenueInfoUrl() {
- return mVenueInfoUrl;
- }
-
- /**
- * Indicates whether the user portal URL can be used to extend sessions, when the user is logged
- * in and the session has a time or byte limit.
- */
- public boolean isSessionExtendable() {
- return mIsSessionExtendable;
- }
-
- /**
- * Get the remaining bytes on the captive portal session, at the time {@link CaptivePortalData}
- * was refreshed. This may be different from the limit currently enforced by the portal.
- * @return The byte limit, or -1 if not set.
- */
- public long getByteLimit() {
- return mByteLimit;
- }
-
- /**
- * Get the time at the session will expire, as per {@link System#currentTimeMillis()}.
- * @return The expiry time, or -1 if unset.
- */
- public long getExpiryTimeMillis() {
- return mExpiryTimeMillis;
- }
-
- /**
- * Get whether the network is captive (portal closed).
- */
- public boolean isCaptive() {
- return mCaptive;
- }
-
- /**
- * Get the information source of the Venue URL
- * @return The source that the Venue URL was obtained from
- */
- public @CaptivePortalDataSource int getVenueInfoUrlSource() {
- return mVenueInfoUrlSource;
- }
-
- /**
- * Get the information source of the user portal URL
- * @return The source that the user portal URL was obtained from
- */
- public @CaptivePortalDataSource int getUserPortalUrlSource() {
- return mUserPortalUrlSource;
- }
-
- /**
- * Get the venue friendly name
- */
- @Nullable
- public CharSequence getVenueFriendlyName() {
- return mVenueFriendlyName;
- }
-
- @NonNull
- public static final Creator<CaptivePortalData> CREATOR = new Creator<CaptivePortalData>() {
- @Override
- public CaptivePortalData createFromParcel(Parcel source) {
- return new CaptivePortalData(source);
- }
-
- @Override
- public CaptivePortalData[] newArray(int size) {
- return new CaptivePortalData[size];
- }
- };
-
- @Override
- public int hashCode() {
- return Objects.hash(mRefreshTimeMillis, mUserPortalUrl, mVenueInfoUrl,
- mIsSessionExtendable, mByteLimit, mExpiryTimeMillis, mCaptive, mVenueFriendlyName,
- mVenueInfoUrlSource, mUserPortalUrlSource);
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (!(obj instanceof CaptivePortalData)) return false;
- final CaptivePortalData other = (CaptivePortalData) obj;
- return mRefreshTimeMillis == other.mRefreshTimeMillis
- && Objects.equals(mUserPortalUrl, other.mUserPortalUrl)
- && Objects.equals(mVenueInfoUrl, other.mVenueInfoUrl)
- && mIsSessionExtendable == other.mIsSessionExtendable
- && mByteLimit == other.mByteLimit
- && mExpiryTimeMillis == other.mExpiryTimeMillis
- && mCaptive == other.mCaptive
- && Objects.equals(mVenueFriendlyName, other.mVenueFriendlyName)
- && mVenueInfoUrlSource == other.mVenueInfoUrlSource
- && mUserPortalUrlSource == other.mUserPortalUrlSource;
- }
-
- @Override
- public String toString() {
- return "CaptivePortalData {"
- + "refreshTime: " + mRefreshTimeMillis
- + ", userPortalUrl: " + mUserPortalUrl
- + ", venueInfoUrl: " + mVenueInfoUrl
- + ", isSessionExtendable: " + mIsSessionExtendable
- + ", byteLimit: " + mByteLimit
- + ", expiryTime: " + mExpiryTimeMillis
- + ", captive: " + mCaptive
- + ", venueFriendlyName: " + mVenueFriendlyName
- + ", venueInfoUrlSource: " + mVenueInfoUrlSource
- + ", userPortalUrlSource: " + mUserPortalUrlSource
- + "}";
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectionInfo.aidl b/packages/Connectivity/framework/src/android/net/ConnectionInfo.aidl
deleted file mode 100644
index 07faf8b..0000000
--- a/packages/Connectivity/framework/src/android/net/ConnectionInfo.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-**
-** Copyright (C) 2018 The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.net;
-
-parcelable ConnectionInfo;
diff --git a/packages/Connectivity/framework/src/android/net/ConnectionInfo.java b/packages/Connectivity/framework/src/android/net/ConnectionInfo.java
deleted file mode 100644
index 4514a84..0000000
--- a/packages/Connectivity/framework/src/android/net/ConnectionInfo.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.UnknownHostException;
-
-/**
- * Describe a network connection including local and remote address/port of a connection and the
- * transport protocol.
- *
- * @hide
- */
-public final class ConnectionInfo implements Parcelable {
- public final int protocol;
- public final InetSocketAddress local;
- public final InetSocketAddress remote;
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public ConnectionInfo(int protocol, InetSocketAddress local, InetSocketAddress remote) {
- this.protocol = protocol;
- this.local = local;
- this.remote = remote;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(protocol);
- out.writeByteArray(local.getAddress().getAddress());
- out.writeInt(local.getPort());
- out.writeByteArray(remote.getAddress().getAddress());
- out.writeInt(remote.getPort());
- }
-
- public static final @android.annotation.NonNull Creator<ConnectionInfo> CREATOR = new Creator<ConnectionInfo>() {
- public ConnectionInfo createFromParcel(Parcel in) {
- int protocol = in.readInt();
- InetAddress localAddress;
- try {
- localAddress = InetAddress.getByAddress(in.createByteArray());
- } catch (UnknownHostException e) {
- throw new IllegalArgumentException("Invalid InetAddress");
- }
- int localPort = in.readInt();
- InetAddress remoteAddress;
- try {
- remoteAddress = InetAddress.getByAddress(in.createByteArray());
- } catch (UnknownHostException e) {
- throw new IllegalArgumentException("Invalid InetAddress");
- }
- int remotePort = in.readInt();
- InetSocketAddress local = new InetSocketAddress(localAddress, localPort);
- InetSocketAddress remote = new InetSocketAddress(remoteAddress, remotePort);
- return new ConnectionInfo(protocol, local, remote);
- }
-
- public ConnectionInfo[] newArray(int size) {
- return new ConnectionInfo[size];
- }
- };
-}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityAnnotations.java b/packages/Connectivity/framework/src/android/net/ConnectivityAnnotations.java
deleted file mode 100644
index eb1faa0..0000000
--- a/packages/Connectivity/framework/src/android/net/ConnectivityAnnotations.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Type annotations for constants used in the connectivity API surface.
- *
- * The annotations are maintained in a separate class so that it can be built as
- * a separate library that other modules can build against, as Typedef should not
- * be exposed as SystemApi.
- *
- * @hide
- */
-public final class ConnectivityAnnotations {
- private ConnectivityAnnotations() {}
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {
- ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER,
- ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY,
- ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE,
- })
- public @interface MultipathPreference {}
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = false, value = {
- ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED,
- ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED,
- ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED,
- })
- public @interface RestrictBackgroundStatus {}
-}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java
deleted file mode 100644
index 3598ebc..0000000
--- a/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java
+++ /dev/null
@@ -1,776 +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 android.net;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StringDef;
-import android.content.Context;
-import android.os.Binder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.PersistableBundle;
-import android.os.RemoteException;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.Executor;
-
-/**
- * Class that provides utilities for collecting network connectivity diagnostics information.
- * Connectivity information is made available through triggerable diagnostics tools and by listening
- * to System validations. Some diagnostics information may be permissions-restricted.
- *
- * <p>ConnectivityDiagnosticsManager is intended for use by applications offering network
- * connectivity on a user device. These tools will provide several mechanisms for these applications
- * to be alerted to network conditions as well as diagnose potential network issues themselves.
- *
- * <p>The primary responsibilities of this class are to:
- *
- * <ul>
- * <li>Allow permissioned applications to register and unregister callbacks for network event
- * notifications
- * <li>Invoke callbacks for network event notifications, including:
- * <ul>
- * <li>Network validations
- * <li>Data stalls
- * <li>Connectivity reports from applications
- * </ul>
- * </ul>
- */
-public class ConnectivityDiagnosticsManager {
- /** @hide */
- @VisibleForTesting
- public static final Map<ConnectivityDiagnosticsCallback, ConnectivityDiagnosticsBinder>
- sCallbacks = new ConcurrentHashMap<>();
-
- private final Context mContext;
- private final IConnectivityManager mService;
-
- /** @hide */
- public ConnectivityDiagnosticsManager(Context context, IConnectivityManager service) {
- mContext = Objects.requireNonNull(context, "missing context");
- mService = Objects.requireNonNull(service, "missing IConnectivityManager");
- }
-
- /** @hide */
- @VisibleForTesting
- public static boolean persistableBundleEquals(
- @Nullable PersistableBundle a, @Nullable PersistableBundle b) {
- if (a == b) return true;
- if (a == null || b == null) return false;
- if (!Objects.equals(a.keySet(), b.keySet())) return false;
- for (String key : a.keySet()) {
- if (!Objects.equals(a.get(key), b.get(key))) return false;
- }
- return true;
- }
-
- /** Class that includes connectivity information for a specific Network at a specific time. */
- public static final class ConnectivityReport implements Parcelable {
- /**
- * The overall status of the network is that it is invalid; it neither provides
- * connectivity nor has been exempted from validation.
- */
- public static final int NETWORK_VALIDATION_RESULT_INVALID = 0;
-
- /**
- * The overall status of the network is that it is valid, this may be because it provides
- * full Internet access (all probes succeeded), or because other properties of the network
- * caused probes not to be run.
- */
- // TODO: link to INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID
- public static final int NETWORK_VALIDATION_RESULT_VALID = 1;
-
- /**
- * The overall status of the network is that it provides partial connectivity; some
- * probed services succeeded but others failed.
- */
- // TODO: link to INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
- public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2;
-
- /**
- * Due to the properties of the network, validation was not performed.
- */
- public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3;
-
- /** @hide */
- @IntDef(
- prefix = {"NETWORK_VALIDATION_RESULT_"},
- value = {
- NETWORK_VALIDATION_RESULT_INVALID,
- NETWORK_VALIDATION_RESULT_VALID,
- NETWORK_VALIDATION_RESULT_PARTIALLY_VALID,
- NETWORK_VALIDATION_RESULT_SKIPPED
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface NetworkValidationResult {}
-
- /**
- * The overall validation result for the Network being reported on.
- *
- * <p>The possible values for this key are:
- * {@link #NETWORK_VALIDATION_RESULT_INVALID},
- * {@link #NETWORK_VALIDATION_RESULT_VALID},
- * {@link #NETWORK_VALIDATION_RESULT_PARTIALLY_VALID},
- * {@link #NETWORK_VALIDATION_RESULT_SKIPPED}.
- *
- * @see android.net.NetworkCapabilities#NET_CAPABILITY_VALIDATED
- */
- @NetworkValidationResult
- public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
-
- /** DNS probe. */
- // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS
- public static final int NETWORK_PROBE_DNS = 0x04;
-
- /** HTTP probe. */
- // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP
- public static final int NETWORK_PROBE_HTTP = 0x08;
-
- /** HTTPS probe. */
- // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS;
- public static final int NETWORK_PROBE_HTTPS = 0x10;
-
- /** Captive portal fallback probe. */
- // TODO: link to INetworkMonitor.NETWORK_VALIDATION_FALLBACK
- public static final int NETWORK_PROBE_FALLBACK = 0x20;
-
- /** Private DNS (DNS over TLS) probd. */
- // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS
- public static final int NETWORK_PROBE_PRIVATE_DNS = 0x40;
-
- /** @hide */
- @IntDef(
- prefix = {"NETWORK_PROBE_"},
- value = {
- NETWORK_PROBE_DNS,
- NETWORK_PROBE_HTTP,
- NETWORK_PROBE_HTTPS,
- NETWORK_PROBE_FALLBACK,
- NETWORK_PROBE_PRIVATE_DNS
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface NetworkProbe {}
-
- /**
- * A bitmask of network validation probes that succeeded.
- *
- * <p>The possible bits values reported by this key are:
- * {@link #NETWORK_PROBE_DNS},
- * {@link #NETWORK_PROBE_HTTP},
- * {@link #NETWORK_PROBE_HTTPS},
- * {@link #NETWORK_PROBE_FALLBACK},
- * {@link #NETWORK_PROBE_PRIVATE_DNS}.
- */
- @NetworkProbe
- public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK =
- "networkProbesSucceeded";
-
- /**
- * A bitmask of network validation probes that were attempted.
- *
- * <p>These probes may have failed or may be incomplete at the time of this report.
- *
- * <p>The possible bits values reported by this key are:
- * {@link #NETWORK_PROBE_DNS},
- * {@link #NETWORK_PROBE_HTTP},
- * {@link #NETWORK_PROBE_HTTPS},
- * {@link #NETWORK_PROBE_FALLBACK},
- * {@link #NETWORK_PROBE_PRIVATE_DNS}.
- */
- @NetworkProbe
- public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK =
- "networkProbesAttempted";
-
- /** @hide */
- @StringDef(prefix = {"KEY_"}, value = {
- KEY_NETWORK_VALIDATION_RESULT, KEY_NETWORK_PROBES_SUCCEEDED_BITMASK,
- KEY_NETWORK_PROBES_ATTEMPTED_BITMASK})
- @Retention(RetentionPolicy.SOURCE)
- public @interface ConnectivityReportBundleKeys {}
-
- /** The Network for which this ConnectivityReport applied */
- @NonNull private final Network mNetwork;
-
- /**
- * The timestamp for the report. The timestamp is taken from {@link
- * System#currentTimeMillis}.
- */
- private final long mReportTimestamp;
-
- /** LinkProperties available on the Network at the reported timestamp */
- @NonNull private final LinkProperties mLinkProperties;
-
- /** NetworkCapabilities available on the Network at the reported timestamp */
- @NonNull private final NetworkCapabilities mNetworkCapabilities;
-
- /** PersistableBundle that may contain additional info about the report */
- @NonNull private final PersistableBundle mAdditionalInfo;
-
- /**
- * Constructor for ConnectivityReport.
- *
- * <p>Apps should obtain instances through {@link
- * ConnectivityDiagnosticsCallback#onConnectivityReportAvailable} instead of instantiating
- * their own instances (unless for testing purposes).
- *
- * @param network The Network for which this ConnectivityReport applies
- * @param reportTimestamp The timestamp for the report
- * @param linkProperties The LinkProperties available on network at reportTimestamp
- * @param networkCapabilities The NetworkCapabilities available on network at
- * reportTimestamp
- * @param additionalInfo A PersistableBundle that may contain additional info about the
- * report
- */
- public ConnectivityReport(
- @NonNull Network network,
- long reportTimestamp,
- @NonNull LinkProperties linkProperties,
- @NonNull NetworkCapabilities networkCapabilities,
- @NonNull PersistableBundle additionalInfo) {
- mNetwork = network;
- mReportTimestamp = reportTimestamp;
- mLinkProperties = new LinkProperties(linkProperties);
- mNetworkCapabilities = new NetworkCapabilities(networkCapabilities);
- mAdditionalInfo = additionalInfo;
- }
-
- /**
- * Returns the Network for this ConnectivityReport.
- *
- * @return The Network for which this ConnectivityReport applied
- */
- @NonNull
- public Network getNetwork() {
- return mNetwork;
- }
-
- /**
- * Returns the epoch timestamp (milliseconds) for when this report was taken.
- *
- * @return The timestamp for the report. Taken from {@link System#currentTimeMillis}.
- */
- public long getReportTimestamp() {
- return mReportTimestamp;
- }
-
- /**
- * Returns the LinkProperties available when this report was taken.
- *
- * @return LinkProperties available on the Network at the reported timestamp
- */
- @NonNull
- public LinkProperties getLinkProperties() {
- return new LinkProperties(mLinkProperties);
- }
-
- /**
- * Returns the NetworkCapabilities when this report was taken.
- *
- * @return NetworkCapabilities available on the Network at the reported timestamp
- */
- @NonNull
- public NetworkCapabilities getNetworkCapabilities() {
- return new NetworkCapabilities(mNetworkCapabilities);
- }
-
- /**
- * Returns a PersistableBundle with additional info for this report.
- *
- * @return PersistableBundle that may contain additional info about the report
- */
- @NonNull
- public PersistableBundle getAdditionalInfo() {
- return new PersistableBundle(mAdditionalInfo);
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (this == o) return true;
- if (!(o instanceof ConnectivityReport)) return false;
- final ConnectivityReport that = (ConnectivityReport) o;
-
- // PersistableBundle is optimized to avoid unparcelling data unless fields are
- // referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over
- // {@link PersistableBundle#kindofEquals}.
- return mReportTimestamp == that.mReportTimestamp
- && mNetwork.equals(that.mNetwork)
- && mLinkProperties.equals(that.mLinkProperties)
- && mNetworkCapabilities.equals(that.mNetworkCapabilities)
- && persistableBundleEquals(mAdditionalInfo, that.mAdditionalInfo);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(
- mNetwork,
- mReportTimestamp,
- mLinkProperties,
- mNetworkCapabilities,
- mAdditionalInfo);
- }
-
- /** {@inheritDoc} */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeParcelable(mNetwork, flags);
- dest.writeLong(mReportTimestamp);
- dest.writeParcelable(mLinkProperties, flags);
- dest.writeParcelable(mNetworkCapabilities, flags);
- dest.writeParcelable(mAdditionalInfo, flags);
- }
-
- /** Implement the Parcelable interface */
- public static final @NonNull Creator<ConnectivityReport> CREATOR =
- new Creator<ConnectivityReport>() {
- public ConnectivityReport createFromParcel(Parcel in) {
- return new ConnectivityReport(
- in.readParcelable(null),
- in.readLong(),
- in.readParcelable(null),
- in.readParcelable(null),
- in.readParcelable(null));
- }
-
- public ConnectivityReport[] newArray(int size) {
- return new ConnectivityReport[size];
- }
- };
- }
-
- /** Class that includes information for a suspected data stall on a specific Network */
- public static final class DataStallReport implements Parcelable {
- /**
- * Indicates that the Data Stall was detected using DNS events.
- */
- public static final int DETECTION_METHOD_DNS_EVENTS = 1;
-
- /**
- * Indicates that the Data Stall was detected using TCP metrics.
- */
- public static final int DETECTION_METHOD_TCP_METRICS = 2;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(
- prefix = {"DETECTION_METHOD_"},
- value = {DETECTION_METHOD_DNS_EVENTS, DETECTION_METHOD_TCP_METRICS})
- public @interface DetectionMethod {}
-
- /**
- * This key represents the period in milliseconds over which other included TCP metrics
- * were measured.
- *
- * <p>This key will be included if the data stall detection method is
- * {@link #DETECTION_METHOD_TCP_METRICS}.
- *
- * <p>This value is an int.
- */
- public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS =
- "tcpMetricsCollectionPeriodMillis";
-
- /**
- * This key represents the fail rate of TCP packets when the suspected data stall was
- * detected.
- *
- * <p>This key will be included if the data stall detection method is
- * {@link #DETECTION_METHOD_TCP_METRICS}.
- *
- * <p>This value is an int percentage between 0 and 100.
- */
- public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate";
-
- /**
- * This key represents the consecutive number of DNS timeouts that have occurred.
- *
- * <p>The consecutive count will be reset any time a DNS response is received.
- *
- * <p>This key will be included if the data stall detection method is
- * {@link #DETECTION_METHOD_DNS_EVENTS}.
- *
- * <p>This value is an int.
- */
- public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts";
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @StringDef(prefix = {"KEY_"}, value = {
- KEY_TCP_PACKET_FAIL_RATE,
- KEY_DNS_CONSECUTIVE_TIMEOUTS
- })
- public @interface DataStallReportBundleKeys {}
-
- /** The Network for which this DataStallReport applied */
- @NonNull private final Network mNetwork;
-
- /**
- * The timestamp for the report. The timestamp is taken from {@link
- * System#currentTimeMillis}.
- */
- private long mReportTimestamp;
-
- /** A bitmask of the detection methods used to identify the suspected data stall */
- @DetectionMethod private final int mDetectionMethod;
-
- /** LinkProperties available on the Network at the reported timestamp */
- @NonNull private final LinkProperties mLinkProperties;
-
- /** NetworkCapabilities available on the Network at the reported timestamp */
- @NonNull private final NetworkCapabilities mNetworkCapabilities;
-
- /** PersistableBundle that may contain additional information on the suspected data stall */
- @NonNull private final PersistableBundle mStallDetails;
-
- /**
- * Constructor for DataStallReport.
- *
- * <p>Apps should obtain instances through {@link
- * ConnectivityDiagnosticsCallback#onDataStallSuspected} instead of instantiating their own
- * instances (unless for testing purposes).
- *
- * @param network The Network for which this DataStallReport applies
- * @param reportTimestamp The timestamp for the report
- * @param detectionMethod The detection method used to identify this data stall
- * @param linkProperties The LinkProperties available on network at reportTimestamp
- * @param networkCapabilities The NetworkCapabilities available on network at
- * reportTimestamp
- * @param stallDetails A PersistableBundle that may contain additional info about the report
- */
- public DataStallReport(
- @NonNull Network network,
- long reportTimestamp,
- @DetectionMethod int detectionMethod,
- @NonNull LinkProperties linkProperties,
- @NonNull NetworkCapabilities networkCapabilities,
- @NonNull PersistableBundle stallDetails) {
- mNetwork = network;
- mReportTimestamp = reportTimestamp;
- mDetectionMethod = detectionMethod;
- mLinkProperties = new LinkProperties(linkProperties);
- mNetworkCapabilities = new NetworkCapabilities(networkCapabilities);
- mStallDetails = stallDetails;
- }
-
- /**
- * Returns the Network for this DataStallReport.
- *
- * @return The Network for which this DataStallReport applied
- */
- @NonNull
- public Network getNetwork() {
- return mNetwork;
- }
-
- /**
- * Returns the epoch timestamp (milliseconds) for when this report was taken.
- *
- * @return The timestamp for the report. Taken from {@link System#currentTimeMillis}.
- */
- public long getReportTimestamp() {
- return mReportTimestamp;
- }
-
- /**
- * Returns the bitmask of detection methods used to identify this suspected data stall.
- *
- * @return The bitmask of detection methods used to identify the suspected data stall
- */
- public int getDetectionMethod() {
- return mDetectionMethod;
- }
-
- /**
- * Returns the LinkProperties available when this report was taken.
- *
- * @return LinkProperties available on the Network at the reported timestamp
- */
- @NonNull
- public LinkProperties getLinkProperties() {
- return new LinkProperties(mLinkProperties);
- }
-
- /**
- * Returns the NetworkCapabilities when this report was taken.
- *
- * @return NetworkCapabilities available on the Network at the reported timestamp
- */
- @NonNull
- public NetworkCapabilities getNetworkCapabilities() {
- return new NetworkCapabilities(mNetworkCapabilities);
- }
-
- /**
- * Returns a PersistableBundle with additional info for this report.
- *
- * <p>Gets a bundle with details about the suspected data stall including information
- * specific to the monitoring method that detected the data stall.
- *
- * @return PersistableBundle that may contain additional information on the suspected data
- * stall
- */
- @NonNull
- public PersistableBundle getStallDetails() {
- return new PersistableBundle(mStallDetails);
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (this == o) return true;
- if (!(o instanceof DataStallReport)) return false;
- final DataStallReport that = (DataStallReport) o;
-
- // PersistableBundle is optimized to avoid unparcelling data unless fields are
- // referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over
- // {@link PersistableBundle#kindofEquals}.
- return mReportTimestamp == that.mReportTimestamp
- && mDetectionMethod == that.mDetectionMethod
- && mNetwork.equals(that.mNetwork)
- && mLinkProperties.equals(that.mLinkProperties)
- && mNetworkCapabilities.equals(that.mNetworkCapabilities)
- && persistableBundleEquals(mStallDetails, that.mStallDetails);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(
- mNetwork,
- mReportTimestamp,
- mDetectionMethod,
- mLinkProperties,
- mNetworkCapabilities,
- mStallDetails);
- }
-
- /** {@inheritDoc} */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** {@inheritDoc} */
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeParcelable(mNetwork, flags);
- dest.writeLong(mReportTimestamp);
- dest.writeInt(mDetectionMethod);
- dest.writeParcelable(mLinkProperties, flags);
- dest.writeParcelable(mNetworkCapabilities, flags);
- dest.writeParcelable(mStallDetails, flags);
- }
-
- /** Implement the Parcelable interface */
- public static final @NonNull Creator<DataStallReport> CREATOR =
- new Creator<DataStallReport>() {
- public DataStallReport createFromParcel(Parcel in) {
- return new DataStallReport(
- in.readParcelable(null),
- in.readLong(),
- in.readInt(),
- in.readParcelable(null),
- in.readParcelable(null),
- in.readParcelable(null));
- }
-
- public DataStallReport[] newArray(int size) {
- return new DataStallReport[size];
- }
- };
- }
-
- /** @hide */
- @VisibleForTesting
- public static class ConnectivityDiagnosticsBinder
- extends IConnectivityDiagnosticsCallback.Stub {
- @NonNull private final ConnectivityDiagnosticsCallback mCb;
- @NonNull private final Executor mExecutor;
-
- /** @hide */
- @VisibleForTesting
- public ConnectivityDiagnosticsBinder(
- @NonNull ConnectivityDiagnosticsCallback cb, @NonNull Executor executor) {
- this.mCb = cb;
- this.mExecutor = executor;
- }
-
- /** @hide */
- @VisibleForTesting
- public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) {
- final long token = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> {
- mCb.onConnectivityReportAvailable(report);
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /** @hide */
- @VisibleForTesting
- public void onDataStallSuspected(@NonNull DataStallReport report) {
- final long token = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> {
- mCb.onDataStallSuspected(report);
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /** @hide */
- @VisibleForTesting
- public void onNetworkConnectivityReported(
- @NonNull Network network, boolean hasConnectivity) {
- final long token = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> {
- mCb.onNetworkConnectivityReported(network, hasConnectivity);
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- }
-
- /**
- * Abstract base class for Connectivity Diagnostics callbacks. Used for notifications about
- * network connectivity events. Must be extended by applications wanting notifications.
- */
- public abstract static class ConnectivityDiagnosticsCallback {
- /**
- * Called when the platform completes a data connectivity check. This will also be invoked
- * immediately upon registration for each network matching the request with the latest
- * report, if a report has already been generated for that network.
- *
- * <p>The Network specified in the ConnectivityReport may not be active any more when this
- * method is invoked.
- *
- * @param report The ConnectivityReport containing information about a connectivity check
- */
- public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) {}
-
- /**
- * Called when the platform suspects a data stall on some Network.
- *
- * <p>The Network specified in the DataStallReport may not be active any more when this
- * method is invoked.
- *
- * @param report The DataStallReport containing information about the suspected data stall
- */
- public void onDataStallSuspected(@NonNull DataStallReport report) {}
-
- /**
- * Called when any app reports connectivity to the System.
- *
- * @param network The Network for which connectivity has been reported
- * @param hasConnectivity The connectivity reported to the System
- */
- public void onNetworkConnectivityReported(
- @NonNull Network network, boolean hasConnectivity) {}
- }
-
- /**
- * Registers a ConnectivityDiagnosticsCallback with the System.
- *
- * <p>Only apps that offer network connectivity to the user should be registering callbacks.
- * These are the only apps whose callbacks will be invoked by the system. Apps considered to
- * meet these conditions include:
- *
- * <ul>
- * <li>Carrier apps with active subscriptions
- * <li>Active VPNs
- * <li>WiFi Suggesters
- * </ul>
- *
- * <p>Callbacks registered by apps not meeting the above criteria will not be invoked.
- *
- * <p>If a registering app loses its relevant permissions, any callbacks it registered will
- * silently stop receiving callbacks.
- *
- * <p>Each register() call <b>MUST</b> use a ConnectivityDiagnosticsCallback instance that is
- * not currently registered. If a ConnectivityDiagnosticsCallback instance is registered with
- * multiple NetworkRequests, an IllegalArgumentException will be thrown.
- *
- * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
- * number of outstanding requests to 100 per app (identified by their UID), shared with
- * callbacks in {@link ConnectivityManager}. Registering a callback with this method will count
- * toward this limit. If this limit is exceeded, an exception will be thrown. To avoid hitting
- * this issue and to conserve resources, make sure to unregister the callbacks with
- * {@link #unregisterConnectivityDiagnosticsCallback}.
- *
- * @param request The NetworkRequest that will be used to match with Networks for which
- * callbacks will be fired
- * @param e The Executor to be used for running the callback method invocations
- * @param callback The ConnectivityDiagnosticsCallback that the caller wants registered with the
- * System
- * @throws IllegalArgumentException if the same callback instance is registered with multiple
- * NetworkRequests
- * @throws RuntimeException if the app already has too many callbacks registered.
- */
- public void registerConnectivityDiagnosticsCallback(
- @NonNull NetworkRequest request,
- @NonNull Executor e,
- @NonNull ConnectivityDiagnosticsCallback callback) {
- final ConnectivityDiagnosticsBinder binder = new ConnectivityDiagnosticsBinder(callback, e);
- if (sCallbacks.putIfAbsent(callback, binder) != null) {
- throw new IllegalArgumentException("Callback is currently registered");
- }
-
- try {
- mService.registerConnectivityDiagnosticsCallback(
- binder, request, mContext.getOpPackageName());
- } catch (RemoteException exception) {
- exception.rethrowFromSystemServer();
- }
- }
-
- /**
- * Unregisters a ConnectivityDiagnosticsCallback with the System.
- *
- * <p>If the given callback is not currently registered with the System, this operation will be
- * a no-op.
- *
- * @param callback The ConnectivityDiagnosticsCallback to be unregistered from the System.
- */
- public void unregisterConnectivityDiagnosticsCallback(
- @NonNull ConnectivityDiagnosticsCallback callback) {
- // unconditionally removing from sCallbacks prevents race conditions here, since remove() is
- // atomic.
- final ConnectivityDiagnosticsBinder binder = sCallbacks.remove(callback);
- if (binder == null) return;
-
- try {
- mService.unregisterConnectivityDiagnosticsCallback(binder);
- } catch (RemoteException exception) {
- exception.rethrowFromSystemServer();
- }
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java b/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java
deleted file mode 100644
index a2e218d..0000000
--- a/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.SystemApi;
-import android.app.SystemServiceRegistry;
-import android.content.Context;
-
-/**
- * Class for performing registration for all core connectivity services.
- *
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public final class ConnectivityFrameworkInitializer {
- private ConnectivityFrameworkInitializer() {}
-
- /**
- * Called by {@link SystemServiceRegistry}'s static initializer and registers all core
- * connectivity services to {@link Context}, so that {@link Context#getSystemService} can
- * return them.
- *
- * @throws IllegalStateException if this is called anywhere besides
- * {@link SystemServiceRegistry}.
- */
- public static void registerServiceWrappers() {
- // registerContextAwareService will throw if this is called outside of SystemServiceRegistry
- // initialization.
- SystemServiceRegistry.registerContextAwareService(
- Context.CONNECTIVITY_SERVICE,
- ConnectivityManager.class,
- (context, serviceBinder) -> {
- IConnectivityManager icm = IConnectivityManager.Stub.asInterface(serviceBinder);
- return new ConnectivityManager(context, icm);
- }
- );
-
- SystemServiceRegistry.registerContextAwareService(
- Context.CONNECTIVITY_DIAGNOSTICS_SERVICE,
- ConnectivityDiagnosticsManager.class,
- (context) -> {
- final ConnectivityManager cm = context.getSystemService(
- ConnectivityManager.class);
- return cm.createDiagnosticsManager();
- }
- );
-
- SystemServiceRegistry.registerContextAwareService(
- Context.TEST_NETWORK_SERVICE,
- TestNetworkManager.class,
- context -> {
- final ConnectivityManager cm = context.getSystemService(
- ConnectivityManager.class);
- return cm.startOrGetTestNetworkManager();
- }
- );
-
- SystemServiceRegistry.registerContextAwareService(
- DnsResolverServiceManager.DNS_RESOLVER_SERVICE,
- DnsResolverServiceManager.class,
- (context, serviceBinder) -> new DnsResolverServiceManager(serviceBinder)
- );
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
deleted file mode 100644
index 93455bc..0000000
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ /dev/null
@@ -1,5459 +0,0 @@
-/*
- * 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.
- */
-package android.net;
-
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
-import static android.net.NetworkRequest.Type.LISTEN;
-import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST;
-import static android.net.NetworkRequest.Type.REQUEST;
-import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
-import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
-import static android.net.QosCallback.QosCallbackRegistrationException;
-
-import android.annotation.CallbackExecutor;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.annotation.SystemService;
-import android.app.PendingIntent;
-import android.app.admin.DevicePolicyManager;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.net.ConnectivityAnnotations.MultipathPreference;
-import android.net.ConnectivityAnnotations.RestrictBackgroundStatus;
-import android.net.ConnectivityDiagnosticsManager.DataStallReport.DetectionMethod;
-import android.net.IpSecManager.UdpEncapsulationSocket;
-import android.net.SocketKeepalive.Callback;
-import android.net.TetheringManager.StartTetheringCallback;
-import android.net.TetheringManager.TetheringEventCallback;
-import android.net.TetheringManager.TetheringRequest;
-import android.net.wifi.WifiNetworkSuggestion;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Build.VERSION_CODES;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.ParcelFileDescriptor;
-import android.os.PersistableBundle;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.ServiceSpecificException;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.Range;
-import android.util.SparseIntArray;
-
-import com.android.internal.annotations.GuardedBy;
-
-import libcore.net.event.NetworkEventDispatcher;
-
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.RejectedExecutionException;
-
-/**
- * Class that answers queries about the state of network connectivity. It also
- * notifies applications when network connectivity changes.
- * <p>
- * The primary responsibilities of this class are to:
- * <ol>
- * <li>Monitor network connections (Wi-Fi, GPRS, UMTS, etc.)</li>
- * <li>Send broadcast intents when network connectivity changes</li>
- * <li>Attempt to "fail over" to another network when connectivity to a network
- * is lost</li>
- * <li>Provide an API that allows applications to query the coarse-grained or fine-grained
- * state of the available networks</li>
- * <li>Provide an API that allows applications to request and select networks for their data
- * traffic</li>
- * </ol>
- */
-@SystemService(Context.CONNECTIVITY_SERVICE)
-public class ConnectivityManager {
- private static final String TAG = "ConnectivityManager";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
- /**
- * A change in network connectivity has occurred. A default connection has either
- * been established or lost. The NetworkInfo for the affected network is
- * sent as an extra; it should be consulted to see what kind of
- * connectivity event occurred.
- * <p/>
- * Apps targeting Android 7.0 (API level 24) and higher do not receive this
- * broadcast if they declare the broadcast receiver in their manifest. Apps
- * will still receive broadcasts if they register their
- * {@link android.content.BroadcastReceiver} with
- * {@link android.content.Context#registerReceiver Context.registerReceiver()}
- * and that context is still valid.
- * <p/>
- * If this is a connection that was the result of failing over from a
- * disconnected network, then the FAILOVER_CONNECTION boolean extra is
- * set to true.
- * <p/>
- * For a loss of connectivity, if the connectivity manager is attempting
- * to connect (or has already connected) to another network, the
- * NetworkInfo for the new network is also passed as an extra. This lets
- * any receivers of the broadcast know that they should not necessarily
- * tell the user that no data traffic will be possible. Instead, the
- * receiver should expect another broadcast soon, indicating either that
- * the failover attempt succeeded (and so there is still overall data
- * connectivity), or that the failover attempt failed, meaning that all
- * connectivity has been lost.
- * <p/>
- * For a disconnect event, the boolean extra EXTRA_NO_CONNECTIVITY
- * is set to {@code true} if there are no connected networks at all.
- *
- * @deprecated apps should use the more versatile {@link #requestNetwork},
- * {@link #registerNetworkCallback} or {@link #registerDefaultNetworkCallback}
- * functions instead for faster and more detailed updates about the network
- * changes they care about.
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @Deprecated
- public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
-
- /**
- * The device has connected to a network that has presented a captive
- * portal, which is blocking Internet connectivity. The user was presented
- * with a notification that network sign in is required,
- * and the user invoked the notification's action indicating they
- * desire to sign in to the network. Apps handling this activity should
- * facilitate signing in to the network. This action includes a
- * {@link Network} typed extra called {@link #EXTRA_NETWORK} that represents
- * the network presenting the captive portal; all communication with the
- * captive portal must be done using this {@code Network} object.
- * <p/>
- * This activity includes a {@link CaptivePortal} extra named
- * {@link #EXTRA_CAPTIVE_PORTAL} that can be used to indicate different
- * outcomes of the captive portal sign in to the system:
- * <ul>
- * <li> When the app handling this action believes the user has signed in to
- * the network and the captive portal has been dismissed, the app should
- * call {@link CaptivePortal#reportCaptivePortalDismissed} so the system can
- * reevaluate the network. If reevaluation finds the network no longer
- * subject to a captive portal, the network may become the default active
- * data network.</li>
- * <li> When the app handling this action believes the user explicitly wants
- * to ignore the captive portal and the network, the app should call
- * {@link CaptivePortal#ignoreNetwork}. </li>
- * </ul>
- */
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL";
-
- /**
- * The lookup key for a {@link NetworkInfo} object. Retrieve with
- * {@link android.content.Intent#getParcelableExtra(String)}.
- *
- * @deprecated The {@link NetworkInfo} object is deprecated, as many of its properties
- * can't accurately represent modern network characteristics.
- * Please obtain information about networks from the {@link NetworkCapabilities}
- * or {@link LinkProperties} objects instead.
- */
- @Deprecated
- public static final String EXTRA_NETWORK_INFO = "networkInfo";
-
- /**
- * Network type which triggered a {@link #CONNECTIVITY_ACTION} broadcast.
- *
- * @see android.content.Intent#getIntExtra(String, int)
- * @deprecated The network type is not rich enough to represent the characteristics
- * of modern networks. Please use {@link NetworkCapabilities} instead,
- * in particular the transports.
- */
- @Deprecated
- public static final String EXTRA_NETWORK_TYPE = "networkType";
-
- /**
- * The lookup key for a boolean that indicates whether a connect event
- * is for a network to which the connectivity manager was failing over
- * following a disconnect on another network.
- * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
- *
- * @deprecated See {@link NetworkInfo}.
- */
- @Deprecated
- public static final String EXTRA_IS_FAILOVER = "isFailover";
- /**
- * The lookup key for a {@link NetworkInfo} object. This is supplied when
- * there is another network that it may be possible to connect to. Retrieve with
- * {@link android.content.Intent#getParcelableExtra(String)}.
- *
- * @deprecated See {@link NetworkInfo}.
- */
- @Deprecated
- public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
- /**
- * The lookup key for a boolean that indicates whether there is a
- * complete lack of connectivity, i.e., no network is available.
- * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
- */
- public static final String EXTRA_NO_CONNECTIVITY = "noConnectivity";
- /**
- * The lookup key for a string that indicates why an attempt to connect
- * to a network failed. The string has no particular structure. It is
- * intended to be used in notifications presented to users. Retrieve
- * it with {@link android.content.Intent#getStringExtra(String)}.
- */
- public static final String EXTRA_REASON = "reason";
- /**
- * The lookup key for a string that provides optionally supplied
- * extra information about the network state. The information
- * may be passed up from the lower networking layers, and its
- * meaning may be specific to a particular network type. Retrieve
- * it with {@link android.content.Intent#getStringExtra(String)}.
- *
- * @deprecated See {@link NetworkInfo#getExtraInfo()}.
- */
- @Deprecated
- public static final String EXTRA_EXTRA_INFO = "extraInfo";
- /**
- * The lookup key for an int that provides information about
- * our connection to the internet at large. 0 indicates no connection,
- * 100 indicates a great connection. Retrieve it with
- * {@link android.content.Intent#getIntExtra(String, int)}.
- * {@hide}
- */
- public static final String EXTRA_INET_CONDITION = "inetCondition";
- /**
- * The lookup key for a {@link CaptivePortal} object included with the
- * {@link #ACTION_CAPTIVE_PORTAL_SIGN_IN} intent. The {@code CaptivePortal}
- * object can be used to either indicate to the system that the captive
- * portal has been dismissed or that the user does not want to pursue
- * signing in to captive portal. Retrieve it with
- * {@link android.content.Intent#getParcelableExtra(String)}.
- */
- public static final String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
-
- /**
- * Key for passing a URL to the captive portal login activity.
- */
- public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
-
- /**
- * Key for passing a {@link android.net.captiveportal.CaptivePortalProbeSpec} to the captive
- * portal login activity.
- * {@hide}
- */
- @SystemApi
- public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC =
- "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
-
- /**
- * Key for passing a user agent string to the captive portal login activity.
- * {@hide}
- */
- @SystemApi
- public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT =
- "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
-
- /**
- * Broadcast action to indicate the change of data activity status
- * (idle or active) on a network in a recent period.
- * The network becomes active when data transmission is started, or
- * idle if there is no data transmission for a period of time.
- * {@hide}
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_DATA_ACTIVITY_CHANGE =
- "android.net.conn.DATA_ACTIVITY_CHANGE";
- /**
- * The lookup key for an enum that indicates the network device type on which this data activity
- * change happens.
- * {@hide}
- */
- public static final String EXTRA_DEVICE_TYPE = "deviceType";
- /**
- * The lookup key for a boolean that indicates the device is active or not. {@code true} means
- * it is actively sending or receiving data and {@code false} means it is idle.
- * {@hide}
- */
- public static final String EXTRA_IS_ACTIVE = "isActive";
- /**
- * The lookup key for a long that contains the timestamp (nanos) of the radio state change.
- * {@hide}
- */
- public static final String EXTRA_REALTIME_NS = "tsNanos";
-
- /**
- * Broadcast Action: The setting for background data usage has changed
- * values. Use {@link #getBackgroundDataSetting()} to get the current value.
- * <p>
- * If an application uses the network in the background, it should listen
- * for this broadcast and stop using the background data if the value is
- * {@code false}.
- * <p>
- *
- * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH}, availability
- * of background data depends on several combined factors, and
- * this broadcast is no longer sent. Instead, when background
- * data is unavailable, {@link #getActiveNetworkInfo()} will now
- * appear disconnected. During first boot after a platform
- * upgrade, this broadcast will be sent once if
- * {@link #getBackgroundDataSetting()} was {@code false} before
- * the upgrade.
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @Deprecated
- public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED =
- "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
-
- /**
- * Broadcast Action: The network connection may not be good
- * uses {@code ConnectivityManager.EXTRA_INET_CONDITION} and
- * {@code ConnectivityManager.EXTRA_NETWORK_INFO} to specify
- * the network and it's condition.
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @UnsupportedAppUsage
- public static final String INET_CONDITION_ACTION =
- "android.net.conn.INET_CONDITION_ACTION";
-
- /**
- * Broadcast Action: A tetherable connection has come or gone.
- * Uses {@code ConnectivityManager.EXTRA_AVAILABLE_TETHER},
- * {@code ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY},
- * {@code ConnectivityManager.EXTRA_ACTIVE_TETHER}, and
- * {@code ConnectivityManager.EXTRA_ERRORED_TETHER} to indicate
- * the current state of tethering. Each include a list of
- * interface names in that state (may be empty).
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final String ACTION_TETHER_STATE_CHANGED =
- TetheringManager.ACTION_TETHER_STATE_CHANGED;
-
- /**
- * @hide
- * gives a String[] listing all the interfaces configured for
- * tethering and currently available for tethering.
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final String EXTRA_AVAILABLE_TETHER = TetheringManager.EXTRA_AVAILABLE_TETHER;
-
- /**
- * @hide
- * gives a String[] listing all the interfaces currently in local-only
- * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding)
- */
- public static final String EXTRA_ACTIVE_LOCAL_ONLY = TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
-
- /**
- * @hide
- * gives a String[] listing all the interfaces currently tethered
- * (ie, has DHCPv4 support and packets potentially forwarded/NATed)
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final String EXTRA_ACTIVE_TETHER = TetheringManager.EXTRA_ACTIVE_TETHER;
-
- /**
- * @hide
- * gives a String[] listing all the interfaces we tried to tether and
- * failed. Use {@link #getLastTetherError} to find the error code
- * for any interfaces listed here.
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final String EXTRA_ERRORED_TETHER = TetheringManager.EXTRA_ERRORED_TETHER;
-
- /**
- * Broadcast Action: The captive portal tracker has finished its test.
- * Sent only while running Setup Wizard, in lieu of showing a user
- * notification.
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CAPTIVE_PORTAL_TEST_COMPLETED =
- "android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED";
- /**
- * The lookup key for a boolean that indicates whether a captive portal was detected.
- * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
- * @hide
- */
- public static final String EXTRA_IS_CAPTIVE_PORTAL = "captivePortal";
-
- /**
- * Action used to display a dialog that asks the user whether to connect to a network that is
- * not validated. This intent is used to start the dialog in settings via startActivity.
- *
- * This action includes a {@link Network} typed extra which is called
- * {@link ConnectivityManager#EXTRA_NETWORK} that represents the network which is unvalidated.
- *
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public static final String ACTION_PROMPT_UNVALIDATED = "android.net.action.PROMPT_UNVALIDATED";
-
- /**
- * Action used to display a dialog that asks the user whether to avoid a network that is no
- * longer validated. This intent is used to start the dialog in settings via startActivity.
- *
- * This action includes a {@link Network} typed extra which is called
- * {@link ConnectivityManager#EXTRA_NETWORK} that represents the network which is no longer
- * validated.
- *
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public static final String ACTION_PROMPT_LOST_VALIDATION =
- "android.net.action.PROMPT_LOST_VALIDATION";
-
- /**
- * Action used to display a dialog that asks the user whether to stay connected to a network
- * that has not validated. This intent is used to start the dialog in settings via
- * startActivity.
- *
- * This action includes a {@link Network} typed extra which is called
- * {@link ConnectivityManager#EXTRA_NETWORK} that represents the network which has partial
- * connectivity.
- *
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY =
- "android.net.action.PROMPT_PARTIAL_CONNECTIVITY";
-
- /**
- * Clear DNS Cache Action: This is broadcast when networks have changed and old
- * DNS entries should be cleared.
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final String ACTION_CLEAR_DNS_CACHE = "android.net.action.CLEAR_DNS_CACHE";
-
- /**
- * Invalid tethering type.
- * @see #startTethering(int, boolean, OnStartTetheringCallback)
- * @hide
- */
- public static final int TETHERING_INVALID = TetheringManager.TETHERING_INVALID;
-
- /**
- * Wifi tethering type.
- * @see #startTethering(int, boolean, OnStartTetheringCallback)
- * @hide
- */
- @SystemApi
- public static final int TETHERING_WIFI = 0;
-
- /**
- * USB tethering type.
- * @see #startTethering(int, boolean, OnStartTetheringCallback)
- * @hide
- */
- @SystemApi
- public static final int TETHERING_USB = 1;
-
- /**
- * Bluetooth tethering type.
- * @see #startTethering(int, boolean, OnStartTetheringCallback)
- * @hide
- */
- @SystemApi
- public static final int TETHERING_BLUETOOTH = 2;
-
- /**
- * Wifi P2p tethering type.
- * Wifi P2p tethering is set through events automatically, and don't
- * need to start from #startTethering(int, boolean, OnStartTetheringCallback).
- * @hide
- */
- public static final int TETHERING_WIFI_P2P = TetheringManager.TETHERING_WIFI_P2P;
-
- /**
- * Extra used for communicating with the TetherService. Includes the type of tethering to
- * enable if any.
- * @hide
- */
- public static final String EXTRA_ADD_TETHER_TYPE = TetheringConstants.EXTRA_ADD_TETHER_TYPE;
-
- /**
- * Extra used for communicating with the TetherService. Includes the type of tethering for
- * which to cancel provisioning.
- * @hide
- */
- public static final String EXTRA_REM_TETHER_TYPE = TetheringConstants.EXTRA_REM_TETHER_TYPE;
-
- /**
- * Extra used for communicating with the TetherService. True to schedule a recheck of tether
- * provisioning.
- * @hide
- */
- public static final String EXTRA_SET_ALARM = TetheringConstants.EXTRA_SET_ALARM;
-
- /**
- * Tells the TetherService to run a provision check now.
- * @hide
- */
- public static final String EXTRA_RUN_PROVISION = TetheringConstants.EXTRA_RUN_PROVISION;
-
- /**
- * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver}
- * which will receive provisioning results. Can be left empty.
- * @hide
- */
- public static final String EXTRA_PROVISION_CALLBACK =
- TetheringConstants.EXTRA_PROVISION_CALLBACK;
-
- /**
- * The absence of a connection type.
- * @hide
- */
- @SystemApi
- public static final int TYPE_NONE = -1;
-
- /**
- * A Mobile data connection. Devices may support more than one.
- *
- * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
- * appropriate network. {@see NetworkCapabilities} for supported transports.
- */
- @Deprecated
- public static final int TYPE_MOBILE = 0;
-
- /**
- * A WIFI data connection. Devices may support more than one.
- *
- * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
- * appropriate network. {@see NetworkCapabilities} for supported transports.
- */
- @Deprecated
- public static final int TYPE_WIFI = 1;
-
- /**
- * An MMS-specific Mobile data connection. This network type may use the
- * same network interface as {@link #TYPE_MOBILE} or it may use a different
- * one. This is used by applications needing to talk to the carrier's
- * Multimedia Messaging Service servers.
- *
- * @deprecated Applications should instead use {@link NetworkCapabilities#hasCapability} or
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
- * provides the {@link NetworkCapabilities#NET_CAPABILITY_MMS} capability.
- */
- @Deprecated
- public static final int TYPE_MOBILE_MMS = 2;
-
- /**
- * A SUPL-specific Mobile data connection. This network type may use the
- * same network interface as {@link #TYPE_MOBILE} or it may use a different
- * one. This is used by applications needing to talk to the carrier's
- * Secure User Plane Location servers for help locating the device.
- *
- * @deprecated Applications should instead use {@link NetworkCapabilities#hasCapability} or
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
- * provides the {@link NetworkCapabilities#NET_CAPABILITY_SUPL} capability.
- */
- @Deprecated
- public static final int TYPE_MOBILE_SUPL = 3;
-
- /**
- * A DUN-specific Mobile data connection. This network type may use the
- * same network interface as {@link #TYPE_MOBILE} or it may use a different
- * one. This is sometimes by the system when setting up an upstream connection
- * for tethering so that the carrier is aware of DUN traffic.
- *
- * @deprecated Applications should instead use {@link NetworkCapabilities#hasCapability} or
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
- * provides the {@link NetworkCapabilities#NET_CAPABILITY_DUN} capability.
- */
- @Deprecated
- public static final int TYPE_MOBILE_DUN = 4;
-
- /**
- * A High Priority Mobile data connection. This network type uses the
- * same network interface as {@link #TYPE_MOBILE} but the routing setup
- * is different.
- *
- * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
- * appropriate network. {@see NetworkCapabilities} for supported transports.
- */
- @Deprecated
- public static final int TYPE_MOBILE_HIPRI = 5;
-
- /**
- * A WiMAX data connection.
- *
- * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
- * appropriate network. {@see NetworkCapabilities} for supported transports.
- */
- @Deprecated
- public static final int TYPE_WIMAX = 6;
-
- /**
- * A Bluetooth data connection.
- *
- * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
- * appropriate network. {@see NetworkCapabilities} for supported transports.
- */
- @Deprecated
- public static final int TYPE_BLUETOOTH = 7;
-
- /**
- * Fake data connection. This should not be used on shipping devices.
- * @deprecated This is not used any more.
- */
- @Deprecated
- public static final int TYPE_DUMMY = 8;
-
- /**
- * An Ethernet data connection.
- *
- * @deprecated Applications should instead use {@link NetworkCapabilities#hasTransport} or
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request an
- * appropriate network. {@see NetworkCapabilities} for supported transports.
- */
- @Deprecated
- public static final int TYPE_ETHERNET = 9;
-
- /**
- * Over the air Administration.
- * @deprecated Use {@link NetworkCapabilities} instead.
- * {@hide}
- */
- @Deprecated
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
- public static final int TYPE_MOBILE_FOTA = 10;
-
- /**
- * IP Multimedia Subsystem.
- * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_IMS} instead.
- * {@hide}
- */
- @Deprecated
- @UnsupportedAppUsage
- public static final int TYPE_MOBILE_IMS = 11;
-
- /**
- * Carrier Branded Services.
- * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_CBS} instead.
- * {@hide}
- */
- @Deprecated
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
- public static final int TYPE_MOBILE_CBS = 12;
-
- /**
- * A Wi-Fi p2p connection. Only requesting processes will have access to
- * the peers connected.
- * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_WIFI_P2P} instead.
- * {@hide}
- */
- @Deprecated
- @SystemApi
- public static final int TYPE_WIFI_P2P = 13;
-
- /**
- * The network to use for initially attaching to the network
- * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_IA} instead.
- * {@hide}
- */
- @Deprecated
- @UnsupportedAppUsage
- public static final int TYPE_MOBILE_IA = 14;
-
- /**
- * Emergency PDN connection for emergency services. This
- * may include IMS and MMS in emergency situations.
- * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_EIMS} instead.
- * {@hide}
- */
- @Deprecated
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
- public static final int TYPE_MOBILE_EMERGENCY = 15;
-
- /**
- * The network that uses proxy to achieve connectivity.
- * @deprecated Use {@link NetworkCapabilities} instead.
- * {@hide}
- */
- @Deprecated
- @SystemApi
- public static final int TYPE_PROXY = 16;
-
- /**
- * A virtual network using one or more native bearers.
- * It may or may not be providing security services.
- * @deprecated Applications should use {@link NetworkCapabilities#TRANSPORT_VPN} instead.
- */
- @Deprecated
- public static final int TYPE_VPN = 17;
-
- /**
- * A network that is exclusively meant to be used for testing
- *
- * @deprecated Use {@link NetworkCapabilities} instead.
- * @hide
- */
- @Deprecated
- public static final int TYPE_TEST = 18; // TODO: Remove this once NetworkTypes are unused.
-
- /**
- * @deprecated Use {@link NetworkCapabilities} instead.
- * @hide
- */
- @Deprecated
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "TYPE_" }, value = {
- TYPE_NONE,
- TYPE_MOBILE,
- TYPE_WIFI,
- TYPE_MOBILE_MMS,
- TYPE_MOBILE_SUPL,
- TYPE_MOBILE_DUN,
- TYPE_MOBILE_HIPRI,
- TYPE_WIMAX,
- TYPE_BLUETOOTH,
- TYPE_DUMMY,
- TYPE_ETHERNET,
- TYPE_MOBILE_FOTA,
- TYPE_MOBILE_IMS,
- TYPE_MOBILE_CBS,
- TYPE_WIFI_P2P,
- TYPE_MOBILE_IA,
- TYPE_MOBILE_EMERGENCY,
- TYPE_PROXY,
- TYPE_VPN,
- TYPE_TEST
- })
- public @interface LegacyNetworkType {}
-
- // Deprecated constants for return values of startUsingNetworkFeature. They used to live
- // in com.android.internal.telephony.PhoneConstants until they were made inaccessible.
- private static final int DEPRECATED_PHONE_CONSTANT_APN_ALREADY_ACTIVE = 0;
- private static final int DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED = 1;
- private static final int DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED = 3;
-
- /** {@hide} */
- public static final int MAX_RADIO_TYPE = TYPE_TEST;
-
- /** {@hide} */
- public static final int MAX_NETWORK_TYPE = TYPE_TEST;
-
- private static final int MIN_NETWORK_TYPE = TYPE_MOBILE;
-
- /**
- * If you want to set the default network preference,you can directly
- * change the networkAttributes array in framework's config.xml.
- *
- * @deprecated Since we support so many more networks now, the single
- * network default network preference can't really express
- * the hierarchy. Instead, the default is defined by the
- * networkAttributes in config.xml. You can determine
- * the current value by calling {@link #getNetworkPreference()}
- * from an App.
- */
- @Deprecated
- public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;
-
- /**
- * @hide
- */
- public static final int REQUEST_ID_UNSET = 0;
-
- /**
- * Static unique request used as a tombstone for NetworkCallbacks that have been unregistered.
- * This allows to distinguish when unregistering NetworkCallbacks those that were never
- * registered from those that were already unregistered.
- * @hide
- */
- private static final NetworkRequest ALREADY_UNREGISTERED =
- new NetworkRequest.Builder().clearCapabilities().build();
-
- /**
- * A NetID indicating no Network is selected.
- * Keep in sync with bionic/libc/dns/include/resolv_netid.h
- * @hide
- */
- public static final int NETID_UNSET = 0;
-
- /**
- * Flag to indicate that an app is not subject to any restrictions that could result in its
- * network access blocked.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_REASON_NONE = 0;
-
- /**
- * Flag to indicate that an app is subject to Battery saver restrictions that would
- * result in its network access being blocked.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_REASON_BATTERY_SAVER = 1 << 0;
-
- /**
- * Flag to indicate that an app is subject to Doze restrictions that would
- * result in its network access being blocked.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_REASON_DOZE = 1 << 1;
-
- /**
- * Flag to indicate that an app is subject to App Standby restrictions that would
- * result in its network access being blocked.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_REASON_APP_STANDBY = 1 << 2;
-
- /**
- * Flag to indicate that an app is subject to Restricted mode restrictions that would
- * result in its network access being blocked.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_REASON_RESTRICTED_MODE = 1 << 3;
-
- /**
- * Flag to indicate that an app is blocked because it is subject to an always-on VPN but the VPN
- * is not currently connected.
- *
- * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean)
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_REASON_LOCKDOWN_VPN = 1 << 4;
-
- /**
- * Flag to indicate that an app is subject to Data saver restrictions that would
- * result in its metered network access being blocked.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_METERED_REASON_DATA_SAVER = 1 << 16;
-
- /**
- * Flag to indicate that an app is subject to user restrictions that would
- * result in its metered network access being blocked.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 1 << 17;
-
- /**
- * Flag to indicate that an app is subject to Device admin restrictions that would
- * result in its metered network access being blocked.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 1 << 18;
-
- /**
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, prefix = {"BLOCKED_"}, value = {
- BLOCKED_REASON_NONE,
- BLOCKED_REASON_BATTERY_SAVER,
- BLOCKED_REASON_DOZE,
- BLOCKED_REASON_APP_STANDBY,
- BLOCKED_REASON_RESTRICTED_MODE,
- BLOCKED_REASON_LOCKDOWN_VPN,
- BLOCKED_METERED_REASON_DATA_SAVER,
- BLOCKED_METERED_REASON_USER_RESTRICTED,
- BLOCKED_METERED_REASON_ADMIN_DISABLED,
- })
- public @interface BlockedReason {}
-
- /**
- * Set of blocked reasons that are only applicable on metered networks.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_METERED_REASON_MASK = 0xffff0000;
-
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
- private final IConnectivityManager mService;
-
- /**
- * A kludge to facilitate static access where a Context pointer isn't available, like in the
- * case of the static set/getProcessDefaultNetwork methods and from the Network class.
- * TODO: Remove this after deprecating the static methods in favor of non-static methods or
- * methods that take a Context argument.
- */
- private static ConnectivityManager sInstance;
-
- private final Context mContext;
-
- private final TetheringManager mTetheringManager;
-
- /**
- * Tests if a given integer represents a valid network type.
- * @param networkType the type to be tested
- * @return a boolean. {@code true} if the type is valid, else {@code false}
- * @deprecated All APIs accepting a network type are deprecated. There should be no need to
- * validate a network type.
- */
- @Deprecated
- public static boolean isNetworkTypeValid(int networkType) {
- return MIN_NETWORK_TYPE <= networkType && networkType <= MAX_NETWORK_TYPE;
- }
-
- /**
- * Returns a non-localized string representing a given network type.
- * ONLY used for debugging output.
- * @param type the type needing naming
- * @return a String for the given type, or a string version of the type ("87")
- * if no name is known.
- * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead.
- * {@hide}
- */
- @Deprecated
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static String getNetworkTypeName(int type) {
- switch (type) {
- case TYPE_NONE:
- return "NONE";
- case TYPE_MOBILE:
- return "MOBILE";
- case TYPE_WIFI:
- return "WIFI";
- case TYPE_MOBILE_MMS:
- return "MOBILE_MMS";
- case TYPE_MOBILE_SUPL:
- return "MOBILE_SUPL";
- case TYPE_MOBILE_DUN:
- return "MOBILE_DUN";
- case TYPE_MOBILE_HIPRI:
- return "MOBILE_HIPRI";
- case TYPE_WIMAX:
- return "WIMAX";
- case TYPE_BLUETOOTH:
- return "BLUETOOTH";
- case TYPE_DUMMY:
- return "DUMMY";
- case TYPE_ETHERNET:
- return "ETHERNET";
- case TYPE_MOBILE_FOTA:
- return "MOBILE_FOTA";
- case TYPE_MOBILE_IMS:
- return "MOBILE_IMS";
- case TYPE_MOBILE_CBS:
- return "MOBILE_CBS";
- case TYPE_WIFI_P2P:
- return "WIFI_P2P";
- case TYPE_MOBILE_IA:
- return "MOBILE_IA";
- case TYPE_MOBILE_EMERGENCY:
- return "MOBILE_EMERGENCY";
- case TYPE_PROXY:
- return "PROXY";
- case TYPE_VPN:
- return "VPN";
- default:
- return Integer.toString(type);
- }
- }
-
- /**
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public void systemReady() {
- try {
- mService.systemReady();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Checks if a given type uses the cellular data connection.
- * This should be replaced in the future by a network property.
- * @param networkType the type to check
- * @return a boolean - {@code true} if uses cellular network, else {@code false}
- * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead.
- * {@hide}
- */
- @Deprecated
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
- public static boolean isNetworkTypeMobile(int networkType) {
- switch (networkType) {
- case TYPE_MOBILE:
- case TYPE_MOBILE_MMS:
- case TYPE_MOBILE_SUPL:
- case TYPE_MOBILE_DUN:
- case TYPE_MOBILE_HIPRI:
- case TYPE_MOBILE_FOTA:
- case TYPE_MOBILE_IMS:
- case TYPE_MOBILE_CBS:
- case TYPE_MOBILE_IA:
- case TYPE_MOBILE_EMERGENCY:
- return true;
- default:
- return false;
- }
- }
-
- /**
- * Checks if the given network type is backed by a Wi-Fi radio.
- *
- * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead.
- * @hide
- */
- @Deprecated
- public static boolean isNetworkTypeWifi(int networkType) {
- switch (networkType) {
- case TYPE_WIFI:
- case TYPE_WIFI_P2P:
- return true;
- default:
- return false;
- }
- }
-
- /**
- * Preference for {@link #setNetworkPreferenceForUser(UserHandle, int, Executor, Runnable)}.
- * Specify that the traffic for this user should by follow the default rules.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0;
-
- /**
- * Preference for {@link #setNetworkPreferenceForUser(UserHandle, int, Executor, Runnable)}.
- * Specify that the traffic for this user should by default go on a network with
- * {@link NetworkCapabilities#NET_CAPABILITY_ENTERPRISE}, and on the system default network
- * if no such network is available.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- PROFILE_NETWORK_PREFERENCE_DEFAULT,
- PROFILE_NETWORK_PREFERENCE_ENTERPRISE
- })
- public @interface ProfileNetworkPreference {
- }
-
- /**
- * Specifies the preferred network type. When the device has more
- * than one type available the preferred network type will be used.
- *
- * @param preference the network type to prefer over all others. It is
- * unspecified what happens to the old preferred network in the
- * overall ordering.
- * @deprecated Functionality has been removed as it no longer makes sense,
- * with many more than two networks - we'd need an array to express
- * preference. Instead we use dynamic network properties of
- * the networks to describe their precedence.
- */
- @Deprecated
- public void setNetworkPreference(int preference) {
- }
-
- /**
- * Retrieves the current preferred network type.
- *
- * @return an integer representing the preferred network type
- *
- * @deprecated Functionality has been removed as it no longer makes sense,
- * with many more than two networks - we'd need an array to express
- * preference. Instead we use dynamic network properties of
- * the networks to describe their precedence.
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public int getNetworkPreference() {
- return TYPE_NONE;
- }
-
- /**
- * Returns details about the currently active default data network. When
- * connected, this network is the default route for outgoing connections.
- * You should always check {@link NetworkInfo#isConnected()} before initiating
- * network traffic. This may return {@code null} when there is no default
- * network.
- * Note that if the default network is a VPN, this method will return the
- * NetworkInfo for one of its underlying networks instead, or null if the
- * VPN agent did not specify any. Apps interested in learning about VPNs
- * should use {@link #getNetworkInfo(android.net.Network)} instead.
- *
- * @return a {@link NetworkInfo} object for the current default network
- * or {@code null} if no default network is currently active
- * @deprecated See {@link NetworkInfo}.
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @Nullable
- public NetworkInfo getActiveNetworkInfo() {
- try {
- return mService.getActiveNetworkInfo();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns a {@link Network} object corresponding to the currently active
- * default data network. In the event that the current active default data
- * network disconnects, the returned {@code Network} object will no longer
- * be usable. This will return {@code null} when there is no default
- * network.
- *
- * @return a {@link Network} object for the current default network or
- * {@code null} if no default network is currently active
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @Nullable
- public Network getActiveNetwork() {
- try {
- return mService.getActiveNetwork();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns a {@link Network} object corresponding to the currently active
- * default data network for a specific UID. In the event that the default data
- * network disconnects, the returned {@code Network} object will no longer
- * be usable. This will return {@code null} when there is no default
- * network for the UID.
- *
- * @return a {@link Network} object for the current default network for the
- * given UID or {@code null} if no default network is currently active
- *
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- @Nullable
- public Network getActiveNetworkForUid(int uid) {
- return getActiveNetworkForUid(uid, false);
- }
-
- /** {@hide} */
- public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) {
- try {
- return mService.getActiveNetworkForUid(uid, ignoreBlocked);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Adds or removes a requirement for given UID ranges to use the VPN.
- *
- * If set to {@code true}, informs the system that the UIDs in the specified ranges must not
- * have any connectivity except if a VPN is connected and applies to the UIDs, or if the UIDs
- * otherwise have permission to bypass the VPN (e.g., because they have the
- * {@link android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS} permission, or when
- * using a socket protected by a method such as {@link VpnService#protect(DatagramSocket)}. If
- * set to {@code false}, a previously-added restriction is removed.
- * <p>
- * Each of the UID ranges specified by this method is added and removed as is, and no processing
- * is performed on the ranges to de-duplicate, merge, split, or intersect them. In order to
- * remove a previously-added range, the exact range must be removed as is.
- * <p>
- * The changes are applied asynchronously and may not have been applied by the time the method
- * returns. Apps will be notified about any changes that apply to them via
- * {@link NetworkCallback#onBlockedStatusChanged} callbacks called after the changes take
- * effect.
- * <p>
- * This method should be called only by the VPN code.
- *
- * @param ranges the UID ranges to restrict
- * @param requireVpn whether the specified UID ranges must use a VPN
- *
- * @hide
- */
- @RequiresPermission(anyOf = {
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_STACK,
- android.Manifest.permission.NETWORK_SETTINGS})
- @SystemApi(client = MODULE_LIBRARIES)
- public void setRequireVpnForUids(boolean requireVpn,
- @NonNull Collection<Range<Integer>> ranges) {
- Objects.requireNonNull(ranges);
- // The Range class is not parcelable. Convert to UidRange, which is what is used internally.
- // This method is not necessarily expected to be used outside the system server, so
- // parceling may not be necessary, but it could be used out-of-process, e.g., by the network
- // stack process, or by tests.
- UidRange[] rangesArray = new UidRange[ranges.size()];
- int index = 0;
- for (Range<Integer> range : ranges) {
- rangesArray[index++] = new UidRange(range.getLower(), range.getUpper());
- }
- try {
- mService.setRequireVpnForUids(requireVpn, rangesArray);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Informs ConnectivityService of whether the legacy lockdown VPN, as implemented by
- * LockdownVpnTracker, is in use. This is deprecated for new devices starting from Android 12
- * but is still supported for backwards compatibility.
- * <p>
- * This type of VPN is assumed always to use the system default network, and must always declare
- * exactly one underlying network, which is the network that was the default when the VPN
- * connected.
- * <p>
- * Calling this method with {@code true} enables legacy behaviour, specifically:
- * <ul>
- * <li>Any VPN that applies to userId 0 behaves specially with respect to deprecated
- * {@link #CONNECTIVITY_ACTION} broadcasts. Any such broadcasts will have the state in the
- * {@link #EXTRA_NETWORK_INFO} replaced by state of the VPN network. Also, any time the VPN
- * connects, a {@link #CONNECTIVITY_ACTION} broadcast will be sent for the network
- * underlying the VPN.</li>
- * <li>Deprecated APIs that return {@link NetworkInfo} objects will have their state
- * similarly replaced by the VPN network state.</li>
- * <li>Information on current network interfaces passed to NetworkStatsService will not
- * include any VPN interfaces.</li>
- * </ul>
- *
- * @param enabled whether legacy lockdown VPN is enabled or disabled
- *
- * @hide
- */
- @RequiresPermission(anyOf = {
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_STACK,
- android.Manifest.permission.NETWORK_SETTINGS})
- @SystemApi(client = MODULE_LIBRARIES)
- public void setLegacyLockdownVpnEnabled(boolean enabled) {
- try {
- mService.setLegacyLockdownVpnEnabled(enabled);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns details about the currently active default data network
- * for a given uid. This is for internal use only to avoid spying
- * other apps.
- *
- * @return a {@link NetworkInfo} object for the current default network
- * for the given uid or {@code null} if no default network is
- * available for the specified uid.
- *
- * {@hide}
- */
- @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public NetworkInfo getActiveNetworkInfoForUid(int uid) {
- return getActiveNetworkInfoForUid(uid, false);
- }
-
- /** {@hide} */
- public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) {
- try {
- return mService.getActiveNetworkInfoForUid(uid, ignoreBlocked);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns connection status information about a particular
- * network type.
- *
- * @param networkType integer specifying which networkType in
- * which you're interested.
- * @return a {@link NetworkInfo} object for the requested
- * network type or {@code null} if the type is not
- * supported by the device. If {@code networkType} is
- * TYPE_VPN and a VPN is active for the calling app,
- * then this method will try to return one of the
- * underlying networks for the VPN or null if the
- * VPN agent didn't specify any.
- *
- * @deprecated This method does not support multiple connected networks
- * of the same type. Use {@link #getAllNetworks} and
- * {@link #getNetworkInfo(android.net.Network)} instead.
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @Nullable
- public NetworkInfo getNetworkInfo(int networkType) {
- try {
- return mService.getNetworkInfo(networkType);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns connection status information about a particular
- * Network.
- *
- * @param network {@link Network} specifying which network
- * in which you're interested.
- * @return a {@link NetworkInfo} object for the requested
- * network or {@code null} if the {@code Network}
- * is not valid.
- * @deprecated See {@link NetworkInfo}.
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @Nullable
- public NetworkInfo getNetworkInfo(@Nullable Network network) {
- return getNetworkInfoForUid(network, Process.myUid(), false);
- }
-
- /** {@hide} */
- public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) {
- try {
- return mService.getNetworkInfoForUid(network, uid, ignoreBlocked);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns connection status information about all network
- * types supported by the device.
- *
- * @return an array of {@link NetworkInfo} objects. Check each
- * {@link NetworkInfo#getType} for which type each applies.
- *
- * @deprecated This method does not support multiple connected networks
- * of the same type. Use {@link #getAllNetworks} and
- * {@link #getNetworkInfo(android.net.Network)} instead.
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @NonNull
- public NetworkInfo[] getAllNetworkInfo() {
- try {
- return mService.getAllNetworkInfo();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Return a list of {@link NetworkStateSnapshot}s, one for each network that is currently
- * connected.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- @RequiresPermission(anyOf = {
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_STACK,
- android.Manifest.permission.NETWORK_SETTINGS})
- @NonNull
- public List<NetworkStateSnapshot> getAllNetworkStateSnapshots() {
- try {
- return mService.getAllNetworkStateSnapshots();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns the {@link Network} object currently serving a given type, or
- * null if the given type is not connected.
- *
- * @hide
- * @deprecated This method does not support multiple connected networks
- * of the same type. Use {@link #getAllNetworks} and
- * {@link #getNetworkInfo(android.net.Network)} instead.
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @UnsupportedAppUsage
- public Network getNetworkForType(int networkType) {
- try {
- return mService.getNetworkForType(networkType);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns an array of all {@link Network} currently tracked by the
- * framework.
- *
- * @deprecated This method does not provide any notification of network state changes, forcing
- * apps to call it repeatedly. This is inefficient and prone to race conditions.
- * Apps should use methods such as
- * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} instead.
- * Apps that desire to obtain information about networks that do not apply to them
- * can use {@link NetworkRequest.Builder#setIncludeOtherUidNetworks}.
- *
- * @return an array of {@link Network} objects.
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @NonNull
- @Deprecated
- public Network[] getAllNetworks() {
- try {
- return mService.getAllNetworks();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns an array of {@link NetworkCapabilities} objects, representing
- * the Networks that applications run by the given user will use by default.
- * @hide
- */
- @UnsupportedAppUsage
- public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
- try {
- return mService.getDefaultNetworkCapabilitiesForUser(
- userId, mContext.getOpPackageName(), getAttributionTag());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns the IP information for the current default network.
- *
- * @return a {@link LinkProperties} object describing the IP info
- * for the current default network, or {@code null} if there
- * is no current default network.
- *
- * {@hide}
- * @deprecated please use {@link #getLinkProperties(Network)} on the return
- * value of {@link #getActiveNetwork()} instead. In particular,
- * this method will return non-null LinkProperties even if the
- * app is blocked by policy from using this network.
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 109783091)
- public LinkProperties getActiveLinkProperties() {
- try {
- return mService.getActiveLinkProperties();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns the IP information for a given network type.
- *
- * @param networkType the network type of interest.
- * @return a {@link LinkProperties} object describing the IP info
- * for the given networkType, or {@code null} if there is
- * no current default network.
- *
- * {@hide}
- * @deprecated This method does not support multiple connected networks
- * of the same type. Use {@link #getAllNetworks},
- * {@link #getNetworkInfo(android.net.Network)}, and
- * {@link #getLinkProperties(android.net.Network)} instead.
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
- public LinkProperties getLinkProperties(int networkType) {
- try {
- return mService.getLinkPropertiesForType(networkType);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Get the {@link LinkProperties} for the given {@link Network}. This
- * will return {@code null} if the network is unknown.
- *
- * @param network The {@link Network} object identifying the network in question.
- * @return The {@link LinkProperties} for the network, or {@code null}.
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @Nullable
- public LinkProperties getLinkProperties(@Nullable Network network) {
- try {
- return mService.getLinkProperties(network);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Get the {@link NetworkCapabilities} for the given {@link Network}. This
- * will return {@code null} if the network is unknown or if the |network| argument is null.
- *
- * This will remove any location sensitive data in {@link TransportInfo} embedded in
- * {@link NetworkCapabilities#getTransportInfo()}. Some transport info instances like
- * {@link android.net.wifi.WifiInfo} contain location sensitive information. Retrieving
- * this location sensitive information (subject to app's location permissions) will be
- * noted by system. To include any location sensitive data in {@link TransportInfo},
- * use a {@link NetworkCallback} with
- * {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} flag.
- *
- * @param network The {@link Network} object identifying the network in question.
- * @return The {@link NetworkCapabilities} for the network, or {@code null}.
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @Nullable
- public NetworkCapabilities getNetworkCapabilities(@Nullable Network network) {
- try {
- return mService.getNetworkCapabilities(
- network, mContext.getOpPackageName(), getAttributionTag());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Gets a URL that can be used for resolving whether a captive portal is present.
- * 1. This URL should respond with a 204 response to a GET request to indicate no captive
- * portal is present.
- * 2. This URL must be HTTP as redirect responses are used to find captive portal
- * sign-in pages. Captive portals cannot respond to HTTPS requests with redirects.
- *
- * The system network validation may be using different strategies to detect captive portals,
- * so this method does not necessarily return a URL used by the system. It only returns a URL
- * that may be relevant for other components trying to detect captive portals.
- *
- * @hide
- * @deprecated This API returns URL which is not guaranteed to be one of the URLs used by the
- * system.
- */
- @Deprecated
- @SystemApi
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public String getCaptivePortalServerUrl() {
- try {
- return mService.getCaptivePortalServerUrl();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Tells the underlying networking system that the caller wants to
- * begin using the named feature. The interpretation of {@code feature}
- * is completely up to each networking implementation.
- *
- * <p>This method requires the caller to hold either the
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
- * or the ability to modify system settings as determined by
- * {@link android.provider.Settings.System#canWrite}.</p>
- *
- * @param networkType specifies which network the request pertains to
- * @param feature the name of the feature to be used
- * @return an integer value representing the outcome of the request.
- * The interpretation of this value is specific to each networking
- * implementation+feature combination, except that the value {@code -1}
- * always indicates failure.
- *
- * @deprecated Deprecated in favor of the cleaner
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)} API.
- * In {@link VERSION_CODES#M}, and above, this method is unsupported and will
- * throw {@code UnsupportedOperationException} if called.
- * @removed
- */
- @Deprecated
- public int startUsingNetworkFeature(int networkType, String feature) {
- checkLegacyRoutingApiAccess();
- NetworkCapabilities netCap = networkCapabilitiesForFeature(networkType, feature);
- if (netCap == null) {
- Log.d(TAG, "Can't satisfy startUsingNetworkFeature for " + networkType + ", " +
- feature);
- return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED;
- }
-
- NetworkRequest request = null;
- synchronized (sLegacyRequests) {
- LegacyRequest l = sLegacyRequests.get(netCap);
- if (l != null) {
- Log.d(TAG, "renewing startUsingNetworkFeature request " + l.networkRequest);
- renewRequestLocked(l);
- if (l.currentNetwork != null) {
- return DEPRECATED_PHONE_CONSTANT_APN_ALREADY_ACTIVE;
- } else {
- return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED;
- }
- }
-
- request = requestNetworkForFeatureLocked(netCap);
- }
- if (request != null) {
- Log.d(TAG, "starting startUsingNetworkFeature for request " + request);
- return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_STARTED;
- } else {
- Log.d(TAG, " request Failed");
- return DEPRECATED_PHONE_CONSTANT_APN_REQUEST_FAILED;
- }
- }
-
- /**
- * Tells the underlying networking system that the caller is finished
- * using the named feature. The interpretation of {@code feature}
- * is completely up to each networking implementation.
- *
- * <p>This method requires the caller to hold either the
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
- * or the ability to modify system settings as determined by
- * {@link android.provider.Settings.System#canWrite}.</p>
- *
- * @param networkType specifies which network the request pertains to
- * @param feature the name of the feature that is no longer needed
- * @return an integer value representing the outcome of the request.
- * The interpretation of this value is specific to each networking
- * implementation+feature combination, except that the value {@code -1}
- * always indicates failure.
- *
- * @deprecated Deprecated in favor of the cleaner
- * {@link #unregisterNetworkCallback(NetworkCallback)} API.
- * In {@link VERSION_CODES#M}, and above, this method is unsupported and will
- * throw {@code UnsupportedOperationException} if called.
- * @removed
- */
- @Deprecated
- public int stopUsingNetworkFeature(int networkType, String feature) {
- checkLegacyRoutingApiAccess();
- NetworkCapabilities netCap = networkCapabilitiesForFeature(networkType, feature);
- if (netCap == null) {
- Log.d(TAG, "Can't satisfy stopUsingNetworkFeature for " + networkType + ", " +
- feature);
- return -1;
- }
-
- if (removeRequestForFeature(netCap)) {
- Log.d(TAG, "stopUsingNetworkFeature for " + networkType + ", " + feature);
- }
- return 1;
- }
-
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) {
- if (networkType == TYPE_MOBILE) {
- switch (feature) {
- case "enableCBS":
- return networkCapabilitiesForType(TYPE_MOBILE_CBS);
- case "enableDUN":
- case "enableDUNAlways":
- return networkCapabilitiesForType(TYPE_MOBILE_DUN);
- case "enableFOTA":
- return networkCapabilitiesForType(TYPE_MOBILE_FOTA);
- case "enableHIPRI":
- return networkCapabilitiesForType(TYPE_MOBILE_HIPRI);
- case "enableIMS":
- return networkCapabilitiesForType(TYPE_MOBILE_IMS);
- case "enableMMS":
- return networkCapabilitiesForType(TYPE_MOBILE_MMS);
- case "enableSUPL":
- return networkCapabilitiesForType(TYPE_MOBILE_SUPL);
- default:
- return null;
- }
- } else if (networkType == TYPE_WIFI && "p2p".equals(feature)) {
- return networkCapabilitiesForType(TYPE_WIFI_P2P);
- }
- return null;
- }
-
- private int legacyTypeForNetworkCapabilities(NetworkCapabilities netCap) {
- if (netCap == null) return TYPE_NONE;
- if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
- return TYPE_MOBILE_CBS;
- }
- if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) {
- return TYPE_MOBILE_IMS;
- }
- if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) {
- return TYPE_MOBILE_FOTA;
- }
- if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) {
- return TYPE_MOBILE_DUN;
- }
- if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
- return TYPE_MOBILE_SUPL;
- }
- if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
- return TYPE_MOBILE_MMS;
- }
- if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
- return TYPE_MOBILE_HIPRI;
- }
- if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P)) {
- return TYPE_WIFI_P2P;
- }
- return TYPE_NONE;
- }
-
- private static class LegacyRequest {
- NetworkCapabilities networkCapabilities;
- NetworkRequest networkRequest;
- int expireSequenceNumber;
- Network currentNetwork;
- int delay = -1;
-
- private void clearDnsBinding() {
- if (currentNetwork != null) {
- currentNetwork = null;
- setProcessDefaultNetworkForHostResolution(null);
- }
- }
-
- NetworkCallback networkCallback = new NetworkCallback() {
- @Override
- public void onAvailable(Network network) {
- currentNetwork = network;
- Log.d(TAG, "startUsingNetworkFeature got Network:" + network);
- setProcessDefaultNetworkForHostResolution(network);
- }
- @Override
- public void onLost(Network network) {
- if (network.equals(currentNetwork)) clearDnsBinding();
- Log.d(TAG, "startUsingNetworkFeature lost Network:" + network);
- }
- };
- }
-
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- private static final HashMap<NetworkCapabilities, LegacyRequest> sLegacyRequests =
- new HashMap<>();
-
- private NetworkRequest findRequestForFeature(NetworkCapabilities netCap) {
- synchronized (sLegacyRequests) {
- LegacyRequest l = sLegacyRequests.get(netCap);
- if (l != null) return l.networkRequest;
- }
- return null;
- }
-
- private void renewRequestLocked(LegacyRequest l) {
- l.expireSequenceNumber++;
- Log.d(TAG, "renewing request to seqNum " + l.expireSequenceNumber);
- sendExpireMsgForFeature(l.networkCapabilities, l.expireSequenceNumber, l.delay);
- }
-
- private void expireRequest(NetworkCapabilities netCap, int sequenceNum) {
- int ourSeqNum = -1;
- synchronized (sLegacyRequests) {
- LegacyRequest l = sLegacyRequests.get(netCap);
- if (l == null) return;
- ourSeqNum = l.expireSequenceNumber;
- if (l.expireSequenceNumber == sequenceNum) removeRequestForFeature(netCap);
- }
- Log.d(TAG, "expireRequest with " + ourSeqNum + ", " + sequenceNum);
- }
-
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- private NetworkRequest requestNetworkForFeatureLocked(NetworkCapabilities netCap) {
- int delay = -1;
- int type = legacyTypeForNetworkCapabilities(netCap);
- try {
- delay = mService.getRestoreDefaultNetworkDelay(type);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- LegacyRequest l = new LegacyRequest();
- l.networkCapabilities = netCap;
- l.delay = delay;
- l.expireSequenceNumber = 0;
- l.networkRequest = sendRequestForNetwork(
- netCap, l.networkCallback, 0, REQUEST, type, getDefaultHandler());
- if (l.networkRequest == null) return null;
- sLegacyRequests.put(netCap, l);
- sendExpireMsgForFeature(netCap, l.expireSequenceNumber, delay);
- return l.networkRequest;
- }
-
- private void sendExpireMsgForFeature(NetworkCapabilities netCap, int seqNum, int delay) {
- if (delay >= 0) {
- Log.d(TAG, "sending expire msg with seqNum " + seqNum + " and delay " + delay);
- CallbackHandler handler = getDefaultHandler();
- Message msg = handler.obtainMessage(EXPIRE_LEGACY_REQUEST, seqNum, 0, netCap);
- handler.sendMessageDelayed(msg, delay);
- }
- }
-
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- private boolean removeRequestForFeature(NetworkCapabilities netCap) {
- final LegacyRequest l;
- synchronized (sLegacyRequests) {
- l = sLegacyRequests.remove(netCap);
- }
- if (l == null) return false;
- unregisterNetworkCallback(l.networkCallback);
- l.clearDnsBinding();
- return true;
- }
-
- private static final SparseIntArray sLegacyTypeToTransport = new SparseIntArray();
- static {
- sLegacyTypeToTransport.put(TYPE_MOBILE, NetworkCapabilities.TRANSPORT_CELLULAR);
- sLegacyTypeToTransport.put(TYPE_MOBILE_CBS, NetworkCapabilities.TRANSPORT_CELLULAR);
- sLegacyTypeToTransport.put(TYPE_MOBILE_DUN, NetworkCapabilities.TRANSPORT_CELLULAR);
- sLegacyTypeToTransport.put(TYPE_MOBILE_FOTA, NetworkCapabilities.TRANSPORT_CELLULAR);
- sLegacyTypeToTransport.put(TYPE_MOBILE_HIPRI, NetworkCapabilities.TRANSPORT_CELLULAR);
- sLegacyTypeToTransport.put(TYPE_MOBILE_IMS, NetworkCapabilities.TRANSPORT_CELLULAR);
- sLegacyTypeToTransport.put(TYPE_MOBILE_MMS, NetworkCapabilities.TRANSPORT_CELLULAR);
- sLegacyTypeToTransport.put(TYPE_MOBILE_SUPL, NetworkCapabilities.TRANSPORT_CELLULAR);
- sLegacyTypeToTransport.put(TYPE_WIFI, NetworkCapabilities.TRANSPORT_WIFI);
- sLegacyTypeToTransport.put(TYPE_WIFI_P2P, NetworkCapabilities.TRANSPORT_WIFI);
- sLegacyTypeToTransport.put(TYPE_BLUETOOTH, NetworkCapabilities.TRANSPORT_BLUETOOTH);
- sLegacyTypeToTransport.put(TYPE_ETHERNET, NetworkCapabilities.TRANSPORT_ETHERNET);
- }
-
- private static final SparseIntArray sLegacyTypeToCapability = new SparseIntArray();
- static {
- sLegacyTypeToCapability.put(TYPE_MOBILE_CBS, NetworkCapabilities.NET_CAPABILITY_CBS);
- sLegacyTypeToCapability.put(TYPE_MOBILE_DUN, NetworkCapabilities.NET_CAPABILITY_DUN);
- sLegacyTypeToCapability.put(TYPE_MOBILE_FOTA, NetworkCapabilities.NET_CAPABILITY_FOTA);
- sLegacyTypeToCapability.put(TYPE_MOBILE_IMS, NetworkCapabilities.NET_CAPABILITY_IMS);
- sLegacyTypeToCapability.put(TYPE_MOBILE_MMS, NetworkCapabilities.NET_CAPABILITY_MMS);
- sLegacyTypeToCapability.put(TYPE_MOBILE_SUPL, NetworkCapabilities.NET_CAPABILITY_SUPL);
- sLegacyTypeToCapability.put(TYPE_WIFI_P2P, NetworkCapabilities.NET_CAPABILITY_WIFI_P2P);
- }
-
- /**
- * Given a legacy type (TYPE_WIFI, ...) returns a NetworkCapabilities
- * instance suitable for registering a request or callback. Throws an
- * IllegalArgumentException if no mapping from the legacy type to
- * NetworkCapabilities is known.
- *
- * @deprecated Types are deprecated. Use {@link NetworkCallback} or {@link NetworkRequest}
- * to find the network instead.
- * @hide
- */
- public static NetworkCapabilities networkCapabilitiesForType(int type) {
- final NetworkCapabilities nc = new NetworkCapabilities();
-
- // Map from type to transports.
- final int NOT_FOUND = -1;
- final int transport = sLegacyTypeToTransport.get(type, NOT_FOUND);
- if (transport == NOT_FOUND) {
- throw new IllegalArgumentException("unknown legacy type: " + type);
- }
- nc.addTransportType(transport);
-
- // Map from type to capabilities.
- nc.addCapability(sLegacyTypeToCapability.get(
- type, NetworkCapabilities.NET_CAPABILITY_INTERNET));
- nc.maybeMarkCapabilitiesRestricted();
- return nc;
- }
-
- /** @hide */
- public static class PacketKeepaliveCallback {
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public PacketKeepaliveCallback() {
- }
- /** The requested keepalive was successfully started. */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public void onStarted() {}
- /** The keepalive was successfully stopped. */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public void onStopped() {}
- /** An error occurred. */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public void onError(int error) {}
- }
-
- /**
- * Allows applications to request that the system periodically send specific packets on their
- * behalf, using hardware offload to save battery power.
- *
- * To request that the system send keepalives, call one of the methods that return a
- * {@link ConnectivityManager.PacketKeepalive} object, such as {@link #startNattKeepalive},
- * passing in a non-null callback. If the callback is successfully started, the callback's
- * {@code onStarted} method will be called. If an error occurs, {@code onError} will be called,
- * specifying one of the {@code ERROR_*} constants in this class.
- *
- * To stop an existing keepalive, call {@link PacketKeepalive#stop}. The system will call
- * {@link PacketKeepaliveCallback#onStopped} if the operation was successful or
- * {@link PacketKeepaliveCallback#onError} if an error occurred.
- *
- * @deprecated Use {@link SocketKeepalive} instead.
- *
- * @hide
- */
- public class PacketKeepalive {
-
- private static final String TAG = "PacketKeepalive";
-
- /** @hide */
- public static final int SUCCESS = 0;
-
- /** @hide */
- public static final int NO_KEEPALIVE = -1;
-
- /** @hide */
- public static final int BINDER_DIED = -10;
-
- /** The specified {@code Network} is not connected. */
- public static final int ERROR_INVALID_NETWORK = -20;
- /** The specified IP addresses are invalid. For example, the specified source IP address is
- * not configured on the specified {@code Network}. */
- public static final int ERROR_INVALID_IP_ADDRESS = -21;
- /** The requested port is invalid. */
- public static final int ERROR_INVALID_PORT = -22;
- /** The packet length is invalid (e.g., too long). */
- public static final int ERROR_INVALID_LENGTH = -23;
- /** The packet transmission interval is invalid (e.g., too short). */
- public static final int ERROR_INVALID_INTERVAL = -24;
-
- /** The hardware does not support this request. */
- public static final int ERROR_HARDWARE_UNSUPPORTED = -30;
- /** The hardware returned an error. */
- public static final int ERROR_HARDWARE_ERROR = -31;
-
- /** The NAT-T destination port for IPsec */
- public static final int NATT_PORT = 4500;
-
- /** The minimum interval in seconds between keepalive packet transmissions */
- public static final int MIN_INTERVAL = 10;
-
- private final Network mNetwork;
- private final ISocketKeepaliveCallback mCallback;
- private final ExecutorService mExecutor;
-
- private volatile Integer mSlot;
-
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public void stop() {
- try {
- mExecutor.execute(() -> {
- try {
- if (mSlot != null) {
- mService.stopKeepalive(mNetwork, mSlot);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Error stopping packet keepalive: ", e);
- throw e.rethrowFromSystemServer();
- }
- });
- } catch (RejectedExecutionException e) {
- // The internal executor has already stopped due to previous event.
- }
- }
-
- private PacketKeepalive(Network network, PacketKeepaliveCallback callback) {
- Objects.requireNonNull(network, "network cannot be null");
- Objects.requireNonNull(callback, "callback cannot be null");
- mNetwork = network;
- mExecutor = Executors.newSingleThreadExecutor();
- mCallback = new ISocketKeepaliveCallback.Stub() {
- @Override
- public void onStarted(int slot) {
- final long token = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> {
- mSlot = slot;
- callback.onStarted();
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void onStopped() {
- final long token = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> {
- mSlot = null;
- callback.onStopped();
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- mExecutor.shutdown();
- }
-
- @Override
- public void onError(int error) {
- final long token = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> {
- mSlot = null;
- callback.onError(error);
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- mExecutor.shutdown();
- }
-
- @Override
- public void onDataReceived() {
- // PacketKeepalive is only used for Nat-T keepalive and as such does not invoke
- // this callback when data is received.
- }
- };
- }
- }
-
- /**
- * Starts an IPsec NAT-T keepalive packet with the specified parameters.
- *
- * @deprecated Use {@link #createSocketKeepalive} instead.
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public PacketKeepalive startNattKeepalive(
- Network network, int intervalSeconds, PacketKeepaliveCallback callback,
- InetAddress srcAddr, int srcPort, InetAddress dstAddr) {
- final PacketKeepalive k = new PacketKeepalive(network, callback);
- try {
- mService.startNattKeepalive(network, intervalSeconds, k.mCallback,
- srcAddr.getHostAddress(), srcPort, dstAddr.getHostAddress());
- } catch (RemoteException e) {
- Log.e(TAG, "Error starting packet keepalive: ", e);
- throw e.rethrowFromSystemServer();
- }
- return k;
- }
-
- // Construct an invalid fd.
- private ParcelFileDescriptor createInvalidFd() {
- final int invalidFd = -1;
- return ParcelFileDescriptor.adoptFd(invalidFd);
- }
-
- /**
- * Request that keepalives be started on a IPsec NAT-T socket.
- *
- * @param network The {@link Network} the socket is on.
- * @param socket The socket that needs to be kept alive.
- * @param source The source address of the {@link UdpEncapsulationSocket}.
- * @param destination The destination address of the {@link UdpEncapsulationSocket}.
- * @param executor The executor on which callback will be invoked. The provided {@link Executor}
- * must run callback sequentially, otherwise the order of callbacks cannot be
- * guaranteed.
- * @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive
- * changes. Must be extended by applications that use this API.
- *
- * @return A {@link SocketKeepalive} object that can be used to control the keepalive on the
- * given socket.
- **/
- public @NonNull SocketKeepalive createSocketKeepalive(@NonNull Network network,
- @NonNull UdpEncapsulationSocket socket,
- @NonNull InetAddress source,
- @NonNull InetAddress destination,
- @NonNull @CallbackExecutor Executor executor,
- @NonNull Callback callback) {
- ParcelFileDescriptor dup;
- try {
- // Dup is needed here as the pfd inside the socket is owned by the IpSecService,
- // which cannot be obtained by the app process.
- dup = ParcelFileDescriptor.dup(socket.getFileDescriptor());
- } catch (IOException ignored) {
- // Construct an invalid fd, so that if the user later calls start(), it will fail with
- // ERROR_INVALID_SOCKET.
- dup = createInvalidFd();
- }
- return new NattSocketKeepalive(mService, network, dup, socket.getResourceId(), source,
- destination, executor, callback);
- }
-
- /**
- * Request that keepalives be started on a IPsec NAT-T socket file descriptor. Directly called
- * by system apps which don't use IpSecService to create {@link UdpEncapsulationSocket}.
- *
- * @param network The {@link Network} the socket is on.
- * @param pfd The {@link ParcelFileDescriptor} that needs to be kept alive. The provided
- * {@link ParcelFileDescriptor} must be bound to a port and the keepalives will be sent
- * from that port.
- * @param source The source address of the {@link UdpEncapsulationSocket}.
- * @param destination The destination address of the {@link UdpEncapsulationSocket}. The
- * keepalive packets will always be sent to port 4500 of the given {@code destination}.
- * @param executor The executor on which callback will be invoked. The provided {@link Executor}
- * must run callback sequentially, otherwise the order of callbacks cannot be
- * guaranteed.
- * @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive
- * changes. Must be extended by applications that use this API.
- *
- * @return A {@link SocketKeepalive} object that can be used to control the keepalive on the
- * given socket.
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD)
- public @NonNull SocketKeepalive createNattKeepalive(@NonNull Network network,
- @NonNull ParcelFileDescriptor pfd,
- @NonNull InetAddress source,
- @NonNull InetAddress destination,
- @NonNull @CallbackExecutor Executor executor,
- @NonNull Callback callback) {
- ParcelFileDescriptor dup;
- try {
- // TODO: Consider remove unnecessary dup.
- dup = pfd.dup();
- } catch (IOException ignored) {
- // Construct an invalid fd, so that if the user later calls start(), it will fail with
- // ERROR_INVALID_SOCKET.
- dup = createInvalidFd();
- }
- return new NattSocketKeepalive(mService, network, dup,
- -1 /* Unused */, source, destination, executor, callback);
- }
-
- /**
- * Request that keepalives be started on a TCP socket.
- * The socket must be established.
- *
- * @param network The {@link Network} the socket is on.
- * @param socket The socket that needs to be kept alive.
- * @param executor The executor on which callback will be invoked. This implementation assumes
- * the provided {@link Executor} runs the callbacks in sequence with no
- * concurrency. Failing this, no guarantee of correctness can be made. It is
- * the responsibility of the caller to ensure the executor provides this
- * guarantee. A simple way of creating such an executor is with the standard
- * tool {@code Executors.newSingleThreadExecutor}.
- * @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive
- * changes. Must be extended by applications that use this API.
- *
- * @return A {@link SocketKeepalive} object that can be used to control the keepalive on the
- * given socket.
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD)
- public @NonNull SocketKeepalive createSocketKeepalive(@NonNull Network network,
- @NonNull Socket socket,
- @NonNull Executor executor,
- @NonNull Callback callback) {
- ParcelFileDescriptor dup;
- try {
- dup = ParcelFileDescriptor.fromSocket(socket);
- } catch (UncheckedIOException ignored) {
- // Construct an invalid fd, so that if the user later calls start(), it will fail with
- // ERROR_INVALID_SOCKET.
- dup = createInvalidFd();
- }
- return new TcpSocketKeepalive(mService, network, dup, executor, callback);
- }
-
- /**
- * Ensure that a network route exists to deliver traffic to the specified
- * host via the specified network interface. An attempt to add a route that
- * already exists is ignored, but treated as successful.
- *
- * <p>This method requires the caller to hold either the
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
- * or the ability to modify system settings as determined by
- * {@link android.provider.Settings.System#canWrite}.</p>
- *
- * @param networkType the type of the network over which traffic to the specified
- * host is to be routed
- * @param hostAddress the IP address of the host to which the route is desired
- * @return {@code true} on success, {@code false} on failure
- *
- * @deprecated Deprecated in favor of the
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)},
- * {@link #bindProcessToNetwork} and {@link Network#getSocketFactory} API.
- * In {@link VERSION_CODES#M}, and above, this method is unsupported and will
- * throw {@code UnsupportedOperationException} if called.
- * @removed
- */
- @Deprecated
- public boolean requestRouteToHost(int networkType, int hostAddress) {
- return requestRouteToHostAddress(networkType, NetworkUtils.intToInetAddress(hostAddress));
- }
-
- /**
- * Ensure that a network route exists to deliver traffic to the specified
- * host via the specified network interface. An attempt to add a route that
- * already exists is ignored, but treated as successful.
- *
- * <p>This method requires the caller to hold either the
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
- * or the ability to modify system settings as determined by
- * {@link android.provider.Settings.System#canWrite}.</p>
- *
- * @param networkType the type of the network over which traffic to the specified
- * host is to be routed
- * @param hostAddress the IP address of the host to which the route is desired
- * @return {@code true} on success, {@code false} on failure
- * @hide
- * @deprecated Deprecated in favor of the {@link #requestNetwork} and
- * {@link #bindProcessToNetwork} API.
- */
- @Deprecated
- @UnsupportedAppUsage
- @SystemApi(client = MODULE_LIBRARIES)
- public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) {
- checkLegacyRoutingApiAccess();
- try {
- return mService.requestRouteToHostAddress(networkType, hostAddress.getAddress(),
- mContext.getOpPackageName(), getAttributionTag());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * @return the context's attribution tag
- */
- // TODO: Remove method and replace with direct call once R code is pushed to AOSP
- private @Nullable String getAttributionTag() {
- return mContext.getAttributionTag();
- }
-
- /**
- * Returns the value of the setting for background data usage. If false,
- * applications should not use the network if the application is not in the
- * foreground. Developers should respect this setting, and check the value
- * of this before performing any background data operations.
- * <p>
- * All applications that have background services that use the network
- * should listen to {@link #ACTION_BACKGROUND_DATA_SETTING_CHANGED}.
- * <p>
- * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH}, availability of
- * background data depends on several combined factors, and this method will
- * always return {@code true}. Instead, when background data is unavailable,
- * {@link #getActiveNetworkInfo()} will now appear disconnected.
- *
- * @return Whether background data usage is allowed.
- */
- @Deprecated
- public boolean getBackgroundDataSetting() {
- // assume that background data is allowed; final authority is
- // NetworkInfo which may be blocked.
- return true;
- }
-
- /**
- * Sets the value of the setting for background data usage.
- *
- * @param allowBackgroundData Whether an application should use data while
- * it is in the background.
- *
- * @attr ref android.Manifest.permission#CHANGE_BACKGROUND_DATA_SETTING
- * @see #getBackgroundDataSetting()
- * @hide
- */
- @Deprecated
- @UnsupportedAppUsage
- public void setBackgroundDataSetting(boolean allowBackgroundData) {
- // ignored
- }
-
- /**
- * @hide
- * @deprecated Talk to TelephonyManager directly
- */
- @Deprecated
- @UnsupportedAppUsage
- public boolean getMobileDataEnabled() {
- TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
- if (tm != null) {
- int subId = SubscriptionManager.getDefaultDataSubscriptionId();
- Log.d("ConnectivityManager", "getMobileDataEnabled()+ subId=" + subId);
- boolean retVal = tm.createForSubscriptionId(subId).isDataEnabled();
- Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId
- + " retVal=" + retVal);
- return retVal;
- }
- Log.d("ConnectivityManager", "getMobileDataEnabled()- remote exception retVal=false");
- return false;
- }
-
- /**
- * Callback for use with {@link ConnectivityManager#addDefaultNetworkActiveListener}
- * to find out when the system default network has gone in to a high power state.
- */
- public interface OnNetworkActiveListener {
- /**
- * Called on the main thread of the process to report that the current data network
- * has become active, and it is now a good time to perform any pending network
- * operations. Note that this listener only tells you when the network becomes
- * active; if at any other time you want to know whether it is active (and thus okay
- * to initiate network traffic), you can retrieve its instantaneous state with
- * {@link ConnectivityManager#isDefaultNetworkActive}.
- */
- void onNetworkActive();
- }
-
- private final ArrayMap<OnNetworkActiveListener, INetworkActivityListener>
- mNetworkActivityListeners = new ArrayMap<>();
-
- /**
- * Start listening to reports when the system's default data network is active, meaning it is
- * a good time to perform network traffic. Use {@link #isDefaultNetworkActive()}
- * to determine the current state of the system's default network after registering the
- * listener.
- * <p>
- * If the process default network has been set with
- * {@link ConnectivityManager#bindProcessToNetwork} this function will not
- * reflect the process's default, but the system default.
- *
- * @param l The listener to be told when the network is active.
- */
- public void addDefaultNetworkActiveListener(final OnNetworkActiveListener l) {
- INetworkActivityListener rl = new INetworkActivityListener.Stub() {
- @Override
- public void onNetworkActive() throws RemoteException {
- l.onNetworkActive();
- }
- };
-
- try {
- mService.registerNetworkActivityListener(rl);
- mNetworkActivityListeners.put(l, rl);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Remove network active listener previously registered with
- * {@link #addDefaultNetworkActiveListener}.
- *
- * @param l Previously registered listener.
- */
- public void removeDefaultNetworkActiveListener(@NonNull OnNetworkActiveListener l) {
- INetworkActivityListener rl = mNetworkActivityListeners.get(l);
- if (rl == null) {
- throw new IllegalArgumentException("Listener was not registered.");
- }
- try {
- mService.registerNetworkActivityListener(rl);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Return whether the data network is currently active. An active network means that
- * it is currently in a high power state for performing data transmission. On some
- * types of networks, it may be expensive to move and stay in such a state, so it is
- * more power efficient to batch network traffic together when the radio is already in
- * this state. This method tells you whether right now is currently a good time to
- * initiate network traffic, as the network is already active.
- */
- public boolean isDefaultNetworkActive() {
- try {
- return mService.isDefaultNetworkActive();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * {@hide}
- */
- public ConnectivityManager(Context context, IConnectivityManager service) {
- mContext = Objects.requireNonNull(context, "missing context");
- mService = Objects.requireNonNull(service, "missing IConnectivityManager");
- mTetheringManager = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE);
- sInstance = this;
- }
-
- /** {@hide} */
- @UnsupportedAppUsage
- public static ConnectivityManager from(Context context) {
- return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- }
-
- /** @hide */
- public NetworkRequest getDefaultRequest() {
- try {
- // This is not racy as the default request is final in ConnectivityService.
- return mService.getDefaultRequest();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Check if the package is a allowed to write settings. This also accounts that such an access
- * happened.
- *
- * @return {@code true} iff the package is allowed to write settings.
- */
- // TODO: Remove method and replace with direct call once R code is pushed to AOSP
- private static boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid,
- @NonNull String callingPackage, @Nullable String callingAttributionTag,
- boolean throwException) {
- return Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPackage,
- callingAttributionTag, throwException);
- }
-
- /**
- * @deprecated - use getSystemService. This is a kludge to support static access in certain
- * situations where a Context pointer is unavailable.
- * @hide
- */
- @Deprecated
- static ConnectivityManager getInstanceOrNull() {
- return sInstance;
- }
-
- /**
- * @deprecated - use getSystemService. This is a kludge to support static access in certain
- * situations where a Context pointer is unavailable.
- * @hide
- */
- @Deprecated
- @UnsupportedAppUsage
- private static ConnectivityManager getInstance() {
- if (getInstanceOrNull() == null) {
- throw new IllegalStateException("No ConnectivityManager yet constructed");
- }
- return getInstanceOrNull();
- }
-
- /**
- * Get the set of tetherable, available interfaces. This list is limited by
- * device configuration and current interface existence.
- *
- * @return an array of 0 or more Strings of tetherable interface names.
- *
- * @deprecated Use {@link TetheringEventCallback#onTetherableInterfacesChanged(List)} instead.
- * {@hide}
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @UnsupportedAppUsage
- @Deprecated
- public String[] getTetherableIfaces() {
- return mTetheringManager.getTetherableIfaces();
- }
-
- /**
- * Get the set of tethered interfaces.
- *
- * @return an array of 0 or more String of currently tethered interface names.
- *
- * @deprecated Use {@link TetheringEventCallback#onTetherableInterfacesChanged(List)} instead.
- * {@hide}
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @UnsupportedAppUsage
- @Deprecated
- public String[] getTetheredIfaces() {
- return mTetheringManager.getTetheredIfaces();
- }
-
- /**
- * Get the set of interface names which attempted to tether but
- * failed. Re-attempting to tether may cause them to reset to the Tethered
- * state. Alternatively, causing the interface to be destroyed and recreated
- * may cause them to reset to the available state.
- * {@link ConnectivityManager#getLastTetherError} can be used to get more
- * information on the cause of the errors.
- *
- * @return an array of 0 or more String indicating the interface names
- * which failed to tether.
- *
- * @deprecated Use {@link TetheringEventCallback#onError(String, int)} instead.
- * {@hide}
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @UnsupportedAppUsage
- @Deprecated
- public String[] getTetheringErroredIfaces() {
- return mTetheringManager.getTetheringErroredIfaces();
- }
-
- /**
- * Get the set of tethered dhcp ranges.
- *
- * @deprecated This method is not supported.
- * TODO: remove this function when all of clients are removed.
- * {@hide}
- */
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- @Deprecated
- public String[] getTetheredDhcpRanges() {
- throw new UnsupportedOperationException("getTetheredDhcpRanges is not supported");
- }
-
- /**
- * Attempt to tether the named interface. This will setup a dhcp server
- * on the interface, forward and NAT IP packets and forward DNS requests
- * to the best active upstream network interface. Note that if no upstream
- * IP network interface is available, dhcp will still run and traffic will be
- * allowed between the tethered devices and this device, though upstream net
- * access will of course fail until an upstream network interface becomes
- * active.
- *
- * <p>This method requires the caller to hold either the
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
- * or the ability to modify system settings as determined by
- * {@link android.provider.Settings.System#canWrite}.</p>
- *
- * <p>WARNING: New clients should not use this function. The only usages should be in PanService
- * and WifiStateMachine which need direct access. All other clients should use
- * {@link #startTethering} and {@link #stopTethering} which encapsulate proper provisioning
- * logic.</p>
- *
- * @param iface the interface name to tether.
- * @return error a {@code TETHER_ERROR} value indicating success or failure type
- * @deprecated Use {@link TetheringManager#startTethering} instead
- *
- * {@hide}
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @Deprecated
- public int tether(String iface) {
- return mTetheringManager.tether(iface);
- }
-
- /**
- * Stop tethering the named interface.
- *
- * <p>This method requires the caller to hold either the
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
- * or the ability to modify system settings as determined by
- * {@link android.provider.Settings.System#canWrite}.</p>
- *
- * <p>WARNING: New clients should not use this function. The only usages should be in PanService
- * and WifiStateMachine which need direct access. All other clients should use
- * {@link #startTethering} and {@link #stopTethering} which encapsulate proper provisioning
- * logic.</p>
- *
- * @param iface the interface name to untether.
- * @return error a {@code TETHER_ERROR} value indicating success or failure type
- *
- * {@hide}
- */
- @UnsupportedAppUsage
- @Deprecated
- public int untether(String iface) {
- return mTetheringManager.untether(iface);
- }
-
- /**
- * Check if the device allows for tethering. It may be disabled via
- * {@code ro.tether.denied} system property, Settings.TETHER_SUPPORTED or
- * due to device configuration.
- *
- * <p>If this app does not have permission to use this API, it will always
- * return false rather than throw an exception.</p>
- *
- * <p>If the device has a hotspot provisioning app, the caller is required to hold the
- * {@link android.Manifest.permission.TETHER_PRIVILEGED} permission.</p>
- *
- * <p>Otherwise, this method requires the caller to hold the ability to modify system
- * settings as determined by {@link android.provider.Settings.System#canWrite}.</p>
- *
- * @return a boolean - {@code true} indicating Tethering is supported.
- *
- * @deprecated Use {@link TetheringEventCallback#onTetheringSupported(boolean)} instead.
- * {@hide}
- */
- @SystemApi
- @RequiresPermission(anyOf = {android.Manifest.permission.TETHER_PRIVILEGED,
- android.Manifest.permission.WRITE_SETTINGS})
- public boolean isTetheringSupported() {
- return mTetheringManager.isTetheringSupported();
- }
-
- /**
- * Callback for use with {@link #startTethering} to find out whether tethering succeeded.
- *
- * @deprecated Use {@link TetheringManager.StartTetheringCallback} instead.
- * @hide
- */
- @SystemApi
- @Deprecated
- public static abstract class OnStartTetheringCallback {
- /**
- * Called when tethering has been successfully started.
- */
- public void onTetheringStarted() {}
-
- /**
- * Called when starting tethering failed.
- */
- public void onTetheringFailed() {}
- }
-
- /**
- * Convenient overload for
- * {@link #startTethering(int, boolean, OnStartTetheringCallback, Handler)} which passes a null
- * handler to run on the current thread's {@link Looper}.
- *
- * @deprecated Use {@link TetheringManager#startTethering} instead.
- * @hide
- */
- @SystemApi
- @Deprecated
- @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
- public void startTethering(int type, boolean showProvisioningUi,
- final OnStartTetheringCallback callback) {
- startTethering(type, showProvisioningUi, callback, null);
- }
-
- /**
- * Runs tether provisioning for the given type if needed and then starts tethering if
- * the check succeeds. If no carrier provisioning is required for tethering, tethering is
- * enabled immediately. If provisioning fails, tethering will not be enabled. It also
- * schedules tether provisioning re-checks if appropriate.
- *
- * @param type The type of tethering to start. Must be one of
- * {@link ConnectivityManager.TETHERING_WIFI},
- * {@link ConnectivityManager.TETHERING_USB}, or
- * {@link ConnectivityManager.TETHERING_BLUETOOTH}.
- * @param showProvisioningUi a boolean indicating to show the provisioning app UI if there
- * is one. This should be true the first time this function is called and also any time
- * the user can see this UI. It gives users information from their carrier about the
- * check failing and how they can sign up for tethering if possible.
- * @param callback an {@link OnStartTetheringCallback} which will be called to notify the caller
- * of the result of trying to tether.
- * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
- *
- * @deprecated Use {@link TetheringManager#startTethering} instead.
- * @hide
- */
- @SystemApi
- @Deprecated
- @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
- public void startTethering(int type, boolean showProvisioningUi,
- final OnStartTetheringCallback callback, Handler handler) {
- Objects.requireNonNull(callback, "OnStartTetheringCallback cannot be null.");
-
- final Executor executor = new Executor() {
- @Override
- public void execute(Runnable command) {
- if (handler == null) {
- command.run();
- } else {
- handler.post(command);
- }
- }
- };
-
- final StartTetheringCallback tetheringCallback = new StartTetheringCallback() {
- @Override
- public void onTetheringStarted() {
- callback.onTetheringStarted();
- }
-
- @Override
- public void onTetheringFailed(final int error) {
- callback.onTetheringFailed();
- }
- };
-
- final TetheringRequest request = new TetheringRequest.Builder(type)
- .setShouldShowEntitlementUi(showProvisioningUi).build();
-
- mTetheringManager.startTethering(request, executor, tetheringCallback);
- }
-
- /**
- * Stops tethering for the given type. Also cancels any provisioning rechecks for that type if
- * applicable.
- *
- * @param type The type of tethering to stop. Must be one of
- * {@link ConnectivityManager.TETHERING_WIFI},
- * {@link ConnectivityManager.TETHERING_USB}, or
- * {@link ConnectivityManager.TETHERING_BLUETOOTH}.
- *
- * @deprecated Use {@link TetheringManager#stopTethering} instead.
- * @hide
- */
- @SystemApi
- @Deprecated
- @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
- public void stopTethering(int type) {
- mTetheringManager.stopTethering(type);
- }
-
- /**
- * Callback for use with {@link registerTetheringEventCallback} to find out tethering
- * upstream status.
- *
- * @deprecated Use {@link TetheringManager#OnTetheringEventCallback} instead.
- * @hide
- */
- @SystemApi
- @Deprecated
- public abstract static class OnTetheringEventCallback {
-
- /**
- * Called when tethering upstream changed. This can be called multiple times and can be
- * called any time.
- *
- * @param network the {@link Network} of tethering upstream. Null means tethering doesn't
- * have any upstream.
- */
- public void onUpstreamChanged(@Nullable Network network) {}
- }
-
- @GuardedBy("mTetheringEventCallbacks")
- private final ArrayMap<OnTetheringEventCallback, TetheringEventCallback>
- mTetheringEventCallbacks = new ArrayMap<>();
-
- /**
- * Start listening to tethering change events. Any new added callback will receive the last
- * tethering status right away. If callback is registered when tethering has no upstream or
- * disabled, {@link OnTetheringEventCallback#onUpstreamChanged} will immediately be called
- * with a null argument. The same callback object cannot be registered twice.
- *
- * @param executor the executor on which callback will be invoked.
- * @param callback the callback to be called when tethering has change events.
- *
- * @deprecated Use {@link TetheringManager#registerTetheringEventCallback} instead.
- * @hide
- */
- @SystemApi
- @Deprecated
- @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
- public void registerTetheringEventCallback(
- @NonNull @CallbackExecutor Executor executor,
- @NonNull final OnTetheringEventCallback callback) {
- Objects.requireNonNull(callback, "OnTetheringEventCallback cannot be null.");
-
- final TetheringEventCallback tetherCallback =
- new TetheringEventCallback() {
- @Override
- public void onUpstreamChanged(@Nullable Network network) {
- callback.onUpstreamChanged(network);
- }
- };
-
- synchronized (mTetheringEventCallbacks) {
- mTetheringEventCallbacks.put(callback, tetherCallback);
- mTetheringManager.registerTetheringEventCallback(executor, tetherCallback);
- }
- }
-
- /**
- * Remove tethering event callback previously registered with
- * {@link #registerTetheringEventCallback}.
- *
- * @param callback previously registered callback.
- *
- * @deprecated Use {@link TetheringManager#unregisterTetheringEventCallback} instead.
- * @hide
- */
- @SystemApi
- @Deprecated
- @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
- public void unregisterTetheringEventCallback(
- @NonNull final OnTetheringEventCallback callback) {
- Objects.requireNonNull(callback, "The callback must be non-null");
- synchronized (mTetheringEventCallbacks) {
- final TetheringEventCallback tetherCallback =
- mTetheringEventCallbacks.remove(callback);
- mTetheringManager.unregisterTetheringEventCallback(tetherCallback);
- }
- }
-
-
- /**
- * Get the list of regular expressions that define any tetherable
- * USB network interfaces. If USB tethering is not supported by the
- * device, this list should be empty.
- *
- * @return an array of 0 or more regular expression Strings defining
- * what interfaces are considered tetherable usb interfaces.
- *
- * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged} instead.
- * {@hide}
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @UnsupportedAppUsage
- @Deprecated
- public String[] getTetherableUsbRegexs() {
- return mTetheringManager.getTetherableUsbRegexs();
- }
-
- /**
- * Get the list of regular expressions that define any tetherable
- * Wifi network interfaces. If Wifi tethering is not supported by the
- * device, this list should be empty.
- *
- * @return an array of 0 or more regular expression Strings defining
- * what interfaces are considered tetherable wifi interfaces.
- *
- * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged} instead.
- * {@hide}
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @UnsupportedAppUsage
- @Deprecated
- public String[] getTetherableWifiRegexs() {
- return mTetheringManager.getTetherableWifiRegexs();
- }
-
- /**
- * Get the list of regular expressions that define any tetherable
- * Bluetooth network interfaces. If Bluetooth tethering is not supported by the
- * device, this list should be empty.
- *
- * @return an array of 0 or more regular expression Strings defining
- * what interfaces are considered tetherable bluetooth interfaces.
- *
- * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged(
- *TetheringManager.TetheringInterfaceRegexps)} instead.
- * {@hide}
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @UnsupportedAppUsage
- @Deprecated
- public String[] getTetherableBluetoothRegexs() {
- return mTetheringManager.getTetherableBluetoothRegexs();
- }
-
- /**
- * Attempt to both alter the mode of USB and Tethering of USB. A
- * utility method to deal with some of the complexity of USB - will
- * attempt to switch to Rndis and subsequently tether the resulting
- * interface on {@code true} or turn off tethering and switch off
- * Rndis on {@code false}.
- *
- * <p>This method requires the caller to hold either the
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
- * or the ability to modify system settings as determined by
- * {@link android.provider.Settings.System#canWrite}.</p>
- *
- * @param enable a boolean - {@code true} to enable tethering
- * @return error a {@code TETHER_ERROR} value indicating success or failure type
- * @deprecated Use {@link TetheringManager#startTethering} instead
- *
- * {@hide}
- */
- @UnsupportedAppUsage
- @Deprecated
- public int setUsbTethering(boolean enable) {
- return mTetheringManager.setUsbTethering(enable);
- }
-
- /**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_NO_ERROR}.
- * {@hide}
- */
- @SystemApi
- @Deprecated
- public static final int TETHER_ERROR_NO_ERROR = 0;
- /**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNKNOWN_IFACE}.
- * {@hide}
- */
- @Deprecated
- public static final int TETHER_ERROR_UNKNOWN_IFACE =
- TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
- /**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_SERVICE_UNAVAIL}.
- * {@hide}
- */
- @Deprecated
- public static final int TETHER_ERROR_SERVICE_UNAVAIL =
- TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
- /**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNSUPPORTED}.
- * {@hide}
- */
- @Deprecated
- public static final int TETHER_ERROR_UNSUPPORTED = TetheringManager.TETHER_ERROR_UNSUPPORTED;
- /**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNAVAIL_IFACE}.
- * {@hide}
- */
- @Deprecated
- public static final int TETHER_ERROR_UNAVAIL_IFACE =
- TetheringManager.TETHER_ERROR_UNAVAIL_IFACE;
- /**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_INTERNAL_ERROR}.
- * {@hide}
- */
- @Deprecated
- public static final int TETHER_ERROR_MASTER_ERROR =
- TetheringManager.TETHER_ERROR_INTERNAL_ERROR;
- /**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_TETHER_IFACE_ERROR}.
- * {@hide}
- */
- @Deprecated
- public static final int TETHER_ERROR_TETHER_IFACE_ERROR =
- TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR;
- /**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNTETHER_IFACE_ERROR}.
- * {@hide}
- */
- @Deprecated
- public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR =
- TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
- /**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_ENABLE_FORWARDING_ERROR}.
- * {@hide}
- */
- @Deprecated
- public static final int TETHER_ERROR_ENABLE_NAT_ERROR =
- TetheringManager.TETHER_ERROR_ENABLE_FORWARDING_ERROR;
- /**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_DISABLE_FORWARDING_ERROR}.
- * {@hide}
- */
- @Deprecated
- public static final int TETHER_ERROR_DISABLE_NAT_ERROR =
- TetheringManager.TETHER_ERROR_DISABLE_FORWARDING_ERROR;
- /**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_IFACE_CFG_ERROR}.
- * {@hide}
- */
- @Deprecated
- public static final int TETHER_ERROR_IFACE_CFG_ERROR =
- TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR;
- /**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_PROVISIONING_FAILED}.
- * {@hide}
- */
- @SystemApi
- @Deprecated
- public static final int TETHER_ERROR_PROVISION_FAILED = 11;
- /**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_DHCPSERVER_ERROR}.
- * {@hide}
- */
- @Deprecated
- public static final int TETHER_ERROR_DHCPSERVER_ERROR =
- TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR;
- /**
- * @deprecated Use {@link TetheringManager#TETHER_ERROR_ENTITLEMENT_UNKNOWN}.
- * {@hide}
- */
- @SystemApi
- @Deprecated
- public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13;
-
- /**
- * Get a more detailed error code after a Tethering or Untethering
- * request asynchronously failed.
- *
- * @param iface The name of the interface of interest
- * @return error The error code of the last error tethering or untethering the named
- * interface
- *
- * @deprecated Use {@link TetheringEventCallback#onError(String, int)} instead.
- * {@hide}
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @Deprecated
- public int getLastTetherError(String iface) {
- int error = mTetheringManager.getLastTetherError(iface);
- if (error == TetheringManager.TETHER_ERROR_UNKNOWN_TYPE) {
- // TETHER_ERROR_UNKNOWN_TYPE was introduced with TetheringManager and has never been
- // returned by ConnectivityManager. Convert it to the legacy TETHER_ERROR_UNKNOWN_IFACE
- // instead.
- error = TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
- }
- return error;
- }
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- TETHER_ERROR_NO_ERROR,
- TETHER_ERROR_PROVISION_FAILED,
- TETHER_ERROR_ENTITLEMENT_UNKONWN,
- })
- public @interface EntitlementResultCode {
- }
-
- /**
- * Callback for use with {@link #getLatestTetheringEntitlementResult} to find out whether
- * entitlement succeeded.
- *
- * @deprecated Use {@link TetheringManager#OnTetheringEntitlementResultListener} instead.
- * @hide
- */
- @SystemApi
- @Deprecated
- public interface OnTetheringEntitlementResultListener {
- /**
- * Called to notify entitlement result.
- *
- * @param resultCode an int value of entitlement result. It may be one of
- * {@link #TETHER_ERROR_NO_ERROR},
- * {@link #TETHER_ERROR_PROVISION_FAILED}, or
- * {@link #TETHER_ERROR_ENTITLEMENT_UNKONWN}.
- */
- void onTetheringEntitlementResult(@EntitlementResultCode int resultCode);
- }
-
- /**
- * Get the last value of the entitlement check on this downstream. If the cached value is
- * {@link #TETHER_ERROR_NO_ERROR} or showEntitlementUi argument is false, it just return the
- * cached value. Otherwise, a UI-based entitlement check would be performed. It is not
- * guaranteed that the UI-based entitlement check will complete in any specific time period
- * and may in fact never complete. Any successful entitlement check the platform performs for
- * any reason will update the cached value.
- *
- * @param type the downstream type of tethering. Must be one of
- * {@link #TETHERING_WIFI},
- * {@link #TETHERING_USB}, or
- * {@link #TETHERING_BLUETOOTH}.
- * @param showEntitlementUi a boolean indicating whether to run UI-based entitlement check.
- * @param executor the executor on which callback will be invoked.
- * @param listener an {@link OnTetheringEntitlementResultListener} which will be called to
- * notify the caller of the result of entitlement check. The listener may be called zero
- * or one time.
- * @deprecated Use {@link TetheringManager#requestLatestTetheringEntitlementResult} instead.
- * {@hide}
- */
- @SystemApi
- @Deprecated
- @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
- public void getLatestTetheringEntitlementResult(int type, boolean showEntitlementUi,
- @NonNull @CallbackExecutor Executor executor,
- @NonNull final OnTetheringEntitlementResultListener listener) {
- Objects.requireNonNull(listener, "TetheringEntitlementResultListener cannot be null.");
- ResultReceiver wrappedListener = new ResultReceiver(null) {
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- final long token = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> {
- listener.onTetheringEntitlementResult(resultCode);
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- };
-
- mTetheringManager.requestLatestTetheringEntitlementResult(type, wrappedListener,
- showEntitlementUi);
- }
-
- /**
- * Report network connectivity status. This is currently used only
- * to alter status bar UI.
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#STATUS_BAR}.
- *
- * @param networkType The type of network you want to report on
- * @param percentage The quality of the connection 0 is bad, 100 is good
- * @deprecated Types are deprecated. Use {@link #reportNetworkConnectivity} instead.
- * {@hide}
- */
- public void reportInetCondition(int networkType, int percentage) {
- printStackTrace();
- try {
- mService.reportInetCondition(networkType, percentage);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Report a problem network to the framework. This provides a hint to the system
- * that there might be connectivity problems on this network and may cause
- * the framework to re-evaluate network connectivity and/or switch to another
- * network.
- *
- * @param network The {@link Network} the application was attempting to use
- * or {@code null} to indicate the current default network.
- * @deprecated Use {@link #reportNetworkConnectivity} which allows reporting both
- * working and non-working connectivity.
- */
- @Deprecated
- public void reportBadNetwork(@Nullable Network network) {
- printStackTrace();
- try {
- // One of these will be ignored because it matches system's current state.
- // The other will trigger the necessary reevaluation.
- mService.reportNetworkConnectivity(network, true);
- mService.reportNetworkConnectivity(network, false);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Report to the framework whether a network has working connectivity.
- * This provides a hint to the system that a particular network is providing
- * working connectivity or not. In response the framework may re-evaluate
- * the network's connectivity and might take further action thereafter.
- *
- * @param network The {@link Network} the application was attempting to use
- * or {@code null} to indicate the current default network.
- * @param hasConnectivity {@code true} if the application was able to successfully access the
- * Internet using {@code network} or {@code false} if not.
- */
- public void reportNetworkConnectivity(@Nullable Network network, boolean hasConnectivity) {
- printStackTrace();
- try {
- mService.reportNetworkConnectivity(network, hasConnectivity);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Set a network-independent global HTTP proxy.
- *
- * This sets an HTTP proxy that applies to all networks and overrides any network-specific
- * proxy. If set, HTTP libraries that are proxy-aware will use this global proxy when
- * accessing any network, regardless of what the settings for that network are.
- *
- * Note that HTTP proxies are by nature typically network-dependent, and setting a global
- * proxy is likely to break networking on multiple networks. This method is only meant
- * for device policy clients looking to do general internal filtering or similar use cases.
- *
- * {@see #getGlobalProxy}
- * {@see LinkProperties#getHttpProxy}
- *
- * @param p A {@link ProxyInfo} object defining the new global HTTP proxy. Calling this
- * method with a {@code null} value will clear the global HTTP proxy.
- * @hide
- */
- // Used by Device Policy Manager to set the global proxy.
- @SystemApi(client = MODULE_LIBRARIES)
- @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- public void setGlobalProxy(@Nullable final ProxyInfo p) {
- try {
- mService.setGlobalProxy(p);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Retrieve any network-independent global HTTP proxy.
- *
- * @return {@link ProxyInfo} for the current global HTTP proxy or {@code null}
- * if no global HTTP proxy is set.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- @Nullable
- public ProxyInfo getGlobalProxy() {
- try {
- return mService.getGlobalProxy();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Retrieve the global HTTP proxy, or if no global HTTP proxy is set, a
- * network-specific HTTP proxy. If {@code network} is null, the
- * network-specific proxy returned is the proxy of the default active
- * network.
- *
- * @return {@link ProxyInfo} for the current global HTTP proxy, or if no
- * global HTTP proxy is set, {@code ProxyInfo} for {@code network},
- * or when {@code network} is {@code null},
- * the {@code ProxyInfo} for the default active network. Returns
- * {@code null} when no proxy applies or the caller doesn't have
- * permission to use {@code network}.
- * @hide
- */
- public ProxyInfo getProxyForNetwork(Network network) {
- try {
- return mService.getProxyForNetwork(network);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Get the current default HTTP proxy settings. If a global proxy is set it will be returned,
- * otherwise if this process is bound to a {@link Network} using
- * {@link #bindProcessToNetwork} then that {@code Network}'s proxy is returned, otherwise
- * the default network's proxy is returned.
- *
- * @return the {@link ProxyInfo} for the current HTTP proxy, or {@code null} if no
- * HTTP proxy is active.
- */
- @Nullable
- public ProxyInfo getDefaultProxy() {
- return getProxyForNetwork(getBoundNetworkForProcess());
- }
-
- /**
- * Returns true if the hardware supports the given network type
- * else it returns false. This doesn't indicate we have coverage
- * or are authorized onto a network, just whether or not the
- * hardware supports it. For example a GSM phone without a SIM
- * should still return {@code true} for mobile data, but a wifi only
- * tablet would return {@code false}.
- *
- * @param networkType The network type we'd like to check
- * @return {@code true} if supported, else {@code false}
- * @deprecated Types are deprecated. Use {@link NetworkCapabilities} instead.
- * @hide
- */
- @Deprecated
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
- public boolean isNetworkSupported(int networkType) {
- try {
- return mService.isNetworkSupported(networkType);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns if the currently active data network is metered. A network is
- * classified as metered when the user is sensitive to heavy data usage on
- * that connection due to monetary costs, data limitations or
- * battery/performance issues. You should check this before doing large
- * data transfers, and warn the user or delay the operation until another
- * network is available.
- *
- * @return {@code true} if large transfers should be avoided, otherwise
- * {@code false}.
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public boolean isActiveNetworkMetered() {
- try {
- return mService.isActiveNetworkMetered();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Set sign in error notification to visible or invisible
- *
- * @hide
- * @deprecated Doesn't properly deal with multiple connected networks of the same type.
- */
- @Deprecated
- public void setProvisioningNotificationVisible(boolean visible, int networkType,
- String action) {
- try {
- mService.setProvisioningNotificationVisible(visible, networkType, action);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Set the value for enabling/disabling airplane mode
- *
- * @param enable whether to enable airplane mode or not
- *
- * @hide
- */
- @RequiresPermission(anyOf = {
- android.Manifest.permission.NETWORK_AIRPLANE_MODE,
- android.Manifest.permission.NETWORK_SETTINGS,
- android.Manifest.permission.NETWORK_SETUP_WIZARD,
- android.Manifest.permission.NETWORK_STACK})
- @SystemApi
- public void setAirplaneMode(boolean enable) {
- try {
- mService.setAirplaneMode(enable);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Registers the specified {@link NetworkProvider}.
- * Each listener must only be registered once. The listener can be unregistered with
- * {@link #unregisterNetworkProvider}.
- *
- * @param provider the provider to register
- * @return the ID of the provider. This ID must be used by the provider when registering
- * {@link android.net.NetworkAgent}s.
- * @hide
- */
- @SystemApi
- @RequiresPermission(anyOf = {
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_FACTORY})
- public int registerNetworkProvider(@NonNull NetworkProvider provider) {
- if (provider.getProviderId() != NetworkProvider.ID_NONE) {
- throw new IllegalStateException("NetworkProviders can only be registered once");
- }
-
- try {
- int providerId = mService.registerNetworkProvider(provider.getMessenger(),
- provider.getName());
- provider.setProviderId(providerId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- return provider.getProviderId();
- }
-
- /**
- * Unregisters the specified NetworkProvider.
- *
- * @param provider the provider to unregister
- * @hide
- */
- @SystemApi
- @RequiresPermission(anyOf = {
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_FACTORY})
- public void unregisterNetworkProvider(@NonNull NetworkProvider provider) {
- try {
- mService.unregisterNetworkProvider(provider.getMessenger());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- provider.setProviderId(NetworkProvider.ID_NONE);
- }
-
- /**
- * Register or update a network offer with ConnectivityService.
- *
- * ConnectivityService keeps track of offers made by the various providers and matches
- * them to networking requests made by apps or the system. A callback identifies an offer
- * uniquely, and later calls with the same callback update the offer. The provider supplies a
- * score and the capabilities of the network it might be able to bring up ; these act as
- * filters used by ConnectivityService to only send those requests that can be fulfilled by the
- * provider.
- *
- * The provider is under no obligation to be able to bring up the network it offers at any
- * given time. Instead, this mechanism is meant to limit requests received by providers
- * to those they actually have a chance to fulfill, as providers don't have a way to compare
- * the quality of the network satisfying a given request to their own offer.
- *
- * An offer can be updated by calling this again with the same callback object. This is
- * similar to calling unofferNetwork and offerNetwork again, but will only update the
- * provider with the changes caused by the changes in the offer.
- *
- * @param provider The provider making this offer.
- * @param score The prospective score of the network.
- * @param caps The prospective capabilities of the network.
- * @param callback The callback to call when this offer is needed or unneeded.
- * @hide exposed via the NetworkProvider class.
- */
- @RequiresPermission(anyOf = {
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_FACTORY})
- public void offerNetwork(@NonNull final int providerId,
- @NonNull final NetworkScore score, @NonNull final NetworkCapabilities caps,
- @NonNull final INetworkOfferCallback callback) {
- try {
- mService.offerNetwork(providerId,
- Objects.requireNonNull(score, "null score"),
- Objects.requireNonNull(caps, "null caps"),
- Objects.requireNonNull(callback, "null callback"));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Withdraw a network offer made with {@link #offerNetwork}.
- *
- * @param callback The callback passed at registration time. This must be the same object
- * that was passed to {@link #offerNetwork}
- * @hide exposed via the NetworkProvider class.
- */
- public void unofferNetwork(@NonNull final INetworkOfferCallback callback) {
- try {
- mService.unofferNetwork(Objects.requireNonNull(callback));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- /** @hide exposed via the NetworkProvider class. */
- @RequiresPermission(anyOf = {
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_FACTORY})
- public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) {
- try {
- mService.declareNetworkRequestUnfulfillable(request);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * @hide
- * Register a NetworkAgent with ConnectivityService.
- * @return Network corresponding to NetworkAgent.
- */
- @RequiresPermission(anyOf = {
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_FACTORY})
- public Network registerNetworkAgent(INetworkAgent na, NetworkInfo ni, LinkProperties lp,
- NetworkCapabilities nc, @NonNull NetworkScore score, NetworkAgentConfig config,
- int providerId) {
- try {
- return mService.registerNetworkAgent(na, ni, lp, nc, score, config, providerId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Base class for {@code NetworkRequest} callbacks. Used for notifications about network
- * changes. Should be extended by applications wanting notifications.
- *
- * A {@code NetworkCallback} is registered by calling
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)},
- * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)},
- * or {@link #registerDefaultNetworkCallback(NetworkCallback)}. A {@code NetworkCallback} is
- * unregistered by calling {@link #unregisterNetworkCallback(NetworkCallback)}.
- * A {@code NetworkCallback} should be registered at most once at any time.
- * A {@code NetworkCallback} that has been unregistered can be registered again.
- */
- public static class NetworkCallback {
- /**
- * No flags associated with this callback.
- * @hide
- */
- public static final int FLAG_NONE = 0;
- /**
- * Use this flag to include any location sensitive data in {@link NetworkCapabilities} sent
- * via {@link #onCapabilitiesChanged(Network, NetworkCapabilities)}.
- * <p>
- * These include:
- * <li> Some transport info instances (retrieved via
- * {@link NetworkCapabilities#getTransportInfo()}) like {@link android.net.wifi.WifiInfo}
- * contain location sensitive information.
- * <li> OwnerUid (retrieved via {@link NetworkCapabilities#getOwnerUid()} is location
- * sensitive for wifi suggestor apps (i.e using {@link WifiNetworkSuggestion}).</li>
- * </p>
- * <p>
- * Note:
- * <li> Retrieving this location sensitive information (subject to app's location
- * permissions) will be noted by system. </li>
- * <li> Without this flag any {@link NetworkCapabilities} provided via the callback does
- * not include location sensitive info.
- * </p>
- */
- // Note: Some existing fields which are location sensitive may still be included without
- // this flag if the app targets SDK < S (to maintain backwards compatibility).
- public static final int FLAG_INCLUDE_LOCATION_INFO = 1 << 0;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, prefix = "FLAG_", value = {
- FLAG_NONE,
- FLAG_INCLUDE_LOCATION_INFO
- })
- public @interface Flag { }
-
- /**
- * All the valid flags for error checking.
- */
- private static final int VALID_FLAGS = FLAG_INCLUDE_LOCATION_INFO;
-
- public NetworkCallback() {
- this(FLAG_NONE);
- }
-
- public NetworkCallback(@Flag int flags) {
- if ((flags & VALID_FLAGS) != flags) {
- throw new IllegalArgumentException("Invalid flags");
- }
- mFlags = flags;
- }
-
- /**
- * Called when the framework connects to a new network to evaluate whether it satisfies this
- * request. If evaluation succeeds, this callback may be followed by an {@link #onAvailable}
- * callback. There is no guarantee that this new network will satisfy any requests, or that
- * the network will stay connected for longer than the time necessary to evaluate it.
- * <p>
- * Most applications <b>should not</b> act on this callback, and should instead use
- * {@link #onAvailable}. This callback is intended for use by applications that can assist
- * the framework in properly evaluating the network — for example, an application that
- * can automatically log in to a captive portal without user intervention.
- *
- * @param network The {@link Network} of the network that is being evaluated.
- *
- * @hide
- */
- public void onPreCheck(@NonNull Network network) {}
-
- /**
- * Called when the framework connects and has declared a new network ready for use.
- * This callback may be called more than once if the {@link Network} that is
- * satisfying the request changes.
- *
- * @param network The {@link Network} of the satisfying network.
- * @param networkCapabilities The {@link NetworkCapabilities} of the satisfying network.
- * @param linkProperties The {@link LinkProperties} of the satisfying network.
- * @param blocked Whether access to the {@link Network} is blocked due to system policy.
- * @hide
- */
- public final void onAvailable(@NonNull Network network,
- @NonNull NetworkCapabilities networkCapabilities,
- @NonNull LinkProperties linkProperties, @BlockedReason int blocked) {
- // Internally only this method is called when a new network is available, and
- // it calls the callback in the same way and order that older versions used
- // to call so as not to change the behavior.
- onAvailable(network, networkCapabilities, linkProperties, blocked != 0);
- onBlockedStatusChanged(network, blocked);
- }
-
- /**
- * Legacy variant of onAvailable that takes a boolean blocked reason.
- *
- * This method has never been public API, but it's not final, so there may be apps that
- * implemented it and rely on it being called. Do our best not to break them.
- * Note: such apps will also get a second call to onBlockedStatusChanged immediately after
- * this method is called. There does not seem to be a way to avoid this.
- * TODO: add a compat check to move apps off this method, and eventually stop calling it.
- *
- * @hide
- */
- public void onAvailable(@NonNull Network network,
- @NonNull NetworkCapabilities networkCapabilities,
- @NonNull LinkProperties linkProperties, boolean blocked) {
- onAvailable(network);
- if (!networkCapabilities.hasCapability(
- NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) {
- onNetworkSuspended(network);
- }
- onCapabilitiesChanged(network, networkCapabilities);
- onLinkPropertiesChanged(network, linkProperties);
- // No call to onBlockedStatusChanged here. That is done by the caller.
- }
-
- /**
- * Called when the framework connects and has declared a new network ready for use.
- *
- * <p>For callbacks registered with {@link #registerNetworkCallback}, multiple networks may
- * be available at the same time, and onAvailable will be called for each of these as they
- * appear.
- *
- * <p>For callbacks registered with {@link #requestNetwork} and
- * {@link #registerDefaultNetworkCallback}, this means the network passed as an argument
- * is the new best network for this request and is now tracked by this callback ; this
- * callback will no longer receive method calls about other networks that may have been
- * passed to this method previously. The previously-best network may have disconnected, or
- * it may still be around and the newly-best network may simply be better.
- *
- * <p>Starting with {@link android.os.Build.VERSION_CODES#O}, this will always immediately
- * be followed by a call to {@link #onCapabilitiesChanged(Network, NetworkCapabilities)}
- * then by a call to {@link #onLinkPropertiesChanged(Network, LinkProperties)}, and a call
- * to {@link #onBlockedStatusChanged(Network, boolean)}.
- *
- * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
- * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
- * this callback as this is prone to race conditions (there is no guarantee the objects
- * returned by these methods will be current). Instead, wait for a call to
- * {@link #onCapabilitiesChanged(Network, NetworkCapabilities)} and
- * {@link #onLinkPropertiesChanged(Network, LinkProperties)} whose arguments are guaranteed
- * to be well-ordered with respect to other callbacks.
- *
- * @param network The {@link Network} of the satisfying network.
- */
- public void onAvailable(@NonNull Network network) {}
-
- /**
- * Called when the network is about to be lost, typically because there are no outstanding
- * requests left for it. This may be paired with a {@link NetworkCallback#onAvailable} call
- * with the new replacement network for graceful handover. This method is not guaranteed
- * to be called before {@link NetworkCallback#onLost} is called, for example in case a
- * network is suddenly disconnected.
- *
- * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
- * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
- * this callback as this is prone to race conditions ; calling these methods while in a
- * callback may return an outdated or even a null object.
- *
- * @param network The {@link Network} that is about to be lost.
- * @param maxMsToLive The time in milliseconds the system intends to keep the network
- * connected for graceful handover; note that the network may still
- * suffer a hard loss at any time.
- */
- public void onLosing(@NonNull Network network, int maxMsToLive) {}
-
- /**
- * Called when a network disconnects or otherwise no longer satisfies this request or
- * callback.
- *
- * <p>If the callback was registered with requestNetwork() or
- * registerDefaultNetworkCallback(), it will only be invoked against the last network
- * returned by onAvailable() when that network is lost and no other network satisfies
- * the criteria of the request.
- *
- * <p>If the callback was registered with registerNetworkCallback() it will be called for
- * each network which no longer satisfies the criteria of the callback.
- *
- * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
- * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
- * this callback as this is prone to race conditions ; calling these methods while in a
- * callback may return an outdated or even a null object.
- *
- * @param network The {@link Network} lost.
- */
- public void onLost(@NonNull Network network) {}
-
- /**
- * Called if no network is found within the timeout time specified in
- * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} call or if the
- * requested network request cannot be fulfilled (whether or not a timeout was
- * specified). When this callback is invoked the associated
- * {@link NetworkRequest} will have already been removed and released, as if
- * {@link #unregisterNetworkCallback(NetworkCallback)} had been called.
- */
- public void onUnavailable() {}
-
- /**
- * Called when the network corresponding to this request changes capabilities but still
- * satisfies the requested criteria.
- *
- * <p>Starting with {@link android.os.Build.VERSION_CODES#O} this method is guaranteed
- * to be called immediately after {@link #onAvailable}.
- *
- * <p>Do NOT call {@link #getLinkProperties(Network)} or other synchronous
- * ConnectivityManager methods in this callback as this is prone to race conditions :
- * calling these methods while in a callback may return an outdated or even a null object.
- *
- * @param network The {@link Network} whose capabilities have changed.
- * @param networkCapabilities The new {@link NetworkCapabilities} for this
- * network.
- */
- public void onCapabilitiesChanged(@NonNull Network network,
- @NonNull NetworkCapabilities networkCapabilities) {}
-
- /**
- * Called when the network corresponding to this request changes {@link LinkProperties}.
- *
- * <p>Starting with {@link android.os.Build.VERSION_CODES#O} this method is guaranteed
- * to be called immediately after {@link #onAvailable}.
- *
- * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or other synchronous
- * ConnectivityManager methods in this callback as this is prone to race conditions :
- * calling these methods while in a callback may return an outdated or even a null object.
- *
- * @param network The {@link Network} whose link properties have changed.
- * @param linkProperties The new {@link LinkProperties} for this network.
- */
- public void onLinkPropertiesChanged(@NonNull Network network,
- @NonNull LinkProperties linkProperties) {}
-
- /**
- * Called when the network the framework connected to for this request suspends data
- * transmission temporarily.
- *
- * <p>This generally means that while the TCP connections are still live temporarily
- * network data fails to transfer. To give a specific example, this is used on cellular
- * networks to mask temporary outages when driving through a tunnel, etc. In general this
- * means read operations on sockets on this network will block once the buffers are
- * drained, and write operations will block once the buffers are full.
- *
- * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
- * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
- * this callback as this is prone to race conditions (there is no guarantee the objects
- * returned by these methods will be current).
- *
- * @hide
- */
- public void onNetworkSuspended(@NonNull Network network) {}
-
- /**
- * Called when the network the framework connected to for this request
- * returns from a {@link NetworkInfo.State#SUSPENDED} state. This should always be
- * preceded by a matching {@link NetworkCallback#onNetworkSuspended} call.
-
- * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
- * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
- * this callback as this is prone to race conditions : calling these methods while in a
- * callback may return an outdated or even a null object.
- *
- * @hide
- */
- public void onNetworkResumed(@NonNull Network network) {}
-
- /**
- * Called when access to the specified network is blocked or unblocked.
- *
- * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
- * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
- * this callback as this is prone to race conditions : calling these methods while in a
- * callback may return an outdated or even a null object.
- *
- * @param network The {@link Network} whose blocked status has changed.
- * @param blocked The blocked status of this {@link Network}.
- */
- public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {}
-
- /**
- * Called when access to the specified network is blocked or unblocked, or the reason for
- * access being blocked changes.
- *
- * If a NetworkCallback object implements this method,
- * {@link #onBlockedStatusChanged(Network, boolean)} will not be called.
- *
- * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
- * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
- * this callback as this is prone to race conditions : calling these methods while in a
- * callback may return an outdated or even a null object.
- *
- * @param network The {@link Network} whose blocked status has changed.
- * @param blocked The blocked status of this {@link Network}.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public void onBlockedStatusChanged(@NonNull Network network, @BlockedReason int blocked) {
- onBlockedStatusChanged(network, blocked != 0);
- }
-
- private NetworkRequest networkRequest;
- private final int mFlags;
- }
-
- /**
- * Constant error codes used by ConnectivityService to communicate about failures and errors
- * across a Binder boundary.
- * @hide
- */
- public interface Errors {
- int TOO_MANY_REQUESTS = 1;
- }
-
- /** @hide */
- public static class TooManyRequestsException extends RuntimeException {}
-
- private static RuntimeException convertServiceException(ServiceSpecificException e) {
- switch (e.errorCode) {
- case Errors.TOO_MANY_REQUESTS:
- return new TooManyRequestsException();
- default:
- Log.w(TAG, "Unknown service error code " + e.errorCode);
- return new RuntimeException(e);
- }
- }
-
- /** @hide */
- public static final int CALLBACK_PRECHECK = 1;
- /** @hide */
- public static final int CALLBACK_AVAILABLE = 2;
- /** @hide arg1 = TTL */
- public static final int CALLBACK_LOSING = 3;
- /** @hide */
- public static final int CALLBACK_LOST = 4;
- /** @hide */
- public static final int CALLBACK_UNAVAIL = 5;
- /** @hide */
- public static final int CALLBACK_CAP_CHANGED = 6;
- /** @hide */
- public static final int CALLBACK_IP_CHANGED = 7;
- /** @hide obj = NetworkCapabilities, arg1 = seq number */
- private static final int EXPIRE_LEGACY_REQUEST = 8;
- /** @hide */
- public static final int CALLBACK_SUSPENDED = 9;
- /** @hide */
- public static final int CALLBACK_RESUMED = 10;
- /** @hide */
- public static final int CALLBACK_BLK_CHANGED = 11;
-
- /** @hide */
- public static String getCallbackName(int whichCallback) {
- switch (whichCallback) {
- case CALLBACK_PRECHECK: return "CALLBACK_PRECHECK";
- case CALLBACK_AVAILABLE: return "CALLBACK_AVAILABLE";
- case CALLBACK_LOSING: return "CALLBACK_LOSING";
- case CALLBACK_LOST: return "CALLBACK_LOST";
- case CALLBACK_UNAVAIL: return "CALLBACK_UNAVAIL";
- case CALLBACK_CAP_CHANGED: return "CALLBACK_CAP_CHANGED";
- case CALLBACK_IP_CHANGED: return "CALLBACK_IP_CHANGED";
- case EXPIRE_LEGACY_REQUEST: return "EXPIRE_LEGACY_REQUEST";
- case CALLBACK_SUSPENDED: return "CALLBACK_SUSPENDED";
- case CALLBACK_RESUMED: return "CALLBACK_RESUMED";
- case CALLBACK_BLK_CHANGED: return "CALLBACK_BLK_CHANGED";
- default:
- return Integer.toString(whichCallback);
- }
- }
-
- private class CallbackHandler extends Handler {
- private static final String TAG = "ConnectivityManager.CallbackHandler";
- private static final boolean DBG = false;
-
- CallbackHandler(Looper looper) {
- super(looper);
- }
-
- CallbackHandler(Handler handler) {
- this(Objects.requireNonNull(handler, "Handler cannot be null.").getLooper());
- }
-
- @Override
- public void handleMessage(Message message) {
- if (message.what == EXPIRE_LEGACY_REQUEST) {
- expireRequest((NetworkCapabilities) message.obj, message.arg1);
- return;
- }
-
- final NetworkRequest request = getObject(message, NetworkRequest.class);
- final Network network = getObject(message, Network.class);
- final NetworkCallback callback;
- synchronized (sCallbacks) {
- callback = sCallbacks.get(request);
- if (callback == null) {
- Log.w(TAG,
- "callback not found for " + getCallbackName(message.what) + " message");
- return;
- }
- if (message.what == CALLBACK_UNAVAIL) {
- sCallbacks.remove(request);
- callback.networkRequest = ALREADY_UNREGISTERED;
- }
- }
- if (DBG) {
- Log.d(TAG, getCallbackName(message.what) + " for network " + network);
- }
-
- switch (message.what) {
- case CALLBACK_PRECHECK: {
- callback.onPreCheck(network);
- break;
- }
- case CALLBACK_AVAILABLE: {
- NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);
- LinkProperties lp = getObject(message, LinkProperties.class);
- callback.onAvailable(network, cap, lp, message.arg1);
- break;
- }
- case CALLBACK_LOSING: {
- callback.onLosing(network, message.arg1);
- break;
- }
- case CALLBACK_LOST: {
- callback.onLost(network);
- break;
- }
- case CALLBACK_UNAVAIL: {
- callback.onUnavailable();
- break;
- }
- case CALLBACK_CAP_CHANGED: {
- NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);
- callback.onCapabilitiesChanged(network, cap);
- break;
- }
- case CALLBACK_IP_CHANGED: {
- LinkProperties lp = getObject(message, LinkProperties.class);
- callback.onLinkPropertiesChanged(network, lp);
- break;
- }
- case CALLBACK_SUSPENDED: {
- callback.onNetworkSuspended(network);
- break;
- }
- case CALLBACK_RESUMED: {
- callback.onNetworkResumed(network);
- break;
- }
- case CALLBACK_BLK_CHANGED: {
- callback.onBlockedStatusChanged(network, message.arg1);
- }
- }
- }
-
- private <T> T getObject(Message msg, Class<T> c) {
- return (T) msg.getData().getParcelable(c.getSimpleName());
- }
- }
-
- private CallbackHandler getDefaultHandler() {
- synchronized (sCallbacks) {
- if (sCallbackHandler == null) {
- sCallbackHandler = new CallbackHandler(ConnectivityThread.getInstanceLooper());
- }
- return sCallbackHandler;
- }
- }
-
- private static final HashMap<NetworkRequest, NetworkCallback> sCallbacks = new HashMap<>();
- private static CallbackHandler sCallbackHandler;
-
- private NetworkRequest sendRequestForNetwork(int asUid, NetworkCapabilities need,
- NetworkCallback callback, int timeoutMs, NetworkRequest.Type reqType, int legacyType,
- CallbackHandler handler) {
- printStackTrace();
- checkCallbackNotNull(callback);
- if (reqType != TRACK_DEFAULT && reqType != TRACK_SYSTEM_DEFAULT && need == null) {
- throw new IllegalArgumentException("null NetworkCapabilities");
- }
- final NetworkRequest request;
- final String callingPackageName = mContext.getOpPackageName();
- try {
- synchronized(sCallbacks) {
- if (callback.networkRequest != null
- && callback.networkRequest != ALREADY_UNREGISTERED) {
- // TODO: throw exception instead and enforce 1:1 mapping of callbacks
- // and requests (http://b/20701525).
- Log.e(TAG, "NetworkCallback was already registered");
- }
- Messenger messenger = new Messenger(handler);
- Binder binder = new Binder();
- final int callbackFlags = callback.mFlags;
- if (reqType == LISTEN) {
- request = mService.listenForNetwork(
- need, messenger, binder, callbackFlags, callingPackageName,
- getAttributionTag());
- } else {
- request = mService.requestNetwork(
- asUid, need, reqType.ordinal(), messenger, timeoutMs, binder,
- legacyType, callbackFlags, callingPackageName, getAttributionTag());
- }
- if (request != null) {
- sCallbacks.put(request, callback);
- }
- callback.networkRequest = request;
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- } catch (ServiceSpecificException e) {
- throw convertServiceException(e);
- }
- return request;
- }
-
- private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
- int timeoutMs, NetworkRequest.Type reqType, int legacyType, CallbackHandler handler) {
- return sendRequestForNetwork(Process.INVALID_UID, need, callback, timeoutMs, reqType,
- legacyType, handler);
- }
-
- /**
- * Helper function to request a network with a particular legacy type.
- *
- * This API is only for use in internal system code that requests networks with legacy type and
- * relies on CONNECTIVITY_ACTION broadcasts instead of NetworkCallbacks. New caller should use
- * {@link #requestNetwork(NetworkRequest, NetworkCallback, Handler)} instead.
- *
- * @param request {@link NetworkRequest} describing this request.
- * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
- * before {@link NetworkCallback#onUnavailable()} is called. The timeout must
- * be a positive value (i.e. >0).
- * @param legacyType to specify the network type(#TYPE_*).
- * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
- * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
- * the callback must not be shared - it uniquely specifies this request.
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
- public void requestNetwork(@NonNull NetworkRequest request,
- int timeoutMs, int legacyType, @NonNull Handler handler,
- @NonNull NetworkCallback networkCallback) {
- if (legacyType == TYPE_NONE) {
- throw new IllegalArgumentException("TYPE_NONE is meaningless legacy type");
- }
- CallbackHandler cbHandler = new CallbackHandler(handler);
- NetworkCapabilities nc = request.networkCapabilities;
- sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, legacyType, cbHandler);
- }
-
- /**
- * Request a network to satisfy a set of {@link NetworkCapabilities}.
- *
- * <p>This method will attempt to find the best network that matches the passed
- * {@link NetworkRequest}, and to bring up one that does if none currently satisfies the
- * criteria. The platform will evaluate which network is the best at its own discretion.
- * Throughput, latency, cost per byte, policy, user preference and other considerations
- * may be factored in the decision of what is considered the best network.
- *
- * <p>As long as this request is outstanding, the platform will try to maintain the best network
- * matching this request, while always attempting to match the request to a better network if
- * possible. If a better match is found, the platform will switch this request to the now-best
- * network and inform the app of the newly best network by invoking
- * {@link NetworkCallback#onAvailable(Network)} on the provided callback. Note that the platform
- * will not try to maintain any other network than the best one currently matching the request:
- * a network not matching any network request may be disconnected at any time.
- *
- * <p>For example, an application could use this method to obtain a connected cellular network
- * even if the device currently has a data connection over Ethernet. This may cause the cellular
- * radio to consume additional power. Or, an application could inform the system that it wants
- * a network supporting sending MMSes and have the system let it know about the currently best
- * MMS-supporting network through the provided {@link NetworkCallback}.
- *
- * <p>The status of the request can be followed by listening to the various callbacks described
- * in {@link NetworkCallback}. The {@link Network} object passed to the callback methods can be
- * used to direct traffic to the network (although accessing some networks may be subject to
- * holding specific permissions). Callers will learn about the specific characteristics of the
- * network through
- * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} and
- * {@link NetworkCallback#onLinkPropertiesChanged(Network, LinkProperties)}. The methods of the
- * provided {@link NetworkCallback} will only be invoked due to changes in the best network
- * matching the request at any given time; therefore when a better network matching the request
- * becomes available, the {@link NetworkCallback#onAvailable(Network)} method is called
- * with the new network after which no further updates are given about the previously-best
- * network, unless it becomes the best again at some later time. All callbacks are invoked
- * in order on the same thread, which by default is a thread created by the framework running
- * in the app.
- * {@see #requestNetwork(NetworkRequest, NetworkCallback, Handler)} to change where the
- * callbacks are invoked.
- *
- * <p>This{@link NetworkRequest} will live until released via
- * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits, at
- * which point the system may let go of the network at any time.
- *
- * <p>A version of this method which takes a timeout is
- * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)}, that an app can use to only
- * wait for a limited amount of time for the network to become unavailable.
- *
- * <p>It is presently unsupported to request a network with mutable
- * {@link NetworkCapabilities} such as
- * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
- * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}
- * as these {@code NetworkCapabilities} represent states that a particular
- * network may never attain, and whether a network will attain these states
- * is unknown prior to bringing up the network so the framework does not
- * know how to go about satisfying a request with these capabilities.
- *
- * <p>This method requires the caller to hold either the
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
- * or the ability to modify system settings as determined by
- * {@link android.provider.Settings.System#canWrite}.</p>
- *
- * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
- * number of outstanding requests to 100 per app (identified by their UID), shared with
- * all variants of this method, of {@link #registerNetworkCallback} as well as
- * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
- * Requesting a network with this method will count toward this limit. If this limit is
- * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
- * make sure to unregister the callbacks with
- * {@link #unregisterNetworkCallback(NetworkCallback)}.
- *
- * @param request {@link NetworkRequest} describing this request.
- * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
- * the callback must not be shared - it uniquely specifies this request.
- * The callback is invoked on the default internal Handler.
- * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
- * @throws SecurityException if missing the appropriate permissions.
- * @throws RuntimeException if the app already has too many callbacks registered.
- */
- public void requestNetwork(@NonNull NetworkRequest request,
- @NonNull NetworkCallback networkCallback) {
- requestNetwork(request, networkCallback, getDefaultHandler());
- }
-
- /**
- * Request a network to satisfy a set of {@link NetworkCapabilities}.
- *
- * This method behaves identically to {@link #requestNetwork(NetworkRequest, NetworkCallback)}
- * but runs all the callbacks on the passed Handler.
- *
- * <p>This method has the same permission requirements as
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, is subject to the same limitations,
- * and throws the same exceptions in the same conditions.
- *
- * @param request {@link NetworkRequest} describing this request.
- * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
- * the callback must not be shared - it uniquely specifies this request.
- * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
- */
- public void requestNetwork(@NonNull NetworkRequest request,
- @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
- CallbackHandler cbHandler = new CallbackHandler(handler);
- NetworkCapabilities nc = request.networkCapabilities;
- sendRequestForNetwork(nc, networkCallback, 0, REQUEST, TYPE_NONE, cbHandler);
- }
-
- /**
- * Request a network to satisfy a set of {@link NetworkCapabilities}, limited
- * by a timeout.
- *
- * This function behaves identically to the non-timed-out version
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, but if a suitable network
- * is not found within the given time (in milliseconds) the
- * {@link NetworkCallback#onUnavailable()} callback is called. The request can still be
- * released normally by calling {@link #unregisterNetworkCallback(NetworkCallback)} but does
- * not have to be released if timed-out (it is automatically released). Unregistering a
- * request that timed out is not an error.
- *
- * <p>Do not use this method to poll for the existence of specific networks (e.g. with a small
- * timeout) - {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} is provided
- * for that purpose. Calling this method will attempt to bring up the requested network.
- *
- * <p>This method has the same permission requirements as
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, is subject to the same limitations,
- * and throws the same exceptions in the same conditions.
- *
- * @param request {@link NetworkRequest} describing this request.
- * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
- * the callback must not be shared - it uniquely specifies this request.
- * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
- * before {@link NetworkCallback#onUnavailable()} is called. The timeout must
- * be a positive value (i.e. >0).
- */
- public void requestNetwork(@NonNull NetworkRequest request,
- @NonNull NetworkCallback networkCallback, int timeoutMs) {
- checkTimeout(timeoutMs);
- NetworkCapabilities nc = request.networkCapabilities;
- sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, TYPE_NONE,
- getDefaultHandler());
- }
-
- /**
- * Request a network to satisfy a set of {@link NetworkCapabilities}, limited
- * by a timeout.
- *
- * This method behaves identically to
- * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} but runs all the callbacks
- * on the passed Handler.
- *
- * <p>This method has the same permission requirements as
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, is subject to the same limitations,
- * and throws the same exceptions in the same conditions.
- *
- * @param request {@link NetworkRequest} describing this request.
- * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
- * the callback must not be shared - it uniquely specifies this request.
- * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
- * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
- * before {@link NetworkCallback#onUnavailable} is called.
- */
- public void requestNetwork(@NonNull NetworkRequest request,
- @NonNull NetworkCallback networkCallback, @NonNull Handler handler, int timeoutMs) {
- checkTimeout(timeoutMs);
- CallbackHandler cbHandler = new CallbackHandler(handler);
- NetworkCapabilities nc = request.networkCapabilities;
- sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, TYPE_NONE, cbHandler);
- }
-
- /**
- * The lookup key for a {@link Network} object included with the intent after
- * successfully finding a network for the applications request. Retrieve it with
- * {@link android.content.Intent#getParcelableExtra(String)}.
- * <p>
- * Note that if you intend to invoke {@link Network#openConnection(java.net.URL)}
- * then you must get a ConnectivityManager instance before doing so.
- */
- public static final String EXTRA_NETWORK = "android.net.extra.NETWORK";
-
- /**
- * The lookup key for a {@link NetworkRequest} object included with the intent after
- * successfully finding a network for the applications request. Retrieve it with
- * {@link android.content.Intent#getParcelableExtra(String)}.
- */
- public static final String EXTRA_NETWORK_REQUEST = "android.net.extra.NETWORK_REQUEST";
-
-
- /**
- * Request a network to satisfy a set of {@link NetworkCapabilities}.
- *
- * This function behaves identically to the version that takes a NetworkCallback, but instead
- * of {@link NetworkCallback} a {@link PendingIntent} is used. This means
- * the request may outlive the calling application and get called back when a suitable
- * network is found.
- * <p>
- * The operation is an Intent broadcast that goes to a broadcast receiver that
- * you registered with {@link Context#registerReceiver} or through the
- * <receiver> tag in an AndroidManifest.xml file
- * <p>
- * The operation Intent is delivered with two extras, a {@link Network} typed
- * extra called {@link #EXTRA_NETWORK} and a {@link NetworkRequest}
- * typed extra called {@link #EXTRA_NETWORK_REQUEST} containing
- * the original requests parameters. It is important to create a new,
- * {@link NetworkCallback} based request before completing the processing of the
- * Intent to reserve the network or it will be released shortly after the Intent
- * is processed.
- * <p>
- * If there is already a request for this Intent registered (with the equality of
- * two Intents defined by {@link Intent#filterEquals}), then it will be removed and
- * replaced by this one, effectively releasing the previous {@link NetworkRequest}.
- * <p>
- * The request may be released normally by calling
- * {@link #releaseNetworkRequest(android.app.PendingIntent)}.
- * <p>It is presently unsupported to request a network with either
- * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
- * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}
- * as these {@code NetworkCapabilities} represent states that a particular
- * network may never attain, and whether a network will attain these states
- * is unknown prior to bringing up the network so the framework does not
- * know how to go about satisfying a request with these capabilities.
- *
- * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
- * number of outstanding requests to 100 per app (identified by their UID), shared with
- * all variants of this method, of {@link #registerNetworkCallback} as well as
- * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
- * Requesting a network with this method will count toward this limit. If this limit is
- * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
- * make sure to unregister the callbacks with {@link #unregisterNetworkCallback(PendingIntent)}
- * or {@link #releaseNetworkRequest(PendingIntent)}.
- *
- * <p>This method requires the caller to hold either the
- * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
- * or the ability to modify system settings as determined by
- * {@link android.provider.Settings.System#canWrite}.</p>
- *
- * @param request {@link NetworkRequest} describing this request.
- * @param operation Action to perform when the network is available (corresponds
- * to the {@link NetworkCallback#onAvailable} call. Typically
- * comes from {@link PendingIntent#getBroadcast}. Cannot be null.
- * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
- * @throws SecurityException if missing the appropriate permissions.
- * @throws RuntimeException if the app already has too many callbacks registered.
- */
- public void requestNetwork(@NonNull NetworkRequest request,
- @NonNull PendingIntent operation) {
- printStackTrace();
- checkPendingIntentNotNull(operation);
- try {
- mService.pendingRequestForNetwork(
- request.networkCapabilities, operation, mContext.getOpPackageName(),
- getAttributionTag());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- } catch (ServiceSpecificException e) {
- throw convertServiceException(e);
- }
- }
-
- /**
- * Removes a request made via {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)}
- * <p>
- * This method has the same behavior as
- * {@link #unregisterNetworkCallback(android.app.PendingIntent)} with respect to
- * releasing network resources and disconnecting.
- *
- * @param operation A PendingIntent equal (as defined by {@link Intent#filterEquals}) to the
- * PendingIntent passed to
- * {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)} with the
- * corresponding NetworkRequest you'd like to remove. Cannot be null.
- */
- public void releaseNetworkRequest(@NonNull PendingIntent operation) {
- printStackTrace();
- checkPendingIntentNotNull(operation);
- try {
- mService.releasePendingNetworkRequest(operation);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- private static void checkPendingIntentNotNull(PendingIntent intent) {
- Objects.requireNonNull(intent, "PendingIntent cannot be null.");
- }
-
- private static void checkCallbackNotNull(NetworkCallback callback) {
- Objects.requireNonNull(callback, "null NetworkCallback");
- }
-
- private static void checkTimeout(int timeoutMs) {
- if (timeoutMs <= 0) {
- throw new IllegalArgumentException("timeoutMs must be strictly positive.");
- }
- }
-
- /**
- * Registers to receive notifications about all networks which satisfy the given
- * {@link NetworkRequest}. The callbacks will continue to be called until
- * either the application exits or {@link #unregisterNetworkCallback(NetworkCallback)} is
- * called.
- *
- * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
- * number of outstanding requests to 100 per app (identified by their UID), shared with
- * all variants of this method, of {@link #requestNetwork} as well as
- * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
- * Requesting a network with this method will count toward this limit. If this limit is
- * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
- * make sure to unregister the callbacks with
- * {@link #unregisterNetworkCallback(NetworkCallback)}.
- *
- * @param request {@link NetworkRequest} describing this request.
- * @param networkCallback The {@link NetworkCallback} that the system will call as suitable
- * networks change state.
- * The callback is invoked on the default internal Handler.
- * @throws RuntimeException if the app already has too many callbacks registered.
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public void registerNetworkCallback(@NonNull NetworkRequest request,
- @NonNull NetworkCallback networkCallback) {
- registerNetworkCallback(request, networkCallback, getDefaultHandler());
- }
-
- /**
- * Registers to receive notifications about all networks which satisfy the given
- * {@link NetworkRequest}. The callbacks will continue to be called until
- * either the application exits or {@link #unregisterNetworkCallback(NetworkCallback)} is
- * called.
- *
- * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
- * number of outstanding requests to 100 per app (identified by their UID), shared with
- * all variants of this method, of {@link #requestNetwork} as well as
- * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
- * Requesting a network with this method will count toward this limit. If this limit is
- * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
- * make sure to unregister the callbacks with
- * {@link #unregisterNetworkCallback(NetworkCallback)}.
- *
- *
- * @param request {@link NetworkRequest} describing this request.
- * @param networkCallback The {@link NetworkCallback} that the system will call as suitable
- * networks change state.
- * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
- * @throws RuntimeException if the app already has too many callbacks registered.
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public void registerNetworkCallback(@NonNull NetworkRequest request,
- @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
- CallbackHandler cbHandler = new CallbackHandler(handler);
- NetworkCapabilities nc = request.networkCapabilities;
- sendRequestForNetwork(nc, networkCallback, 0, LISTEN, TYPE_NONE, cbHandler);
- }
-
- /**
- * Registers a PendingIntent to be sent when a network is available which satisfies the given
- * {@link NetworkRequest}.
- *
- * This function behaves identically to the version that takes a NetworkCallback, but instead
- * of {@link NetworkCallback} a {@link PendingIntent} is used. This means
- * the request may outlive the calling application and get called back when a suitable
- * network is found.
- * <p>
- * The operation is an Intent broadcast that goes to a broadcast receiver that
- * you registered with {@link Context#registerReceiver} or through the
- * <receiver> tag in an AndroidManifest.xml file
- * <p>
- * The operation Intent is delivered with two extras, a {@link Network} typed
- * extra called {@link #EXTRA_NETWORK} and a {@link NetworkRequest}
- * typed extra called {@link #EXTRA_NETWORK_REQUEST} containing
- * the original requests parameters.
- * <p>
- * If there is already a request for this Intent registered (with the equality of
- * two Intents defined by {@link Intent#filterEquals}), then it will be removed and
- * replaced by this one, effectively releasing the previous {@link NetworkRequest}.
- * <p>
- * The request may be released normally by calling
- * {@link #unregisterNetworkCallback(android.app.PendingIntent)}.
- *
- * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
- * number of outstanding requests to 100 per app (identified by their UID), shared with
- * all variants of this method, of {@link #requestNetwork} as well as
- * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
- * Requesting a network with this method will count toward this limit. If this limit is
- * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
- * make sure to unregister the callbacks with {@link #unregisterNetworkCallback(PendingIntent)}
- * or {@link #releaseNetworkRequest(PendingIntent)}.
- *
- * @param request {@link NetworkRequest} describing this request.
- * @param operation Action to perform when the network is available (corresponds
- * to the {@link NetworkCallback#onAvailable} call. Typically
- * comes from {@link PendingIntent#getBroadcast}. Cannot be null.
- * @throws RuntimeException if the app already has too many callbacks registered.
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public void registerNetworkCallback(@NonNull NetworkRequest request,
- @NonNull PendingIntent operation) {
- printStackTrace();
- checkPendingIntentNotNull(operation);
- try {
- mService.pendingListenForNetwork(
- request.networkCapabilities, operation, mContext.getOpPackageName(),
- getAttributionTag());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- } catch (ServiceSpecificException e) {
- throw convertServiceException(e);
- }
- }
-
- /**
- * Registers to receive notifications about changes in the application's default network. This
- * may be a physical network or a virtual network, such as a VPN that applies to the
- * application. The callbacks will continue to be called until either the application exits or
- * {@link #unregisterNetworkCallback(NetworkCallback)} is called.
- *
- * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
- * number of outstanding requests to 100 per app (identified by their UID), shared with
- * all variants of this method, of {@link #requestNetwork} as well as
- * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
- * Requesting a network with this method will count toward this limit. If this limit is
- * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
- * make sure to unregister the callbacks with
- * {@link #unregisterNetworkCallback(NetworkCallback)}.
- *
- * @param networkCallback The {@link NetworkCallback} that the system will call as the
- * application's default network changes.
- * The callback is invoked on the default internal Handler.
- * @throws RuntimeException if the app already has too many callbacks registered.
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback) {
- registerDefaultNetworkCallback(networkCallback, getDefaultHandler());
- }
-
- /**
- * Registers to receive notifications about changes in the application's default network. This
- * may be a physical network or a virtual network, such as a VPN that applies to the
- * application. The callbacks will continue to be called until either the application exits or
- * {@link #unregisterNetworkCallback(NetworkCallback)} is called.
- *
- * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
- * number of outstanding requests to 100 per app (identified by their UID), shared with
- * all variants of this method, of {@link #requestNetwork} as well as
- * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
- * Requesting a network with this method will count toward this limit. If this limit is
- * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
- * make sure to unregister the callbacks with
- * {@link #unregisterNetworkCallback(NetworkCallback)}.
- *
- * @param networkCallback The {@link NetworkCallback} that the system will call as the
- * application's default network changes.
- * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
- * @throws RuntimeException if the app already has too many callbacks registered.
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
- @NonNull Handler handler) {
- registerDefaultNetworkCallbackForUid(Process.INVALID_UID, networkCallback, handler);
- }
-
- /**
- * Registers to receive notifications about changes in the default network for the specified
- * UID. This may be a physical network or a virtual network, such as a VPN that applies to the
- * UID. The callbacks will continue to be called until either the application exits or
- * {@link #unregisterNetworkCallback(NetworkCallback)} is called.
- *
- * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
- * number of outstanding requests to 100 per app (identified by their UID), shared with
- * all variants of this method, of {@link #requestNetwork} as well as
- * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
- * Requesting a network with this method will count toward this limit. If this limit is
- * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
- * make sure to unregister the callbacks with
- * {@link #unregisterNetworkCallback(NetworkCallback)}.
- *
- * @param uid the UID for which to track default network changes.
- * @param networkCallback The {@link NetworkCallback} that the system will call as the
- * UID's default network changes.
- * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
- * @throws RuntimeException if the app already has too many callbacks registered.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- @SuppressLint({"ExecutorRegistration", "PairedRegistration"})
- @RequiresPermission(anyOf = {
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_SETTINGS})
- public void registerDefaultNetworkCallbackForUid(int uid,
- @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
- CallbackHandler cbHandler = new CallbackHandler(handler);
- sendRequestForNetwork(uid, null /* need */, networkCallback, 0 /* timeoutMs */,
- TRACK_DEFAULT, TYPE_NONE, cbHandler);
- }
-
- /**
- * Registers to receive notifications about changes in the system default network. The callbacks
- * will continue to be called until either the application exits or
- * {@link #unregisterNetworkCallback(NetworkCallback)} is called.
- *
- * This method should not be used to determine networking state seen by applications, because in
- * many cases, most or even all application traffic may not use the default network directly,
- * and traffic from different applications may go on different networks by default. As an
- * example, if a VPN is connected, traffic from all applications might be sent through the VPN
- * and not onto the system default network. Applications or system components desiring to do
- * determine network state as seen by applications should use other methods such as
- * {@link #registerDefaultNetworkCallback(NetworkCallback, Handler)}.
- *
- * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
- * number of outstanding requests to 100 per app (identified by their UID), shared with
- * all variants of this method, of {@link #requestNetwork} as well as
- * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
- * Requesting a network with this method will count toward this limit. If this limit is
- * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
- * make sure to unregister the callbacks with
- * {@link #unregisterNetworkCallback(NetworkCallback)}.
- *
- * @param networkCallback The {@link NetworkCallback} that the system will call as the
- * system default network changes.
- * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
- * @throws RuntimeException if the app already has too many callbacks registered.
- *
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- @SuppressLint({"ExecutorRegistration", "PairedRegistration"})
- @RequiresPermission(anyOf = {
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_SETTINGS})
- public void registerSystemDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
- @NonNull Handler handler) {
- CallbackHandler cbHandler = new CallbackHandler(handler);
- sendRequestForNetwork(null /* NetworkCapabilities need */, networkCallback, 0,
- TRACK_SYSTEM_DEFAULT, TYPE_NONE, cbHandler);
- }
-
- /**
- * Registers to receive notifications about the best matching network which satisfy the given
- * {@link NetworkRequest}. The callbacks will continue to be called until
- * either the application exits or {@link #unregisterNetworkCallback(NetworkCallback)} is
- * called.
- *
- * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
- * number of outstanding requests to 100 per app (identified by their UID), shared with
- * {@link #registerNetworkCallback} and its variants and {@link #requestNetwork} as well as
- * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
- * Requesting a network with this method will count toward this limit. If this limit is
- * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
- * make sure to unregister the callbacks with
- * {@link #unregisterNetworkCallback(NetworkCallback)}.
- *
- *
- * @param request {@link NetworkRequest} describing this request.
- * @param networkCallback The {@link NetworkCallback} that the system will call as suitable
- * networks change state.
- * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
- * @throws RuntimeException if the app already has too many callbacks registered.
- */
- @SuppressLint("ExecutorRegistration")
- public void registerBestMatchingNetworkCallback(@NonNull NetworkRequest request,
- @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
- final NetworkCapabilities nc = request.networkCapabilities;
- final CallbackHandler cbHandler = new CallbackHandler(handler);
- sendRequestForNetwork(nc, networkCallback, 0, LISTEN_FOR_BEST, TYPE_NONE, cbHandler);
- }
-
- /**
- * Requests bandwidth update for a given {@link Network} and returns whether the update request
- * is accepted by ConnectivityService. Once accepted, ConnectivityService will poll underlying
- * network connection for updated bandwidth information. The caller will be notified via
- * {@link ConnectivityManager.NetworkCallback} if there is an update. Notice that this
- * method assumes that the caller has previously called
- * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} to listen for network
- * changes.
- *
- * @param network {@link Network} specifying which network you're interested.
- * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid.
- */
- public boolean requestBandwidthUpdate(@NonNull Network network) {
- try {
- return mService.requestBandwidthUpdate(network);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Unregisters a {@code NetworkCallback} and possibly releases networks originating from
- * {@link #requestNetwork(NetworkRequest, NetworkCallback)} and
- * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} calls.
- * If the given {@code NetworkCallback} had previously been used with
- * {@code #requestNetwork}, any networks that had been connected to only to satisfy that request
- * will be disconnected.
- *
- * Notifications that would have triggered that {@code NetworkCallback} will immediately stop
- * triggering it as soon as this call returns.
- *
- * @param networkCallback The {@link NetworkCallback} used when making the request.
- */
- public void unregisterNetworkCallback(@NonNull NetworkCallback networkCallback) {
- printStackTrace();
- checkCallbackNotNull(networkCallback);
- final List<NetworkRequest> reqs = new ArrayList<>();
- // Find all requests associated to this callback and stop callback triggers immediately.
- // Callback is reusable immediately. http://b/20701525, http://b/35921499.
- synchronized (sCallbacks) {
- if (networkCallback.networkRequest == null) {
- throw new IllegalArgumentException("NetworkCallback was not registered");
- }
- if (networkCallback.networkRequest == ALREADY_UNREGISTERED) {
- Log.d(TAG, "NetworkCallback was already unregistered");
- return;
- }
- for (Map.Entry<NetworkRequest, NetworkCallback> e : sCallbacks.entrySet()) {
- if (e.getValue() == networkCallback) {
- reqs.add(e.getKey());
- }
- }
- // TODO: throw exception if callback was registered more than once (http://b/20701525).
- for (NetworkRequest r : reqs) {
- try {
- mService.releaseNetworkRequest(r);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- // Only remove mapping if rpc was successful.
- sCallbacks.remove(r);
- }
- networkCallback.networkRequest = ALREADY_UNREGISTERED;
- }
- }
-
- /**
- * Unregisters a callback previously registered via
- * {@link #registerNetworkCallback(NetworkRequest, android.app.PendingIntent)}.
- *
- * @param operation A PendingIntent equal (as defined by {@link Intent#filterEquals}) to the
- * PendingIntent passed to
- * {@link #registerNetworkCallback(NetworkRequest, android.app.PendingIntent)}.
- * Cannot be null.
- */
- public void unregisterNetworkCallback(@NonNull PendingIntent operation) {
- releaseNetworkRequest(operation);
- }
-
- /**
- * Informs the system whether it should switch to {@code network} regardless of whether it is
- * validated or not. If {@code accept} is true, and the network was explicitly selected by the
- * user (e.g., by selecting a Wi-Fi network in the Settings app), then the network will become
- * the system default network regardless of any other network that's currently connected. If
- * {@code always} is true, then the choice is remembered, so that the next time the user
- * connects to this network, the system will switch to it.
- *
- * @param network The network to accept.
- * @param accept Whether to accept the network even if unvalidated.
- * @param always Whether to remember this choice in the future.
- *
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- @RequiresPermission(anyOf = {
- android.Manifest.permission.NETWORK_SETTINGS,
- android.Manifest.permission.NETWORK_SETUP_WIZARD,
- android.Manifest.permission.NETWORK_STACK,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
- public void setAcceptUnvalidated(@NonNull Network network, boolean accept, boolean always) {
- try {
- mService.setAcceptUnvalidated(network, accept, always);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Informs the system whether it should consider the network as validated even if it only has
- * partial connectivity. If {@code accept} is true, then the network will be considered as
- * validated even if connectivity is only partial. If {@code always} is true, then the choice
- * is remembered, so that the next time the user connects to this network, the system will
- * switch to it.
- *
- * @param network The network to accept.
- * @param accept Whether to consider the network as validated even if it has partial
- * connectivity.
- * @param always Whether to remember this choice in the future.
- *
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- @RequiresPermission(anyOf = {
- android.Manifest.permission.NETWORK_SETTINGS,
- android.Manifest.permission.NETWORK_SETUP_WIZARD,
- android.Manifest.permission.NETWORK_STACK,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
- public void setAcceptPartialConnectivity(@NonNull Network network, boolean accept,
- boolean always) {
- try {
- mService.setAcceptPartialConnectivity(network, accept, always);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Informs the system to penalize {@code network}'s score when it becomes unvalidated. This is
- * only meaningful if the system is configured not to penalize such networks, e.g., if the
- * {@code config_networkAvoidBadWifi} configuration variable is set to 0 and the {@code
- * NETWORK_AVOID_BAD_WIFI setting is unset}.
- *
- * @param network The network to accept.
- *
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- @RequiresPermission(anyOf = {
- android.Manifest.permission.NETWORK_SETTINGS,
- android.Manifest.permission.NETWORK_SETUP_WIZARD,
- android.Manifest.permission.NETWORK_STACK,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
- public void setAvoidUnvalidated(@NonNull Network network) {
- try {
- mService.setAvoidUnvalidated(network);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Requests that the system open the captive portal app on the specified network.
- *
- * <p>This is to be used on networks where a captive portal was detected, as per
- * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}.
- *
- * @param network The network to log into.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @RequiresPermission(anyOf = {
- android.Manifest.permission.NETWORK_SETTINGS,
- android.Manifest.permission.NETWORK_STACK,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
- })
- public void startCaptivePortalApp(@NonNull Network network) {
- try {
- mService.startCaptivePortalApp(network);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Requests that the system open the captive portal app with the specified extras.
- *
- * <p>This endpoint is exclusively for use by the NetworkStack and is protected by the
- * corresponding permission.
- * @param network Network on which the captive portal was detected.
- * @param appExtras Extras to include in the app start intent.
- * @hide
- */
- @SystemApi
- @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
- public void startCaptivePortalApp(@NonNull Network network, @NonNull Bundle appExtras) {
- try {
- mService.startCaptivePortalAppInternal(network, appExtras);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Determine whether the device is configured to avoid bad wifi.
- * @hide
- */
- @SystemApi
- @RequiresPermission(anyOf = {
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_STACK})
- public boolean shouldAvoidBadWifi() {
- try {
- return mService.shouldAvoidBadWifi();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * It is acceptable to briefly use multipath data to provide seamless connectivity for
- * time-sensitive user-facing operations when the system default network is temporarily
- * unresponsive. The amount of data should be limited (less than one megabyte for every call to
- * this method), and the operation should be infrequent to ensure that data usage is limited.
- *
- * An example of such an operation might be a time-sensitive foreground activity, such as a
- * voice command, that the user is performing while walking out of range of a Wi-Fi network.
- */
- public static final int MULTIPATH_PREFERENCE_HANDOVER = 1 << 0;
-
- /**
- * It is acceptable to use small amounts of multipath data on an ongoing basis to provide
- * a backup channel for traffic that is primarily going over another network.
- *
- * An example might be maintaining backup connections to peers or servers for the purpose of
- * fast fallback if the default network is temporarily unresponsive or disconnects. The traffic
- * on backup paths should be negligible compared to the traffic on the main path.
- */
- public static final int MULTIPATH_PREFERENCE_RELIABILITY = 1 << 1;
-
- /**
- * It is acceptable to use metered data to improve network latency and performance.
- */
- public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 1 << 2;
-
- /**
- * Return value to use for unmetered networks. On such networks we currently set all the flags
- * to true.
- * @hide
- */
- public static final int MULTIPATH_PREFERENCE_UNMETERED =
- MULTIPATH_PREFERENCE_HANDOVER |
- MULTIPATH_PREFERENCE_RELIABILITY |
- MULTIPATH_PREFERENCE_PERFORMANCE;
-
- /**
- * Provides a hint to the calling application on whether it is desirable to use the
- * multinetwork APIs (e.g., {@link Network#openConnection}, {@link Network#bindSocket}, etc.)
- * for multipath data transfer on this network when it is not the system default network.
- * Applications desiring to use multipath network protocols should call this method before
- * each such operation.
- *
- * @param network The network on which the application desires to use multipath data.
- * If {@code null}, this method will return the a preference that will generally
- * apply to metered networks.
- * @return a bitwise OR of zero or more of the {@code MULTIPATH_PREFERENCE_*} constants.
- */
- @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- public @MultipathPreference int getMultipathPreference(@Nullable Network network) {
- try {
- return mService.getMultipathPreference(network);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Resets all connectivity manager settings back to factory defaults.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- @RequiresPermission(anyOf = {
- android.Manifest.permission.NETWORK_SETTINGS,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
- public void factoryReset() {
- try {
- mService.factoryReset();
- mTetheringManager.stopAllTethering();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Binds the current process to {@code network}. All Sockets created in the future
- * (and not explicitly bound via a bound SocketFactory from
- * {@link Network#getSocketFactory() Network.getSocketFactory()}) will be bound to
- * {@code network}. All host name resolutions will be limited to {@code network} as well.
- * Note that if {@code network} ever disconnects, all Sockets created in this way will cease to
- * work and all host name resolutions will fail. This is by design so an application doesn't
- * accidentally use Sockets it thinks are still bound to a particular {@link Network}.
- * To clear binding pass {@code null} for {@code network}. Using individually bound
- * Sockets created by Network.getSocketFactory().createSocket() and
- * performing network-specific host name resolutions via
- * {@link Network#getAllByName Network.getAllByName} is preferred to calling
- * {@code bindProcessToNetwork}.
- *
- * @param network The {@link Network} to bind the current process to, or {@code null} to clear
- * the current binding.
- * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid.
- */
- public boolean bindProcessToNetwork(@Nullable Network network) {
- // Forcing callers to call through non-static function ensures ConnectivityManager
- // instantiated.
- return setProcessDefaultNetwork(network);
- }
-
- /**
- * Binds the current process to {@code network}. All Sockets created in the future
- * (and not explicitly bound via a bound SocketFactory from
- * {@link Network#getSocketFactory() Network.getSocketFactory()}) will be bound to
- * {@code network}. All host name resolutions will be limited to {@code network} as well.
- * Note that if {@code network} ever disconnects, all Sockets created in this way will cease to
- * work and all host name resolutions will fail. This is by design so an application doesn't
- * accidentally use Sockets it thinks are still bound to a particular {@link Network}.
- * To clear binding pass {@code null} for {@code network}. Using individually bound
- * Sockets created by Network.getSocketFactory().createSocket() and
- * performing network-specific host name resolutions via
- * {@link Network#getAllByName Network.getAllByName} is preferred to calling
- * {@code setProcessDefaultNetwork}.
- *
- * @param network The {@link Network} to bind the current process to, or {@code null} to clear
- * the current binding.
- * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid.
- * @deprecated This function can throw {@link IllegalStateException}. Use
- * {@link #bindProcessToNetwork} instead. {@code bindProcessToNetwork}
- * is a direct replacement.
- */
- @Deprecated
- public static boolean setProcessDefaultNetwork(@Nullable Network network) {
- int netId = (network == null) ? NETID_UNSET : network.netId;
- boolean isSameNetId = (netId == NetworkUtils.getBoundNetworkForProcess());
-
- if (netId != NETID_UNSET) {
- netId = network.getNetIdForResolv();
- }
-
- if (!NetworkUtils.bindProcessToNetwork(netId)) {
- return false;
- }
-
- if (!isSameNetId) {
- // Set HTTP proxy system properties to match network.
- // TODO: Deprecate this static method and replace it with a non-static version.
- try {
- Proxy.setHttpProxyConfiguration(getInstance().getDefaultProxy());
- } catch (SecurityException e) {
- // The process doesn't have ACCESS_NETWORK_STATE, so we can't fetch the proxy.
- Log.e(TAG, "Can't set proxy properties", e);
- }
- // Must flush DNS cache as new network may have different DNS resolutions.
- InetAddressCompat.clearDnsCache();
- // Must flush socket pool as idle sockets will be bound to previous network and may
- // cause subsequent fetches to be performed on old network.
- NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged();
- }
-
- return true;
- }
-
- /**
- * Returns the {@link Network} currently bound to this process via
- * {@link #bindProcessToNetwork}, or {@code null} if no {@link Network} is explicitly bound.
- *
- * @return {@code Network} to which this process is bound, or {@code null}.
- */
- @Nullable
- public Network getBoundNetworkForProcess() {
- // Forcing callers to call thru non-static function ensures ConnectivityManager
- // instantiated.
- return getProcessDefaultNetwork();
- }
-
- /**
- * Returns the {@link Network} currently bound to this process via
- * {@link #bindProcessToNetwork}, or {@code null} if no {@link Network} is explicitly bound.
- *
- * @return {@code Network} to which this process is bound, or {@code null}.
- * @deprecated Using this function can lead to other functions throwing
- * {@link IllegalStateException}. Use {@link #getBoundNetworkForProcess} instead.
- * {@code getBoundNetworkForProcess} is a direct replacement.
- */
- @Deprecated
- @Nullable
- public static Network getProcessDefaultNetwork() {
- int netId = NetworkUtils.getBoundNetworkForProcess();
- if (netId == NETID_UNSET) return null;
- return new Network(netId);
- }
-
- private void unsupportedStartingFrom(int version) {
- if (Process.myUid() == Process.SYSTEM_UID) {
- // The getApplicationInfo() call we make below is not supported in system context. Let
- // the call through here, and rely on the fact that ConnectivityService will refuse to
- // allow the system to use these APIs anyway.
- return;
- }
-
- if (mContext.getApplicationInfo().targetSdkVersion >= version) {
- throw new UnsupportedOperationException(
- "This method is not supported in target SDK version " + version + " and above");
- }
- }
-
- // Checks whether the calling app can use the legacy routing API (startUsingNetworkFeature,
- // stopUsingNetworkFeature, requestRouteToHost), and if not throw UnsupportedOperationException.
- // TODO: convert the existing system users (Tethering, GnssLocationProvider) to the new APIs and
- // remove these exemptions. Note that this check is not secure, and apps can still access these
- // functions by accessing ConnectivityService directly. However, it should be clear that doing
- // so is unsupported and may break in the future. http://b/22728205
- private void checkLegacyRoutingApiAccess() {
- unsupportedStartingFrom(VERSION_CODES.M);
- }
-
- /**
- * Binds host resolutions performed by this process to {@code network}.
- * {@link #bindProcessToNetwork} takes precedence over this setting.
- *
- * @param network The {@link Network} to bind host resolutions from the current process to, or
- * {@code null} to clear the current binding.
- * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid.
- * @hide
- * @deprecated This is strictly for legacy usage to support {@link #startUsingNetworkFeature}.
- */
- @Deprecated
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static boolean setProcessDefaultNetworkForHostResolution(Network network) {
- return NetworkUtils.bindProcessToNetworkForHostResolution(
- (network == null) ? NETID_UNSET : network.getNetIdForResolv());
- }
-
- /**
- * Device is not restricting metered network activity while application is running on
- * background.
- */
- public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1;
-
- /**
- * Device is restricting metered network activity while application is running on background,
- * but application is allowed to bypass it.
- * <p>
- * In this state, application should take action to mitigate metered network access.
- * For example, a music streaming application should switch to a low-bandwidth bitrate.
- */
- public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2;
-
- /**
- * Device is restricting metered network activity while application is running on background.
- * <p>
- * In this state, application should not try to use the network while running on background,
- * because it would be denied.
- */
- public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3;
-
- /**
- * A change in the background metered network activity restriction has occurred.
- * <p>
- * Applications should call {@link #getRestrictBackgroundStatus()} to check if the restriction
- * applies to them.
- * <p>
- * This is only sent to registered receivers, not manifest receivers.
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_RESTRICT_BACKGROUND_CHANGED =
- "android.net.conn.RESTRICT_BACKGROUND_CHANGED";
-
- /**
- * Determines if the calling application is subject to metered network restrictions while
- * running on background.
- *
- * @return {@link #RESTRICT_BACKGROUND_STATUS_DISABLED},
- * {@link #RESTRICT_BACKGROUND_STATUS_ENABLED},
- * or {@link #RESTRICT_BACKGROUND_STATUS_WHITELISTED}
- */
- public @RestrictBackgroundStatus int getRestrictBackgroundStatus() {
- try {
- return mService.getRestrictBackgroundStatusByCaller();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * The network watchlist is a list of domains and IP addresses that are associated with
- * potentially harmful apps. This method returns the SHA-256 of the watchlist config file
- * currently used by the system for validation purposes.
- *
- * @return Hash of network watchlist config file. Null if config does not exist.
- */
- @Nullable
- public byte[] getNetworkWatchlistConfigHash() {
- try {
- return mService.getNetworkWatchlistConfigHash();
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to get watchlist config hash");
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns the {@code uid} of the owner of a network connection.
- *
- * @param protocol The protocol of the connection. Only {@code IPPROTO_TCP} and {@code
- * IPPROTO_UDP} currently supported.
- * @param local The local {@link InetSocketAddress} of a connection.
- * @param remote The remote {@link InetSocketAddress} of a connection.
- * @return {@code uid} if the connection is found and the app has permission to observe it
- * (e.g., if it is associated with the calling VPN app's VpnService tunnel) or {@link
- * android.os.Process#INVALID_UID} if the connection is not found.
- * @throws {@link SecurityException} if the caller is not the active VpnService for the current
- * user.
- * @throws {@link IllegalArgumentException} if an unsupported protocol is requested.
- */
- public int getConnectionOwnerUid(
- int protocol, @NonNull InetSocketAddress local, @NonNull InetSocketAddress remote) {
- ConnectionInfo connectionInfo = new ConnectionInfo(protocol, local, remote);
- try {
- return mService.getConnectionOwnerUid(connectionInfo);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- private void printStackTrace() {
- if (DEBUG) {
- final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
- final StringBuffer sb = new StringBuffer();
- for (int i = 3; i < callStack.length; i++) {
- final String stackTrace = callStack[i].toString();
- if (stackTrace == null || stackTrace.contains("android.os")) {
- break;
- }
- sb.append(" [").append(stackTrace).append("]");
- }
- Log.d(TAG, "StackLog:" + sb.toString());
- }
- }
-
- /** @hide */
- public TestNetworkManager startOrGetTestNetworkManager() {
- final IBinder tnBinder;
- try {
- tnBinder = mService.startOrGetTestNetworkService();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
-
- return new TestNetworkManager(ITestNetworkManager.Stub.asInterface(tnBinder));
- }
-
- /** @hide */
- public ConnectivityDiagnosticsManager createDiagnosticsManager() {
- return new ConnectivityDiagnosticsManager(mContext, mService);
- }
-
- /**
- * Simulates a Data Stall for the specified Network.
- *
- * <p>This method should only be used for tests.
- *
- * <p>The caller must be the owner of the specified Network. This simulates a data stall to
- * have the system behave as if it had happened, but does not actually stall connectivity.
- *
- * @param detectionMethod The detection method used to identify the Data Stall.
- * See ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_*.
- * @param timestampMillis The timestamp at which the stall 'occurred', in milliseconds, as per
- * SystemClock.elapsedRealtime.
- * @param network The Network for which a Data Stall is being simluated.
- * @param extras The PersistableBundle of extras included in the Data Stall notification.
- * @throws SecurityException if the caller is not the owner of the given network.
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_TEST_NETWORKS,
- android.Manifest.permission.NETWORK_STACK})
- public void simulateDataStall(@DetectionMethod int detectionMethod, long timestampMillis,
- @NonNull Network network, @NonNull PersistableBundle extras) {
- try {
- mService.simulateDataStall(detectionMethod, timestampMillis, network, extras);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- }
-
- @NonNull
- private final List<QosCallbackConnection> mQosCallbackConnections = new ArrayList<>();
-
- /**
- * Registers a {@link QosSocketInfo} with an associated {@link QosCallback}. The callback will
- * receive available QoS events related to the {@link Network} and local ip + port
- * specified within socketInfo.
- * <p/>
- * The same {@link QosCallback} must be unregistered before being registered a second time,
- * otherwise {@link QosCallbackRegistrationException} is thrown.
- * <p/>
- * This API does not, in itself, require any permission if called with a network that is not
- * restricted. However, the underlying implementation currently only supports the IMS network,
- * which is always restricted. That means non-preinstalled callers can't possibly find this API
- * useful, because they'd never be called back on networks that they would have access to.
- *
- * @throws SecurityException if {@link QosSocketInfo#getNetwork()} is restricted and the app is
- * missing CONNECTIVITY_USE_RESTRICTED_NETWORKS permission.
- * @throws QosCallback.QosCallbackRegistrationException if qosCallback is already registered.
- * @throws RuntimeException if the app already has too many callbacks registered.
- *
- * Exceptions after the time of registration is passed through
- * {@link QosCallback#onError(QosCallbackException)}. see: {@link QosCallbackException}.
- *
- * @param socketInfo the socket information used to match QoS events
- * @param executor The executor on which the callback will be invoked. The provided
- * {@link Executor} must run callback sequentially, otherwise the order of
- * callbacks cannot be guaranteed.onQosCallbackRegistered
- * @param callback receives qos events that satisfy socketInfo
- *
- * @hide
- */
- @SystemApi
- public void registerQosCallback(@NonNull final QosSocketInfo socketInfo,
- @CallbackExecutor @NonNull final Executor executor,
- @NonNull final QosCallback callback) {
- Objects.requireNonNull(socketInfo, "socketInfo must be non-null");
- Objects.requireNonNull(executor, "executor must be non-null");
- Objects.requireNonNull(callback, "callback must be non-null");
-
- try {
- synchronized (mQosCallbackConnections) {
- if (getQosCallbackConnection(callback) == null) {
- final QosCallbackConnection connection =
- new QosCallbackConnection(this, callback, executor);
- mQosCallbackConnections.add(connection);
- mService.registerQosSocketCallback(socketInfo, connection);
- } else {
- Log.e(TAG, "registerQosCallback: Callback already registered");
- throw new QosCallbackRegistrationException();
- }
- }
- } catch (final RemoteException e) {
- Log.e(TAG, "registerQosCallback: Error while registering ", e);
-
- // The same unregister method method is called for consistency even though nothing
- // will be sent to the ConnectivityService since the callback was never successfully
- // registered.
- unregisterQosCallback(callback);
- e.rethrowFromSystemServer();
- } catch (final ServiceSpecificException e) {
- Log.e(TAG, "registerQosCallback: Error while registering ", e);
- unregisterQosCallback(callback);
- throw convertServiceException(e);
- }
- }
-
- /**
- * Unregisters the given {@link QosCallback}. The {@link QosCallback} will no longer receive
- * events once unregistered and can be registered a second time.
- * <p/>
- * If the {@link QosCallback} does not have an active registration, it is a no-op.
- *
- * @param callback the callback being unregistered
- *
- * @hide
- */
- @SystemApi
- public void unregisterQosCallback(@NonNull final QosCallback callback) {
- Objects.requireNonNull(callback, "The callback must be non-null");
- try {
- synchronized (mQosCallbackConnections) {
- final QosCallbackConnection connection = getQosCallbackConnection(callback);
- if (connection != null) {
- connection.stopReceivingMessages();
- mService.unregisterQosCallback(connection);
- mQosCallbackConnections.remove(connection);
- } else {
- Log.d(TAG, "unregisterQosCallback: Callback not registered");
- }
- }
- } catch (final RemoteException e) {
- Log.e(TAG, "unregisterQosCallback: Error while unregistering ", e);
- e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Gets the connection related to the callback.
- *
- * @param callback the callback to look up
- * @return the related connection
- */
- @Nullable
- private QosCallbackConnection getQosCallbackConnection(final QosCallback callback) {
- for (final QosCallbackConnection connection : mQosCallbackConnections) {
- // Checking by reference here is intentional
- if (connection.getCallback() == callback) {
- return connection;
- }
- }
- return null;
- }
-
- /**
- * Request a network to satisfy a set of {@link NetworkCapabilities}, but
- * does not cause any networks to retain the NET_CAPABILITY_FOREGROUND capability. This can
- * be used to request that the system provide a network without causing the network to be
- * in the foreground.
- *
- * <p>This method will attempt to find the best network that matches the passed
- * {@link NetworkRequest}, and to bring up one that does if none currently satisfies the
- * criteria. The platform will evaluate which network is the best at its own discretion.
- * Throughput, latency, cost per byte, policy, user preference and other considerations
- * may be factored in the decision of what is considered the best network.
- *
- * <p>As long as this request is outstanding, the platform will try to maintain the best network
- * matching this request, while always attempting to match the request to a better network if
- * possible. If a better match is found, the platform will switch this request to the now-best
- * network and inform the app of the newly best network by invoking
- * {@link NetworkCallback#onAvailable(Network)} on the provided callback. Note that the platform
- * will not try to maintain any other network than the best one currently matching the request:
- * a network not matching any network request may be disconnected at any time.
- *
- * <p>For example, an application could use this method to obtain a connected cellular network
- * even if the device currently has a data connection over Ethernet. This may cause the cellular
- * radio to consume additional power. Or, an application could inform the system that it wants
- * a network supporting sending MMSes and have the system let it know about the currently best
- * MMS-supporting network through the provided {@link NetworkCallback}.
- *
- * <p>The status of the request can be followed by listening to the various callbacks described
- * in {@link NetworkCallback}. The {@link Network} object passed to the callback methods can be
- * used to direct traffic to the network (although accessing some networks may be subject to
- * holding specific permissions). Callers will learn about the specific characteristics of the
- * network through
- * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)} and
- * {@link NetworkCallback#onLinkPropertiesChanged(Network, LinkProperties)}. The methods of the
- * provided {@link NetworkCallback} will only be invoked due to changes in the best network
- * matching the request at any given time; therefore when a better network matching the request
- * becomes available, the {@link NetworkCallback#onAvailable(Network)} method is called
- * with the new network after which no further updates are given about the previously-best
- * network, unless it becomes the best again at some later time. All callbacks are invoked
- * in order on the same thread, which by default is a thread created by the framework running
- * in the app.
- *
- * <p>This{@link NetworkRequest} will live until released via
- * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits, at
- * which point the system may let go of the network at any time.
- *
- * <p>It is presently unsupported to request a network with mutable
- * {@link NetworkCapabilities} such as
- * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
- * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}
- * as these {@code NetworkCapabilities} represent states that a particular
- * network may never attain, and whether a network will attain these states
- * is unknown prior to bringing up the network so the framework does not
- * know how to go about satisfying a request with these capabilities.
- *
- * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
- * number of outstanding requests to 100 per app (identified by their UID), shared with
- * all variants of this method, of {@link #registerNetworkCallback} as well as
- * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
- * Requesting a network with this method will count toward this limit. If this limit is
- * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
- * make sure to unregister the callbacks with
- * {@link #unregisterNetworkCallback(NetworkCallback)}.
- *
- * @param request {@link NetworkRequest} describing this request.
- * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
- * the callback must not be shared - it uniquely specifies this request.
- * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
- * If null, the callback is invoked on the default internal Handler.
- * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
- * @throws SecurityException if missing the appropriate permissions.
- * @throws RuntimeException if the app already has too many callbacks registered.
- *
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- @SuppressLint("ExecutorRegistration")
- @RequiresPermission(anyOf = {
- android.Manifest.permission.NETWORK_SETTINGS,
- android.Manifest.permission.NETWORK_STACK,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
- })
- public void requestBackgroundNetwork(@NonNull NetworkRequest request,
- @NonNull NetworkCallback networkCallback,
- @SuppressLint("ListenerLast") @NonNull Handler handler) {
- final NetworkCapabilities nc = request.networkCapabilities;
- sendRequestForNetwork(nc, networkCallback, 0, BACKGROUND_REQUEST,
- TYPE_NONE, new CallbackHandler(handler));
- }
-
- /**
- * Used by automotive devices to set the network preferences used to direct traffic at an
- * application level as per the given OemNetworkPreferences. An example use-case would be an
- * automotive OEM wanting to provide connectivity for applications critical to the usage of a
- * vehicle via a particular network.
- *
- * Calling this will overwrite the existing preference.
- *
- * @param preference {@link OemNetworkPreferences} The application network preference to be set.
- * @param executor the executor on which listener will be invoked.
- * @param listener {@link OnSetOemNetworkPreferenceListener} optional listener used to
- * communicate completion of setOemNetworkPreference(). This will only be
- * called once upon successful completion of setOemNetworkPreference().
- * @throws IllegalArgumentException if {@code preference} contains invalid preference values.
- * @throws SecurityException if missing the appropriate permissions.
- * @throws UnsupportedOperationException if called on a non-automotive device.
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE)
- public void setOemNetworkPreference(@NonNull final OemNetworkPreferences preference,
- @Nullable @CallbackExecutor final Executor executor,
- @Nullable final Runnable listener) {
- Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
- if (null != listener) {
- Objects.requireNonNull(executor, "Executor must be non-null");
- }
- final IOnCompleteListener listenerInternal = listener == null ? null :
- new IOnCompleteListener.Stub() {
- @Override
- public void onComplete() {
- executor.execute(listener::run);
- }
- };
-
- try {
- mService.setOemNetworkPreference(preference, listenerInternal);
- } catch (RemoteException e) {
- Log.e(TAG, "setOemNetworkPreference() failed for preference: " + preference.toString());
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Request that a user profile is put by default on a network matching a given preference.
- *
- * See the documentation for the individual preferences for a description of the supported
- * behaviors.
- *
- * @param profile the profile concerned.
- * @param preference the preference for this profile.
- * @param executor an executor to execute the listener on. Optional if listener is null.
- * @param listener an optional listener to listen for completion of the operation.
- * @throws IllegalArgumentException if {@code profile} is not a valid user profile.
- * @throws SecurityException if missing the appropriate permissions.
- * @hide
- */
- // This function is for establishing per-profile default networking and can only be called by
- // the device policy manager, running as the system server. It would make no sense to call it
- // on a context for a user because it does not establish a setting on behalf of a user, rather
- // it establishes a setting for a user on behalf of the DPM.
- @SuppressLint({"UserHandle"})
- @SystemApi(client = MODULE_LIBRARIES)
- @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- public void setProfileNetworkPreference(@NonNull final UserHandle profile,
- @ProfileNetworkPreference final int preference,
- @Nullable @CallbackExecutor final Executor executor,
- @Nullable final Runnable listener) {
- if (null != listener) {
- Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener");
- }
- final IOnCompleteListener proxy;
- if (null == listener) {
- proxy = null;
- } else {
- proxy = new IOnCompleteListener.Stub() {
- @Override
- public void onComplete() {
- executor.execute(listener::run);
- }
- };
- }
- try {
- mService.setProfileNetworkPreference(profile, preference, proxy);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- // The first network ID of IPSec tunnel interface.
- private static final int TUN_INTF_NETID_START = 0xFC00; // 0xFC00 = 64512
- // The network ID range of IPSec tunnel interface.
- private static final int TUN_INTF_NETID_RANGE = 0x0400; // 0x0400 = 1024
-
- /**
- * Get the network ID range reserved for IPSec tunnel interfaces.
- *
- * @return A Range which indicates the network ID range of IPSec tunnel interface.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- @NonNull
- public static Range<Integer> getIpSecNetIdRange() {
- return new Range(TUN_INTF_NETID_START, TUN_INTF_NETID_START + TUN_INTF_NETID_RANGE - 1);
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityResources.java b/packages/Connectivity/framework/src/android/net/ConnectivityResources.java
deleted file mode 100644
index 18f0de0..0000000
--- a/packages/Connectivity/framework/src/android/net/ConnectivityResources.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.List;
-
-/**
- * Utility to obtain the {@link com.android.server.ConnectivityService} {@link Resources}, in the
- * ServiceConnectivityResources APK.
- * @hide
- */
-public class ConnectivityResources {
- private static final String RESOURCES_APK_INTENT =
- "com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK";
- private static final String RES_PKG_DIR = "/apex/com.android.tethering/";
-
- @NonNull
- private final Context mContext;
-
- @Nullable
- private Context mResourcesContext = null;
-
- @Nullable
- private static Context sTestResourcesContext = null;
-
- public ConnectivityResources(Context context) {
- mContext = context;
- }
-
- /**
- * Convenience method to mock all resources for the duration of a test.
- *
- * Call with a null context to reset after the test.
- */
- @VisibleForTesting
- public static void setResourcesContextForTest(@Nullable Context testContext) {
- sTestResourcesContext = testContext;
- }
-
- /**
- * Get the {@link Context} of the resources package.
- */
- public synchronized Context getResourcesContext() {
- if (sTestResourcesContext != null) {
- return sTestResourcesContext;
- }
-
- if (mResourcesContext != null) {
- return mResourcesContext;
- }
-
- final List<ResolveInfo> pkgs = mContext.getPackageManager()
- .queryIntentActivities(new Intent(RESOURCES_APK_INTENT), MATCH_SYSTEM_ONLY);
- pkgs.removeIf(pkg -> !pkg.activityInfo.applicationInfo.sourceDir.startsWith(RES_PKG_DIR));
- if (pkgs.size() > 1) {
- Log.wtf(ConnectivityResources.class.getSimpleName(),
- "More than one package found: " + pkgs);
- }
- if (pkgs.isEmpty()) {
- throw new IllegalStateException("No connectivity resource package found");
- }
-
- final Context pkgContext;
- try {
- pkgContext = mContext.createPackageContext(
- pkgs.get(0).activityInfo.applicationInfo.packageName, 0 /* flags */);
- } catch (PackageManager.NameNotFoundException e) {
- throw new IllegalStateException("Resolved package not found", e);
- }
-
- mResourcesContext = pkgContext;
- return pkgContext;
- }
-
- /**
- * Get the {@link Resources} of the ServiceConnectivityResources APK.
- */
- public Resources get() {
- return getResourcesContext().getResources();
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
deleted file mode 100644
index 1a69099..0000000
--- a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
+++ /dev/null
@@ -1,1087 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER;
-import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE;
-import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY;
-
-import android.annotation.IntDef;
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.net.ConnectivityAnnotations.MultipathPreference;
-import android.os.Process;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.ArraySet;
-import android.util.Range;
-
-import com.android.net.module.util.ProxyUtils;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.time.Duration;
-import java.util.List;
-import java.util.Set;
-import java.util.StringJoiner;
-
-/**
- * A manager class for connectivity module settings.
- *
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public class ConnectivitySettingsManager {
-
- private ConnectivitySettingsManager() {}
-
- /** Data activity timeout settings */
-
- /**
- * Inactivity timeout to track mobile data activity.
- *
- * If set to a positive integer, it indicates the inactivity timeout value in seconds to
- * infer the data activity of mobile network. After a period of no activity on mobile
- * networks with length specified by the timeout, an {@code ACTION_DATA_ACTIVITY_CHANGE}
- * intent is fired to indicate a transition of network status from "active" to "idle". Any
- * subsequent activity on mobile networks triggers the firing of {@code
- * ACTION_DATA_ACTIVITY_CHANGE} intent indicating transition from "idle" to "active".
- *
- * Network activity refers to transmitting or receiving data on the network interfaces.
- *
- * Tracking is disabled if set to zero or negative value.
- *
- * @hide
- */
- public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile";
-
- /**
- * Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE}
- * but for Wifi network.
- *
- * @hide
- */
- public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi";
-
- /** Dns resolver settings */
-
- /**
- * Sample validity in seconds to configure for the system DNS resolver.
- *
- * @hide
- */
- public static final String DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS =
- "dns_resolver_sample_validity_seconds";
-
- /**
- * Success threshold in percent for use with the system DNS resolver.
- *
- * @hide
- */
- public static final String DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT =
- "dns_resolver_success_threshold_percent";
-
- /**
- * Minimum number of samples needed for statistics to be considered meaningful in the
- * system DNS resolver.
- *
- * @hide
- */
- public static final String DNS_RESOLVER_MIN_SAMPLES = "dns_resolver_min_samples";
-
- /**
- * Maximum number taken into account for statistics purposes in the system DNS resolver.
- *
- * @hide
- */
- public static final String DNS_RESOLVER_MAX_SAMPLES = "dns_resolver_max_samples";
-
- private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
- private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
-
- /** Network switch notification settings */
-
- /**
- * The maximum number of notifications shown in 24 hours when switching networks.
- *
- * @hide
- */
- public static final String NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT =
- "network_switch_notification_daily_limit";
-
- /**
- * The minimum time in milliseconds between notifications when switching networks.
- *
- * @hide
- */
- public static final String NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS =
- "network_switch_notification_rate_limit_millis";
-
- /** Captive portal settings */
-
- /**
- * The URL used for HTTP captive portal detection upon a new connection.
- * A 204 response code from the server is used for validation.
- *
- * @hide
- */
- public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
-
- /**
- * What to do when connecting a network that presents a captive portal.
- * Must be one of the CAPTIVE_PORTAL_MODE_* constants below.
- *
- * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
- *
- * @hide
- */
- public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
-
- /**
- * Don't attempt to detect captive portals.
- */
- public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0;
-
- /**
- * When detecting a captive portal, display a notification that
- * prompts the user to sign in.
- */
- public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1;
-
- /**
- * When detecting a captive portal, immediately disconnect from the
- * network and do not reconnect to that network in the future.
- */
- public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- CAPTIVE_PORTAL_MODE_IGNORE,
- CAPTIVE_PORTAL_MODE_PROMPT,
- CAPTIVE_PORTAL_MODE_AVOID,
- })
- public @interface CaptivePortalMode {}
-
- /** Global http proxy settings */
-
- /**
- * Host name for global http proxy. Set via ConnectivityManager.
- *
- * @hide
- */
- public static final String GLOBAL_HTTP_PROXY_HOST = "global_http_proxy_host";
-
- /**
- * Integer host port for global http proxy. Set via ConnectivityManager.
- *
- * @hide
- */
- public static final String GLOBAL_HTTP_PROXY_PORT = "global_http_proxy_port";
-
- /**
- * Exclusion list for global proxy. This string contains a list of
- * comma-separated domains where the global proxy does not apply.
- * Domains should be listed in a comma- separated list. Example of
- * acceptable formats: ".domain1.com,my.domain2.com" Use
- * ConnectivityManager to set/get.
- *
- * @hide
- */
- public static final String GLOBAL_HTTP_PROXY_EXCLUSION_LIST =
- "global_http_proxy_exclusion_list";
-
- /**
- * The location PAC File for the proxy.
- *
- * @hide
- */
- public static final String GLOBAL_HTTP_PROXY_PAC = "global_proxy_pac_url";
-
- /** Private dns settings */
-
- /**
- * The requested Private DNS mode (string), and an accompanying specifier (string).
- *
- * Currently, the specifier holds the chosen provider name when the mode requests
- * a specific provider. It may be used to store the provider name even when the
- * mode changes so that temporarily disabling and re-enabling the specific
- * provider mode does not necessitate retyping the provider hostname.
- *
- * @hide
- */
- public static final String PRIVATE_DNS_MODE = "private_dns_mode";
-
- /**
- * The specific Private DNS provider name.
- *
- * @hide
- */
- public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
-
- /**
- * Forced override of the default mode (hardcoded as "automatic", nee "opportunistic").
- * This allows changing the default mode without effectively disabling other modes,
- * all of which require explicit user action to enable/configure. See also b/79719289.
- *
- * Value is a string, suitable for assignment to PRIVATE_DNS_MODE above.
- *
- * @hide
- */
- public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode";
-
- /** Other settings */
-
- /**
- * The number of milliseconds to hold on to a PendingIntent based request. This delay gives
- * the receivers of the PendingIntent an opportunity to make a new network request before
- * the Network satisfying the request is potentially removed.
- *
- * @hide
- */
- public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS =
- "connectivity_release_pending_intent_delay_ms";
-
- /**
- * Whether the mobile data connection should remain active even when higher
- * priority networks like WiFi are active, to help make network switching faster.
- *
- * See ConnectivityService for more info.
- *
- * (0 = disabled, 1 = enabled)
- *
- * @hide
- */
- public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on";
-
- /**
- * Whether the wifi data connection should remain active even when higher
- * priority networks like Ethernet are active, to keep both networks.
- * In the case where higher priority networks are connected, wifi will be
- * unused unless an application explicitly requests to use it.
- *
- * See ConnectivityService for more info.
- *
- * (0 = disabled, 1 = enabled)
- *
- * @hide
- */
- public static final String WIFI_ALWAYS_REQUESTED = "wifi_always_requested";
-
- /**
- * Whether to automatically switch away from wifi networks that lose Internet access.
- * Only meaningful if config_networkAvoidBadWifi is set to 0, otherwise the system always
- * avoids such networks. Valid values are:
- *
- * 0: Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
- * null: Ask the user whether to switch away from bad wifi.
- * 1: Avoid bad wifi.
- *
- * @hide
- */
- public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
-
- /**
- * Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
- */
- public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0;
-
- /**
- * Ask the user whether to switch away from bad wifi.
- */
- public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1;
-
- /**
- * Avoid bad wifi.
- */
- public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- NETWORK_AVOID_BAD_WIFI_IGNORE,
- NETWORK_AVOID_BAD_WIFI_PROMPT,
- NETWORK_AVOID_BAD_WIFI_AVOID,
- })
- public @interface NetworkAvoidBadWifi {}
-
- /**
- * User setting for ConnectivityManager.getMeteredMultipathPreference(). This value may be
- * overridden by the system based on device or application state. If null, the value
- * specified by config_networkMeteredMultipathPreference is used.
- *
- * @hide
- */
- public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
- "network_metered_multipath_preference";
-
- /**
- * A list of uids that should go on cellular networks in preference even when higher-priority
- * networks are connected.
- *
- * @hide
- */
- public static final String MOBILE_DATA_PREFERRED_UIDS = "mobile_data_preferred_uids";
-
- /**
- * One of the private DNS modes that indicates the private DNS mode is off.
- */
- public static final int PRIVATE_DNS_MODE_OFF = 1;
-
- /**
- * One of the private DNS modes that indicates the private DNS mode is automatic, which
- * will try to use the current DNS as private DNS.
- */
- public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2;
-
- /**
- * One of the private DNS modes that indicates the private DNS mode is strict and the
- * {@link #PRIVATE_DNS_SPECIFIER} is required, which will try to use the value of
- * {@link #PRIVATE_DNS_SPECIFIER} as private DNS.
- */
- public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- PRIVATE_DNS_MODE_OFF,
- PRIVATE_DNS_MODE_OPPORTUNISTIC,
- PRIVATE_DNS_MODE_PROVIDER_HOSTNAME,
- })
- public @interface PrivateDnsMode {}
-
- private static final String PRIVATE_DNS_MODE_OFF_STRING = "off";
- private static final String PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING = "opportunistic";
- private static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING = "hostname";
-
- /**
- * A list of apps that is allowed on restricted networks.
- *
- * @hide
- */
- public static final String APPS_ALLOWED_ON_RESTRICTED_NETWORKS =
- "apps_allowed_on_restricted_networks";
-
- /**
- * Get mobile data activity timeout from {@link Settings}.
- *
- * @param context The {@link Context} to query the setting.
- * @param def The default timeout if no setting value.
- * @return The {@link Duration} of timeout to track mobile data activity.
- */
- @NonNull
- public static Duration getMobileDataActivityTimeout(@NonNull Context context,
- @NonNull Duration def) {
- final int timeout = Settings.Global.getInt(
- context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE, (int) def.getSeconds());
- return Duration.ofSeconds(timeout);
- }
-
- /**
- * Set mobile data activity timeout to {@link Settings}.
- * Tracking is disabled if set to zero or negative value.
- *
- * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
- * ignored.
- *
- * @param context The {@link Context} to set the setting.
- * @param timeout The mobile data activity timeout.
- */
- public static void setMobileDataActivityTimeout(@NonNull Context context,
- @NonNull Duration timeout) {
- Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE,
- (int) timeout.getSeconds());
- }
-
- /**
- * Get wifi data activity timeout from {@link Settings}.
- *
- * @param context The {@link Context} to query the setting.
- * @param def The default timeout if no setting value.
- * @return The {@link Duration} of timeout to track wifi data activity.
- */
- @NonNull
- public static Duration getWifiDataActivityTimeout(@NonNull Context context,
- @NonNull Duration def) {
- final int timeout = Settings.Global.getInt(
- context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI, (int) def.getSeconds());
- return Duration.ofSeconds(timeout);
- }
-
- /**
- * Set wifi data activity timeout to {@link Settings}.
- * Tracking is disabled if set to zero or negative value.
- *
- * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
- * ignored.
- *
- * @param context The {@link Context} to set the setting.
- * @param timeout The wifi data activity timeout.
- */
- public static void setWifiDataActivityTimeout(@NonNull Context context,
- @NonNull Duration timeout) {
- Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI,
- (int) timeout.getSeconds());
- }
-
- /**
- * Get dns resolver sample validity duration from {@link Settings}.
- *
- * @param context The {@link Context} to query the setting.
- * @param def The default duration if no setting value.
- * @return The {@link Duration} of sample validity duration to configure for the system DNS
- * resolver.
- */
- @NonNull
- public static Duration getDnsResolverSampleValidityDuration(@NonNull Context context,
- @NonNull Duration def) {
- final int duration = Settings.Global.getInt(context.getContentResolver(),
- DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, (int) def.getSeconds());
- return Duration.ofSeconds(duration);
- }
-
- /**
- * Set dns resolver sample validity duration to {@link Settings}. The duration must be a
- * positive number of seconds.
- *
- * @param context The {@link Context} to set the setting.
- * @param duration The sample validity duration.
- */
- public static void setDnsResolverSampleValidityDuration(@NonNull Context context,
- @NonNull Duration duration) {
- final int time = (int) duration.getSeconds();
- if (time <= 0) {
- throw new IllegalArgumentException("Invalid duration");
- }
- Settings.Global.putInt(
- context.getContentResolver(), DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, time);
- }
-
- /**
- * Get dns resolver success threshold percent from {@link Settings}.
- *
- * @param context The {@link Context} to query the setting.
- * @param def The default value if no setting value.
- * @return The success threshold in percent for use with the system DNS resolver.
- */
- public static int getDnsResolverSuccessThresholdPercent(@NonNull Context context, int def) {
- return Settings.Global.getInt(
- context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, def);
- }
-
- /**
- * Set dns resolver success threshold percent to {@link Settings}. The threshold percent must
- * be 0~100.
- *
- * @param context The {@link Context} to set the setting.
- * @param percent The success threshold percent.
- */
- public static void setDnsResolverSuccessThresholdPercent(@NonNull Context context,
- @IntRange(from = 0, to = 100) int percent) {
- if (percent < 0 || percent > 100) {
- throw new IllegalArgumentException("Percent must be 0~100");
- }
- Settings.Global.putInt(
- context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, percent);
- }
-
- /**
- * Get dns resolver samples range from {@link Settings}.
- *
- * @param context The {@link Context} to query the setting.
- * @return The {@link Range<Integer>} of samples needed for statistics to be considered
- * meaningful in the system DNS resolver.
- */
- @NonNull
- public static Range<Integer> getDnsResolverSampleRanges(@NonNull Context context) {
- final int minSamples = Settings.Global.getInt(context.getContentResolver(),
- DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
- final int maxSamples = Settings.Global.getInt(context.getContentResolver(),
- DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
- return new Range<>(minSamples, maxSamples);
- }
-
- /**
- * Set dns resolver samples range to {@link Settings}.
- *
- * @param context The {@link Context} to set the setting.
- * @param range The samples range. The minimum number should be more than 0 and the maximum
- * number should be less that 64.
- */
- public static void setDnsResolverSampleRanges(@NonNull Context context,
- @NonNull Range<Integer> range) {
- if (range.getLower() < 0 || range.getUpper() > 64) {
- throw new IllegalArgumentException("Argument must be 0~64");
- }
- Settings.Global.putInt(
- context.getContentResolver(), DNS_RESOLVER_MIN_SAMPLES, range.getLower());
- Settings.Global.putInt(
- context.getContentResolver(), DNS_RESOLVER_MAX_SAMPLES, range.getUpper());
- }
-
- /**
- * Get maximum count (from {@link Settings}) of switching network notifications shown in 24
- * hours.
- *
- * @param context The {@link Context} to query the setting.
- * @param def The default value if no setting value.
- * @return The maximum count of notifications shown in 24 hours when switching networks.
- */
- public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
- int def) {
- return Settings.Global.getInt(
- context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, def);
- }
-
- /**
- * Set maximum count (to {@link Settings}) of switching network notifications shown in 24 hours.
- * The count must be at least 0.
- *
- * @param context The {@link Context} to set the setting.
- * @param count The maximum count of switching network notifications shown in 24 hours.
- */
- public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
- @IntRange(from = 0) int count) {
- if (count < 0) {
- throw new IllegalArgumentException("Count must be 0~10.");
- }
- Settings.Global.putInt(
- context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, count);
- }
-
- /**
- * Get minimum duration (from {@link Settings}) between each switching network notifications.
- *
- * @param context The {@link Context} to query the setting.
- * @param def The default time if no setting value.
- * @return The minimum duration between notifications when switching networks.
- */
- @NonNull
- public static Duration getNetworkSwitchNotificationRateDuration(@NonNull Context context,
- @NonNull Duration def) {
- final int duration = Settings.Global.getInt(context.getContentResolver(),
- NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, (int) def.toMillis());
- return Duration.ofMillis(duration);
- }
-
- /**
- * Set minimum duration (to {@link Settings}) between each switching network notifications.
- *
- * @param context The {@link Context} to set the setting.
- * @param duration The minimum duration between notifications when switching networks.
- */
- public static void setNetworkSwitchNotificationRateDuration(@NonNull Context context,
- @NonNull Duration duration) {
- final int time = (int) duration.toMillis();
- if (time < 0) {
- throw new IllegalArgumentException("Invalid duration.");
- }
- Settings.Global.putInt(context.getContentResolver(),
- NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, time);
- }
-
- /**
- * Get URL (from {@link Settings}) used for HTTP captive portal detection upon a new connection.
- *
- * @param context The {@link Context} to query the setting.
- * @return The URL used for HTTP captive portal detection upon a new connection.
- */
- @Nullable
- public static String getCaptivePortalHttpUrl(@NonNull Context context) {
- return Settings.Global.getString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL);
- }
-
- /**
- * Set URL (to {@link Settings}) used for HTTP captive portal detection upon a new connection.
- * This URL should respond with a 204 response to a GET request to indicate no captive portal is
- * present. And this URL must be HTTP as redirect responses are used to find captive portal
- * sign-in pages. If the URL set to null or be incorrect, it will result in captive portal
- * detection failed and lost the connection.
- *
- * @param context The {@link Context} to set the setting.
- * @param url The URL used for HTTP captive portal detection upon a new connection.
- */
- public static void setCaptivePortalHttpUrl(@NonNull Context context, @Nullable String url) {
- Settings.Global.putString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL, url);
- }
-
- /**
- * Get mode (from {@link Settings}) when connecting a network that presents a captive portal.
- *
- * @param context The {@link Context} to query the setting.
- * @param def The default mode if no setting value.
- * @return The mode when connecting a network that presents a captive portal.
- */
- @CaptivePortalMode
- public static int getCaptivePortalMode(@NonNull Context context,
- @CaptivePortalMode int def) {
- return Settings.Global.getInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, def);
- }
-
- /**
- * Set mode (to {@link Settings}) when connecting a network that presents a captive portal.
- *
- * @param context The {@link Context} to set the setting.
- * @param mode The mode when connecting a network that presents a captive portal.
- */
- public static void setCaptivePortalMode(@NonNull Context context, @CaptivePortalMode int mode) {
- if (!(mode == CAPTIVE_PORTAL_MODE_IGNORE
- || mode == CAPTIVE_PORTAL_MODE_PROMPT
- || mode == CAPTIVE_PORTAL_MODE_AVOID)) {
- throw new IllegalArgumentException("Invalid captive portal mode");
- }
- Settings.Global.putInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, mode);
- }
-
- /**
- * Get the global HTTP proxy applied to the device, or null if none.
- *
- * @param context The {@link Context} to query the setting.
- * @return The {@link ProxyInfo} which build from global http proxy settings.
- */
- @Nullable
- public static ProxyInfo getGlobalProxy(@NonNull Context context) {
- final String host = Settings.Global.getString(
- context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST);
- final int port = Settings.Global.getInt(
- context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* def */);
- final String exclusionList = Settings.Global.getString(
- context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
- final String pacFileUrl = Settings.Global.getString(
- context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC);
-
- if (TextUtils.isEmpty(host) && TextUtils.isEmpty(pacFileUrl)) {
- return null; // No global proxy.
- }
-
- if (TextUtils.isEmpty(pacFileUrl)) {
- return ProxyInfo.buildDirectProxy(
- host, port, ProxyUtils.exclusionStringAsList(exclusionList));
- } else {
- return ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
- }
- }
-
- /**
- * Set global http proxy settings from given {@link ProxyInfo}.
- *
- * @param context The {@link Context} to set the setting.
- * @param proxyInfo The {@link ProxyInfo} for global http proxy settings which build from
- * {@link ProxyInfo#buildPacProxy(Uri)} or
- * {@link ProxyInfo#buildDirectProxy(String, int, List)}
- */
- public static void setGlobalProxy(@NonNull Context context, @NonNull ProxyInfo proxyInfo) {
- final String host = proxyInfo.getHost();
- final int port = proxyInfo.getPort();
- final String exclusionList = proxyInfo.getExclusionListAsString();
- final String pacFileUrl = proxyInfo.getPacFileUrl().toString();
-
- if (TextUtils.isEmpty(pacFileUrl)) {
- Settings.Global.putString(context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, host);
- Settings.Global.putInt(context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, port);
- Settings.Global.putString(
- context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclusionList);
- Settings.Global.putString(
- context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
- } else {
- Settings.Global.putString(
- context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
- Settings.Global.putString(
- context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
- Settings.Global.putInt(
- context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
- Settings.Global.putString(
- context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
- }
- }
-
- /**
- * Clear all global http proxy settings.
- *
- * @param context The {@link Context} to set the setting.
- */
- public static void clearGlobalProxy(@NonNull Context context) {
- Settings.Global.putString(
- context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
- Settings.Global.putInt(
- context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
- Settings.Global.putString(
- context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
- Settings.Global.putString(
- context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
- }
-
- private static String getPrivateDnsModeAsString(@PrivateDnsMode int mode) {
- switch (mode) {
- case PRIVATE_DNS_MODE_OFF:
- return PRIVATE_DNS_MODE_OFF_STRING;
- case PRIVATE_DNS_MODE_OPPORTUNISTIC:
- return PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING;
- case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
- return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING;
- default:
- throw new IllegalArgumentException("Invalid private dns mode: " + mode);
- }
- }
-
- private static int getPrivateDnsModeAsInt(String mode) {
- switch (mode) {
- case "off":
- return PRIVATE_DNS_MODE_OFF;
- case "hostname":
- return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
- case "opportunistic":
- return PRIVATE_DNS_MODE_OPPORTUNISTIC;
- default:
- throw new IllegalArgumentException("Invalid private dns mode: " + mode);
- }
- }
-
- /**
- * Get private DNS mode from settings.
- *
- * @param context The Context to query the private DNS mode from settings.
- * @return A string of private DNS mode.
- */
- @PrivateDnsMode
- public static int getPrivateDnsMode(@NonNull Context context) {
- final ContentResolver cr = context.getContentResolver();
- String mode = Settings.Global.getString(cr, PRIVATE_DNS_MODE);
- if (TextUtils.isEmpty(mode)) mode = Settings.Global.getString(cr, PRIVATE_DNS_DEFAULT_MODE);
- // If both PRIVATE_DNS_MODE and PRIVATE_DNS_DEFAULT_MODE are not set, choose
- // PRIVATE_DNS_MODE_OPPORTUNISTIC as default mode.
- if (TextUtils.isEmpty(mode)) return PRIVATE_DNS_MODE_OPPORTUNISTIC;
- return getPrivateDnsModeAsInt(mode);
- }
-
- /**
- * Set private DNS mode to settings.
- *
- * @param context The {@link Context} to set the private DNS mode.
- * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants.
- */
- public static void setPrivateDnsMode(@NonNull Context context, @PrivateDnsMode int mode) {
- if (!(mode == PRIVATE_DNS_MODE_OFF
- || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
- || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
- throw new IllegalArgumentException("Invalid private dns mode: " + mode);
- }
- Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE,
- getPrivateDnsModeAsString(mode));
- }
-
- /**
- * Get specific private dns provider name from {@link Settings}.
- *
- * @param context The {@link Context} to query the setting.
- * @return The specific private dns provider name, or null if no setting value.
- */
- @Nullable
- public static String getPrivateDnsHostname(@NonNull Context context) {
- return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER);
- }
-
- /**
- * Set specific private dns provider name to {@link Settings}.
- *
- * @param context The {@link Context} to set the setting.
- * @param specifier The specific private dns provider name.
- */
- public static void setPrivateDnsHostname(@NonNull Context context,
- @Nullable String specifier) {
- Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER, specifier);
- }
-
- /**
- * Get default private dns mode from {@link Settings}.
- *
- * @param context The {@link Context} to query the setting.
- * @return The default private dns mode.
- */
- @PrivateDnsMode
- @NonNull
- public static String getPrivateDnsDefaultMode(@NonNull Context context) {
- return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE);
- }
-
- /**
- * Set default private dns mode to {@link Settings}.
- *
- * @param context The {@link Context} to set the setting.
- * @param mode The default private dns mode. This should be one of the PRIVATE_DNS_MODE_*
- * constants.
- */
- public static void setPrivateDnsDefaultMode(@NonNull Context context,
- @NonNull @PrivateDnsMode int mode) {
- if (!(mode == PRIVATE_DNS_MODE_OFF
- || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
- || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
- throw new IllegalArgumentException("Invalid private dns mode");
- }
- Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE,
- getPrivateDnsModeAsString(mode));
- }
-
- /**
- * Get duration (from {@link Settings}) to keep a PendingIntent-based request.
- *
- * @param context The {@link Context} to query the setting.
- * @param def The default duration if no setting value.
- * @return The duration to keep a PendingIntent-based request.
- */
- @NonNull
- public static Duration getConnectivityKeepPendingIntentDuration(@NonNull Context context,
- @NonNull Duration def) {
- final int duration = Settings.Secure.getInt(context.getContentResolver(),
- CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, (int) def.toMillis());
- return Duration.ofMillis(duration);
- }
-
- /**
- * Set duration (to {@link Settings}) to keep a PendingIntent-based request.
- *
- * @param context The {@link Context} to set the setting.
- * @param duration The duration to keep a PendingIntent-based request.
- */
- public static void setConnectivityKeepPendingIntentDuration(@NonNull Context context,
- @NonNull Duration duration) {
- final int time = (int) duration.toMillis();
- if (time < 0) {
- throw new IllegalArgumentException("Invalid duration.");
- }
- Settings.Secure.putInt(
- context.getContentResolver(), CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, time);
- }
-
- /**
- * Read from {@link Settings} whether the mobile data connection should remain active
- * even when higher priority networks are active.
- *
- * @param context The {@link Context} to query the setting.
- * @param def The default value if no setting value.
- * @return Whether the mobile data connection should remain active even when higher
- * priority networks are active.
- */
- public static boolean getMobileDataAlwaysOn(@NonNull Context context, boolean def) {
- final int enable = Settings.Global.getInt(
- context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (def ? 1 : 0));
- return (enable != 0) ? true : false;
- }
-
- /**
- * Write into {@link Settings} whether the mobile data connection should remain active
- * even when higher priority networks are active.
- *
- * @param context The {@link Context} to set the setting.
- * @param enable Whether the mobile data connection should remain active even when higher
- * priority networks are active.
- */
- public static void setMobileDataAlwaysOn(@NonNull Context context, boolean enable) {
- Settings.Global.putInt(
- context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (enable ? 1 : 0));
- }
-
- /**
- * Read from {@link Settings} whether the wifi data connection should remain active
- * even when higher priority networks are active.
- *
- * @param context The {@link Context} to query the setting.
- * @param def The default value if no setting value.
- * @return Whether the wifi data connection should remain active even when higher
- * priority networks are active.
- */
- public static boolean getWifiAlwaysRequested(@NonNull Context context, boolean def) {
- final int enable = Settings.Global.getInt(
- context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (def ? 1 : 0));
- return (enable != 0) ? true : false;
- }
-
- /**
- * Write into {@link Settings} whether the wifi data connection should remain active
- * even when higher priority networks are active.
- *
- * @param context The {@link Context} to set the setting.
- * @param enable Whether the wifi data connection should remain active even when higher
- * priority networks are active
- */
- public static void setWifiAlwaysRequested(@NonNull Context context, boolean enable) {
- Settings.Global.putInt(
- context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (enable ? 1 : 0));
- }
-
- /**
- * Get avoid bad wifi setting from {@link Settings}.
- *
- * @param context The {@link Context} to query the setting.
- * @return The setting whether to automatically switch away from wifi networks that lose
- * internet access.
- */
- @NetworkAvoidBadWifi
- public static int getNetworkAvoidBadWifi(@NonNull Context context) {
- final String setting =
- Settings.Global.getString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI);
- if ("0".equals(setting)) {
- return NETWORK_AVOID_BAD_WIFI_IGNORE;
- } else if ("1".equals(setting)) {
- return NETWORK_AVOID_BAD_WIFI_AVOID;
- } else {
- return NETWORK_AVOID_BAD_WIFI_PROMPT;
- }
- }
-
- /**
- * Set avoid bad wifi setting to {@link Settings}.
- *
- * @param context The {@link Context} to set the setting.
- * @param value Whether to automatically switch away from wifi networks that lose internet
- * access.
- */
- public static void setNetworkAvoidBadWifi(@NonNull Context context,
- @NetworkAvoidBadWifi int value) {
- final String setting;
- if (value == NETWORK_AVOID_BAD_WIFI_IGNORE) {
- setting = "0";
- } else if (value == NETWORK_AVOID_BAD_WIFI_AVOID) {
- setting = "1";
- } else if (value == NETWORK_AVOID_BAD_WIFI_PROMPT) {
- setting = null;
- } else {
- throw new IllegalArgumentException("Invalid avoid bad wifi setting");
- }
- Settings.Global.putString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI, setting);
- }
-
- /**
- * Get network metered multipath preference from {@link Settings}.
- *
- * @param context The {@link Context} to query the setting.
- * @return The network metered multipath preference which should be one of
- * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value specified
- * by config_networkMeteredMultipathPreference is used.
- */
- @Nullable
- public static String getNetworkMeteredMultipathPreference(@NonNull Context context) {
- return Settings.Global.getString(
- context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE);
- }
-
- /**
- * Set network metered multipath preference to {@link Settings}.
- *
- * @param context The {@link Context} to set the setting.
- * @param preference The network metered multipath preference which should be one of
- * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value
- * specified by config_networkMeteredMultipathPreference is used.
- */
- public static void setNetworkMeteredMultipathPreference(@NonNull Context context,
- @NonNull @MultipathPreference String preference) {
- if (!(Integer.valueOf(preference) == MULTIPATH_PREFERENCE_HANDOVER
- || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_RELIABILITY
- || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_PERFORMANCE)) {
- throw new IllegalArgumentException("Invalid private dns mode");
- }
- Settings.Global.putString(
- context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE, preference);
- }
-
- /**
- * Get the list of uids(from {@link Settings}) that should go on cellular networks in preference
- * even when higher-priority networks are connected.
- *
- * @param context The {@link Context} to query the setting.
- * @return A list of uids that should go on cellular networks in preference even when
- * higher-priority networks are connected or null if no setting value.
- */
- @NonNull
- public static Set<Integer> getMobileDataPreferredUids(@NonNull Context context) {
- final String uidList = Settings.Secure.getString(
- context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS);
- final Set<Integer> uids = new ArraySet<>();
- if (TextUtils.isEmpty(uidList)) {
- return uids;
- }
- for (String uid : uidList.split(";")) {
- uids.add(Integer.valueOf(uid));
- }
- return uids;
- }
-
- /**
- * Set the list of uids(to {@link Settings}) that should go on cellular networks in preference
- * even when higher-priority networks are connected.
- *
- * @param context The {@link Context} to set the setting.
- * @param uidList A list of uids that should go on cellular networks in preference even when
- * higher-priority networks are connected.
- */
- public static void setMobileDataPreferredUids(@NonNull Context context,
- @NonNull Set<Integer> uidList) {
- final StringJoiner joiner = new StringJoiner(";");
- for (Integer uid : uidList) {
- if (uid < 0 || UserHandle.getAppId(uid) > Process.LAST_APPLICATION_UID) {
- throw new IllegalArgumentException("Invalid uid");
- }
- joiner.add(uid.toString());
- }
- Settings.Secure.putString(
- context.getContentResolver(), MOBILE_DATA_PREFERRED_UIDS, joiner.toString());
- }
-
- /**
- * Get the list of apps(from {@link Settings}) that is allowed on restricted networks.
- *
- * @param context The {@link Context} to query the setting.
- * @return A list of apps that is allowed on restricted networks or null if no setting
- * value.
- */
- @NonNull
- public static Set<String> getAppsAllowedOnRestrictedNetworks(@NonNull Context context) {
- final String appList = Settings.Secure.getString(
- context.getContentResolver(), APPS_ALLOWED_ON_RESTRICTED_NETWORKS);
- if (TextUtils.isEmpty(appList)) {
- return new ArraySet<>();
- }
- return new ArraySet<>(appList.split(";"));
- }
-
- /**
- * Set the list of apps(from {@link Settings}) that is allowed on restricted networks.
- *
- * Note: Please refer to android developer guidelines for valid app(package name).
- * https://developer.android.com/guide/topics/manifest/manifest-element.html#package
- *
- * @param context The {@link Context} to set the setting.
- * @param list A list of apps that is allowed on restricted networks.
- */
- public static void setAppsAllowedOnRestrictedNetworks(@NonNull Context context,
- @NonNull Set<String> list) {
- final StringJoiner joiner = new StringJoiner(";");
- for (String app : list) {
- if (app == null || app.contains(";")) {
- throw new IllegalArgumentException("Invalid app(package name)");
- }
- joiner.add(app);
- }
- Settings.Secure.putString(context.getContentResolver(), APPS_ALLOWED_ON_RESTRICTED_NETWORKS,
- joiner.toString());
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityThread.java b/packages/Connectivity/framework/src/android/net/ConnectivityThread.java
deleted file mode 100644
index 0b218e7..0000000
--- a/packages/Connectivity/framework/src/android/net/ConnectivityThread.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.os.HandlerThread;
-import android.os.Looper;
-
-/**
- * Shared singleton connectivity thread for the system. This is a thread for
- * connectivity operations such as AsyncChannel connections to system services.
- * Various connectivity manager objects can use this singleton as a common
- * resource for their handlers instead of creating separate threads of their own.
- * @hide
- */
-public final class ConnectivityThread extends HandlerThread {
-
- // A class implementing the lazy holder idiom: the unique static instance
- // of ConnectivityThread is instantiated in a thread-safe way (guaranteed by
- // the language specs) the first time that Singleton is referenced in get()
- // or getInstanceLooper().
- private static class Singleton {
- private static final ConnectivityThread INSTANCE = createInstance();
- }
-
- private ConnectivityThread() {
- super("ConnectivityThread");
- }
-
- private static ConnectivityThread createInstance() {
- ConnectivityThread t = new ConnectivityThread();
- t.start();
- return t;
- }
-
- public static ConnectivityThread get() {
- return Singleton.INSTANCE;
- }
-
- public static Looper getInstanceLooper() {
- return Singleton.INSTANCE.getLooper();
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/DhcpInfo.java b/packages/Connectivity/framework/src/android/net/DhcpInfo.java
deleted file mode 100644
index 912df67..0000000
--- a/packages/Connectivity/framework/src/android/net/DhcpInfo.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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.
- */
-
-package android.net;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * A simple object for retrieving the results of a DHCP request.
- */
-public class DhcpInfo implements Parcelable {
- public int ipAddress;
- public int gateway;
- public int netmask;
- public int dns1;
- public int dns2;
- public int serverAddress;
-
- public int leaseDuration;
-
- public DhcpInfo() {
- super();
- }
-
- /** copy constructor {@hide} */
- public DhcpInfo(DhcpInfo source) {
- if (source != null) {
- ipAddress = source.ipAddress;
- gateway = source.gateway;
- netmask = source.netmask;
- dns1 = source.dns1;
- dns2 = source.dns2;
- serverAddress = source.serverAddress;
- leaseDuration = source.leaseDuration;
- }
- }
-
- public String toString() {
- StringBuffer str = new StringBuffer();
-
- str.append("ipaddr "); putAddress(str, ipAddress);
- str.append(" gateway "); putAddress(str, gateway);
- str.append(" netmask "); putAddress(str, netmask);
- str.append(" dns1 "); putAddress(str, dns1);
- str.append(" dns2 "); putAddress(str, dns2);
- str.append(" DHCP server "); putAddress(str, serverAddress);
- str.append(" lease ").append(leaseDuration).append(" seconds");
-
- return str.toString();
- }
-
- private static void putAddress(StringBuffer buf, int addr) {
- buf.append(NetworkUtils.intToInetAddress(addr).getHostAddress());
- }
-
- /** Implement the Parcelable interface */
- public int describeContents() {
- return 0;
- }
-
- /** Implement the Parcelable interface */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(ipAddress);
- dest.writeInt(gateway);
- dest.writeInt(netmask);
- dest.writeInt(dns1);
- dest.writeInt(dns2);
- dest.writeInt(serverAddress);
- dest.writeInt(leaseDuration);
- }
-
- /** Implement the Parcelable interface */
- public static final @android.annotation.NonNull Creator<DhcpInfo> CREATOR =
- new Creator<DhcpInfo>() {
- public DhcpInfo createFromParcel(Parcel in) {
- DhcpInfo info = new DhcpInfo();
- info.ipAddress = in.readInt();
- info.gateway = in.readInt();
- info.netmask = in.readInt();
- info.dns1 = in.readInt();
- info.dns2 = in.readInt();
- info.serverAddress = in.readInt();
- info.leaseDuration = in.readInt();
- return info;
- }
-
- public DhcpInfo[] newArray(int size) {
- return new DhcpInfo[size];
- }
- };
-}
diff --git a/packages/Connectivity/framework/src/android/net/DnsResolver.java b/packages/Connectivity/framework/src/android/net/DnsResolver.java
deleted file mode 100644
index dac88ad..0000000
--- a/packages/Connectivity/framework/src/android/net/DnsResolver.java
+++ /dev/null
@@ -1,577 +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 android.net;
-
-import static android.net.NetworkUtils.getDnsNetwork;
-import static android.net.NetworkUtils.resNetworkCancel;
-import static android.net.NetworkUtils.resNetworkQuery;
-import static android.net.NetworkUtils.resNetworkResult;
-import static android.net.NetworkUtils.resNetworkSend;
-import static android.net.util.DnsUtils.haveIpv4;
-import static android.net.util.DnsUtils.haveIpv6;
-import static android.net.util.DnsUtils.rfc6724Sort;
-import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
-import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
-import static android.system.OsConstants.ENONET;
-
-import android.annotation.CallbackExecutor;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.CancellationSignal;
-import android.os.Looper;
-import android.os.MessageQueue;
-import android.system.ErrnoException;
-import android.util.Log;
-
-import com.android.net.module.util.DnsPacket;
-
-import java.io.FileDescriptor;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-/**
- * Dns resolver class for asynchronous dns querying
- *
- * Note that if a client sends a query with more than 1 record in the question section but
- * the remote dns server does not support this, it may not respond at all, leading to a timeout.
- *
- */
-public final class DnsResolver {
- private static final String TAG = "DnsResolver";
- private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR;
- private static final int MAXPACKET = 8 * 1024;
- private static final int SLEEP_TIME_MS = 2;
-
- @IntDef(prefix = { "CLASS_" }, value = {
- CLASS_IN
- })
- @Retention(RetentionPolicy.SOURCE)
- @interface QueryClass {}
- public static final int CLASS_IN = 1;
-
- @IntDef(prefix = { "TYPE_" }, value = {
- TYPE_A,
- TYPE_AAAA
- })
- @Retention(RetentionPolicy.SOURCE)
- @interface QueryType {}
- public static final int TYPE_A = 1;
- public static final int TYPE_AAAA = 28;
-
- @IntDef(prefix = { "FLAG_" }, value = {
- FLAG_EMPTY,
- FLAG_NO_RETRY,
- FLAG_NO_CACHE_STORE,
- FLAG_NO_CACHE_LOOKUP
- })
- @Retention(RetentionPolicy.SOURCE)
- @interface QueryFlag {}
- public static final int FLAG_EMPTY = 0;
- public static final int FLAG_NO_RETRY = 1 << 0;
- public static final int FLAG_NO_CACHE_STORE = 1 << 1;
- public static final int FLAG_NO_CACHE_LOOKUP = 1 << 2;
-
- @IntDef(prefix = { "ERROR_" }, value = {
- ERROR_PARSE,
- ERROR_SYSTEM
- })
- @Retention(RetentionPolicy.SOURCE)
- @interface DnsError {}
- /**
- * Indicates that there was an error parsing the response the query.
- * The cause of this error is available via getCause() and is a {@link ParseException}.
- */
- public static final int ERROR_PARSE = 0;
- /**
- * Indicates that there was an error sending the query.
- * The cause of this error is available via getCause() and is an ErrnoException.
- */
- public static final int ERROR_SYSTEM = 1;
-
- private static final int NETID_UNSET = 0;
-
- private static final DnsResolver sInstance = new DnsResolver();
-
- /**
- * Get instance for DnsResolver
- */
- public static @NonNull DnsResolver getInstance() {
- return sInstance;
- }
-
- private DnsResolver() {}
-
- /**
- * Base interface for answer callbacks
- *
- * @param <T> The type of the answer
- */
- public interface Callback<T> {
- /**
- * Success response to
- * {@link android.net.DnsResolver#query query()} or
- * {@link android.net.DnsResolver#rawQuery rawQuery()}.
- *
- * Invoked when the answer to a query was successfully parsed.
- *
- * @param answer <T> answer to the query.
- * @param rcode The response code in the DNS response.
- *
- * {@see android.net.DnsResolver#query query()}
- */
- void onAnswer(@NonNull T answer, int rcode);
- /**
- * Error response to
- * {@link android.net.DnsResolver#query query()} or
- * {@link android.net.DnsResolver#rawQuery rawQuery()}.
- *
- * Invoked when there is no valid answer to
- * {@link android.net.DnsResolver#query query()}
- * {@link android.net.DnsResolver#rawQuery rawQuery()}.
- *
- * @param error a {@link DnsException} object with additional
- * detail regarding the failure
- */
- void onError(@NonNull DnsException error);
- }
-
- /**
- * Class to represent DNS error
- */
- public static class DnsException extends Exception {
- /**
- * DNS error code as one of the ERROR_* constants
- */
- @DnsError public final int code;
-
- DnsException(@DnsError int code, @Nullable Throwable cause) {
- super(cause);
- this.code = code;
- }
- }
-
- /**
- * Send a raw DNS query.
- * The answer will be provided asynchronously through the provided {@link Callback}.
- *
- * @param network {@link Network} specifying which network to query on.
- * {@code null} for query on default network.
- * @param query blob message to query
- * @param flags flags as a combination of the FLAGS_* constants
- * @param executor The {@link Executor} that the callback should be executed on.
- * @param cancellationSignal used by the caller to signal if the query should be
- * cancelled. May be {@code null}.
- * @param callback a {@link Callback} which will be called to notify the caller
- * of the result of dns query.
- */
- public void rawQuery(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags,
- @NonNull @CallbackExecutor Executor executor,
- @Nullable CancellationSignal cancellationSignal,
- @NonNull Callback<? super byte[]> callback) {
- if (cancellationSignal != null && cancellationSignal.isCanceled()) {
- return;
- }
- final Object lock = new Object();
- final FileDescriptor queryfd;
- try {
- queryfd = resNetworkSend((network != null)
- ? network.getNetIdForResolv() : NETID_UNSET, query, query.length, flags);
- } catch (ErrnoException e) {
- executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
- return;
- }
-
- synchronized (lock) {
- registerFDListener(executor, queryfd, callback, cancellationSignal, lock);
- if (cancellationSignal == null) return;
- addCancellationSignal(cancellationSignal, queryfd, lock);
- }
- }
-
- /**
- * Send a DNS query with the specified name, class and query type.
- * The answer will be provided asynchronously through the provided {@link Callback}.
- *
- * @param network {@link Network} specifying which network to query on.
- * {@code null} for query on default network.
- * @param domain domain name to query
- * @param nsClass dns class as one of the CLASS_* constants
- * @param nsType dns resource record (RR) type as one of the TYPE_* constants
- * @param flags flags as a combination of the FLAGS_* constants
- * @param executor The {@link Executor} that the callback should be executed on.
- * @param cancellationSignal used by the caller to signal if the query should be
- * cancelled. May be {@code null}.
- * @param callback a {@link Callback} which will be called to notify the caller
- * of the result of dns query.
- */
- public void rawQuery(@Nullable Network network, @NonNull String domain,
- @QueryClass int nsClass, @QueryType int nsType, @QueryFlag int flags,
- @NonNull @CallbackExecutor Executor executor,
- @Nullable CancellationSignal cancellationSignal,
- @NonNull Callback<? super byte[]> callback) {
- if (cancellationSignal != null && cancellationSignal.isCanceled()) {
- return;
- }
- final Object lock = new Object();
- final FileDescriptor queryfd;
- try {
- queryfd = resNetworkQuery((network != null)
- ? network.getNetIdForResolv() : NETID_UNSET, domain, nsClass, nsType, flags);
- } catch (ErrnoException e) {
- executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
- return;
- }
- synchronized (lock) {
- registerFDListener(executor, queryfd, callback, cancellationSignal, lock);
- if (cancellationSignal == null) return;
- addCancellationSignal(cancellationSignal, queryfd, lock);
- }
- }
-
- private class InetAddressAnswerAccumulator implements Callback<byte[]> {
- private final List<InetAddress> mAllAnswers;
- private final Network mNetwork;
- private int mRcode;
- private DnsException mDnsException;
- private final Callback<? super List<InetAddress>> mUserCallback;
- private final int mTargetAnswerCount;
- private int mReceivedAnswerCount = 0;
-
- InetAddressAnswerAccumulator(@NonNull Network network, int size,
- @NonNull Callback<? super List<InetAddress>> callback) {
- mNetwork = network;
- mTargetAnswerCount = size;
- mAllAnswers = new ArrayList<>();
- mUserCallback = callback;
- }
-
- private boolean maybeReportError() {
- if (mRcode != 0) {
- mUserCallback.onAnswer(mAllAnswers, mRcode);
- return true;
- }
- if (mDnsException != null) {
- mUserCallback.onError(mDnsException);
- return true;
- }
- return false;
- }
-
- private void maybeReportAnswer() {
- if (++mReceivedAnswerCount != mTargetAnswerCount) return;
- if (mAllAnswers.isEmpty() && maybeReportError()) return;
- mUserCallback.onAnswer(rfc6724Sort(mNetwork, mAllAnswers), mRcode);
- }
-
- @Override
- public void onAnswer(@NonNull byte[] answer, int rcode) {
- // If at least one query succeeded, return an rcode of 0.
- // Otherwise, arbitrarily return the first rcode received.
- if (mReceivedAnswerCount == 0 || rcode == 0) {
- mRcode = rcode;
- }
- try {
- mAllAnswers.addAll(new DnsAddressAnswer(answer).getAddresses());
- } catch (DnsPacket.ParseException e) {
- // Convert the com.android.net.module.util.DnsPacket.ParseException to an
- // android.net.ParseException. This is the type that was used in Q and is implied
- // by the public documentation of ERROR_PARSE.
- //
- // DnsPacket cannot throw android.net.ParseException directly because it's @hide.
- ParseException pe = new ParseException(e.reason, e.getCause());
- pe.setStackTrace(e.getStackTrace());
- mDnsException = new DnsException(ERROR_PARSE, pe);
- }
- maybeReportAnswer();
- }
-
- @Override
- public void onError(@NonNull DnsException error) {
- mDnsException = error;
- maybeReportAnswer();
- }
- }
-
- /**
- * Send a DNS query with the specified name on a network with both IPv4 and IPv6,
- * get back a set of InetAddresses with rfc6724 sorting style asynchronously.
- *
- * This method will examine the connection ability on given network, and query IPv4
- * and IPv6 if connection is available.
- *
- * If at least one query succeeded with valid answer, rcode will be 0
- *
- * The answer will be provided asynchronously through the provided {@link Callback}.
- *
- * @param network {@link Network} specifying which network to query on.
- * {@code null} for query on default network.
- * @param domain domain name to query
- * @param flags flags as a combination of the FLAGS_* constants
- * @param executor The {@link Executor} that the callback should be executed on.
- * @param cancellationSignal used by the caller to signal if the query should be
- * cancelled. May be {@code null}.
- * @param callback a {@link Callback} which will be called to notify the
- * caller of the result of dns query.
- */
- public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags,
- @NonNull @CallbackExecutor Executor executor,
- @Nullable CancellationSignal cancellationSignal,
- @NonNull Callback<? super List<InetAddress>> callback) {
- if (cancellationSignal != null && cancellationSignal.isCanceled()) {
- return;
- }
- final Object lock = new Object();
- final Network queryNetwork;
- try {
- queryNetwork = (network != null) ? network : getDnsNetwork();
- } catch (ErrnoException e) {
- executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
- return;
- }
- final boolean queryIpv6 = haveIpv6(queryNetwork);
- final boolean queryIpv4 = haveIpv4(queryNetwork);
-
- // This can only happen if queryIpv4 and queryIpv6 are both false.
- // This almost certainly means that queryNetwork does not exist or no longer exists.
- if (!queryIpv6 && !queryIpv4) {
- executor.execute(() -> callback.onError(
- new DnsException(ERROR_SYSTEM, new ErrnoException("resNetworkQuery", ENONET))));
- return;
- }
-
- final FileDescriptor v4fd;
- final FileDescriptor v6fd;
-
- int queryCount = 0;
-
- if (queryIpv6) {
- try {
- v6fd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN,
- TYPE_AAAA, flags);
- } catch (ErrnoException e) {
- executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
- return;
- }
- queryCount++;
- } else v6fd = null;
-
- // Avoiding gateways drop packets if queries are sent too close together
- try {
- Thread.sleep(SLEEP_TIME_MS);
- } catch (InterruptedException ex) {
- Thread.currentThread().interrupt();
- }
-
- if (queryIpv4) {
- try {
- v4fd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, TYPE_A,
- flags);
- } catch (ErrnoException e) {
- if (queryIpv6) resNetworkCancel(v6fd); // Closes fd, marks it invalid.
- executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
- return;
- }
- queryCount++;
- } else v4fd = null;
-
- final InetAddressAnswerAccumulator accumulator =
- new InetAddressAnswerAccumulator(queryNetwork, queryCount, callback);
-
- synchronized (lock) {
- if (queryIpv6) {
- registerFDListener(executor, v6fd, accumulator, cancellationSignal, lock);
- }
- if (queryIpv4) {
- registerFDListener(executor, v4fd, accumulator, cancellationSignal, lock);
- }
- if (cancellationSignal == null) return;
- cancellationSignal.setOnCancelListener(() -> {
- synchronized (lock) {
- if (queryIpv4) cancelQuery(v4fd);
- if (queryIpv6) cancelQuery(v6fd);
- }
- });
- }
- }
-
- /**
- * Send a DNS query with the specified name and query type, get back a set of
- * InetAddresses with rfc6724 sorting style asynchronously.
- *
- * The answer will be provided asynchronously through the provided {@link Callback}.
- *
- * @param network {@link Network} specifying which network to query on.
- * {@code null} for query on default network.
- * @param domain domain name to query
- * @param nsType dns resource record (RR) type as one of the TYPE_* constants
- * @param flags flags as a combination of the FLAGS_* constants
- * @param executor The {@link Executor} that the callback should be executed on.
- * @param cancellationSignal used by the caller to signal if the query should be
- * cancelled. May be {@code null}.
- * @param callback a {@link Callback} which will be called to notify the caller
- * of the result of dns query.
- */
- public void query(@Nullable Network network, @NonNull String domain,
- @QueryType int nsType, @QueryFlag int flags,
- @NonNull @CallbackExecutor Executor executor,
- @Nullable CancellationSignal cancellationSignal,
- @NonNull Callback<? super List<InetAddress>> callback) {
- if (cancellationSignal != null && cancellationSignal.isCanceled()) {
- return;
- }
- final Object lock = new Object();
- final FileDescriptor queryfd;
- final Network queryNetwork;
- try {
- queryNetwork = (network != null) ? network : getDnsNetwork();
- queryfd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, nsType,
- flags);
- } catch (ErrnoException e) {
- executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
- return;
- }
- final InetAddressAnswerAccumulator accumulator =
- new InetAddressAnswerAccumulator(queryNetwork, 1, callback);
- synchronized (lock) {
- registerFDListener(executor, queryfd, accumulator, cancellationSignal, lock);
- if (cancellationSignal == null) return;
- addCancellationSignal(cancellationSignal, queryfd, lock);
- }
- }
-
- /**
- * Class to retrieve DNS response
- *
- * @hide
- */
- public static final class DnsResponse {
- public final @NonNull byte[] answerbuf;
- public final int rcode;
- public DnsResponse(@NonNull byte[] answerbuf, int rcode) {
- this.answerbuf = answerbuf;
- this.rcode = rcode;
- }
- }
-
- private void registerFDListener(@NonNull Executor executor,
- @NonNull FileDescriptor queryfd, @NonNull Callback<? super byte[]> answerCallback,
- @Nullable CancellationSignal cancellationSignal, @NonNull Object lock) {
- final MessageQueue mainThreadMessageQueue = Looper.getMainLooper().getQueue();
- mainThreadMessageQueue.addOnFileDescriptorEventListener(
- queryfd,
- FD_EVENTS,
- (fd, events) -> {
- // b/134310704
- // Unregister fd event listener before resNetworkResult is called to prevent
- // race condition caused by fd reused.
- // For example when querying v4 and v6, it's possible that the first query ends
- // and the fd is closed before the second request starts, which might return
- // the same fd for the second request. By that time, the looper must have
- // unregistered the fd, otherwise another event listener can't be registered.
- mainThreadMessageQueue.removeOnFileDescriptorEventListener(fd);
-
- executor.execute(() -> {
- DnsResponse resp = null;
- ErrnoException exception = null;
- synchronized (lock) {
- if (cancellationSignal != null && cancellationSignal.isCanceled()) {
- return;
- }
- try {
- resp = resNetworkResult(fd); // Closes fd, marks it invalid.
- } catch (ErrnoException e) {
- Log.w(TAG, "resNetworkResult:" + e.toString());
- exception = e;
- }
- }
- if (exception != null) {
- answerCallback.onError(new DnsException(ERROR_SYSTEM, exception));
- return;
- }
- answerCallback.onAnswer(resp.answerbuf, resp.rcode);
- });
-
- // The file descriptor has already been unregistered, so it does not really
- // matter what is returned here. In spirit 0 (meaning "unregister this FD")
- // is still the closest to what the looper needs to do. When returning 0,
- // Looper knows to ignore the fd if it has already been unregistered.
- return 0;
- });
- }
-
- private void cancelQuery(@NonNull FileDescriptor queryfd) {
- if (!queryfd.valid()) return;
- Looper.getMainLooper().getQueue().removeOnFileDescriptorEventListener(queryfd);
- resNetworkCancel(queryfd); // Closes fd, marks it invalid.
- }
-
- private void addCancellationSignal(@NonNull CancellationSignal cancellationSignal,
- @NonNull FileDescriptor queryfd, @NonNull Object lock) {
- cancellationSignal.setOnCancelListener(() -> {
- synchronized (lock) {
- cancelQuery(queryfd);
- }
- });
- }
-
- private static class DnsAddressAnswer extends DnsPacket {
- private static final String TAG = "DnsResolver.DnsAddressAnswer";
- private static final boolean DBG = false;
-
- private final int mQueryType;
-
- DnsAddressAnswer(@NonNull byte[] data) throws ParseException {
- super(data);
- if ((mHeader.flags & (1 << 15)) == 0) {
- throw new ParseException("Not an answer packet");
- }
- if (mHeader.getRecordCount(QDSECTION) == 0) {
- throw new ParseException("No question found");
- }
- // Expect only one question in question section.
- mQueryType = mRecords[QDSECTION].get(0).nsType;
- }
-
- public @NonNull List<InetAddress> getAddresses() {
- final List<InetAddress> results = new ArrayList<InetAddress>();
- if (mHeader.getRecordCount(ANSECTION) == 0) return results;
-
- for (final DnsRecord ansSec : mRecords[ANSECTION]) {
- // Only support A and AAAA, also ignore answers if query type != answer type.
- int nsType = ansSec.nsType;
- if (nsType != mQueryType || (nsType != TYPE_A && nsType != TYPE_AAAA)) {
- continue;
- }
- try {
- results.add(InetAddress.getByAddress(ansSec.getRR()));
- } catch (UnknownHostException e) {
- if (DBG) {
- Log.w(TAG, "rr to address fail");
- }
- }
- }
- return results;
- }
- }
-
-}
diff --git a/packages/Connectivity/framework/src/android/net/DnsResolverServiceManager.java b/packages/Connectivity/framework/src/android/net/DnsResolverServiceManager.java
deleted file mode 100644
index 79009e8..0000000
--- a/packages/Connectivity/framework/src/android/net/DnsResolverServiceManager.java
+++ /dev/null
@@ -1,45 +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.net;
-
-import android.annotation.NonNull;
-import android.os.IBinder;
-
-/**
- * Provides a way to obtain the DnsResolver binder objects.
- *
- * @hide
- */
-public class DnsResolverServiceManager {
- /** Service name for the DNS resolver. Keep in sync with DnsResolverService.h */
- public static final String DNS_RESOLVER_SERVICE = "dnsresolver";
-
- private final IBinder mResolver;
-
- DnsResolverServiceManager(IBinder resolver) {
- mResolver = resolver;
- }
-
- /**
- * Get an {@link IBinder} representing the DnsResolver stable AIDL interface
- *
- * @return {@link android.net.IDnsResolver} IBinder.
- */
- @NonNull
- public IBinder getService() {
- return mResolver;
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl b/packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl
deleted file mode 100644
index e35f8d4..0000000
--- a/packages/Connectivity/framework/src/android/net/ICaptivePortal.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-/**
- * Interface to inform NetworkMonitor of decisions of app handling captive portal.
- * @hide
- */
-oneway interface ICaptivePortal {
- void appRequest(int request);
- void appResponse(int response);
-}
diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityDiagnosticsCallback.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityDiagnosticsCallback.aidl
deleted file mode 100644
index 82b64a9..0000000
--- a/packages/Connectivity/framework/src/android/net/IConnectivityDiagnosticsCallback.aidl
+++ /dev/null
@@ -1,28 +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 android.net;
-
-import android.net.ConnectivityDiagnosticsManager;
-import android.net.Network;
-
-/** @hide */
-oneway interface IConnectivityDiagnosticsCallback {
- void onConnectivityReportAvailable(in ConnectivityDiagnosticsManager.ConnectivityReport report);
- void onDataStallSuspected(in ConnectivityDiagnosticsManager.DataStallReport report);
- void onNetworkConnectivityReported(in Network n, boolean hasConnectivity);
-}
\ No newline at end of file
diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
deleted file mode 100644
index c434bbc..0000000
--- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
+++ /dev/null
@@ -1,229 +0,0 @@
-/**
- * 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.
- */
-
-package android.net;
-
-import android.app.PendingIntent;
-import android.net.ConnectionInfo;
-import android.net.ConnectivityDiagnosticsManager;
-import android.net.IConnectivityDiagnosticsCallback;
-import android.net.INetworkAgent;
-import android.net.IOnCompleteListener;
-import android.net.INetworkActivityListener;
-import android.net.INetworkOfferCallback;
-import android.net.IQosCallback;
-import android.net.ISocketKeepaliveCallback;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkAgentConfig;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkRequest;
-import android.net.NetworkScore;
-import android.net.NetworkState;
-import android.net.NetworkStateSnapshot;
-import android.net.OemNetworkPreferences;
-import android.net.ProxyInfo;
-import android.net.UidRange;
-import android.net.QosSocketInfo;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Messenger;
-import android.os.ParcelFileDescriptor;
-import android.os.PersistableBundle;
-import android.os.ResultReceiver;
-import android.os.UserHandle;
-
-/**
- * Interface that answers queries about, and allows changing, the
- * state of network connectivity.
- */
-/** {@hide} */
-interface IConnectivityManager
-{
- Network getActiveNetwork();
- Network getActiveNetworkForUid(int uid, boolean ignoreBlocked);
- @UnsupportedAppUsage
- NetworkInfo getActiveNetworkInfo();
- NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked);
- @UnsupportedAppUsage(maxTargetSdk = 28)
- NetworkInfo getNetworkInfo(int networkType);
- NetworkInfo getNetworkInfoForUid(in Network network, int uid, boolean ignoreBlocked);
- @UnsupportedAppUsage
- NetworkInfo[] getAllNetworkInfo();
- Network getNetworkForType(int networkType);
- Network[] getAllNetworks();
- NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
- int userId, String callingPackageName, String callingAttributionTag);
-
- boolean isNetworkSupported(int networkType);
-
- @UnsupportedAppUsage
- LinkProperties getActiveLinkProperties();
- LinkProperties getLinkPropertiesForType(int networkType);
- LinkProperties getLinkProperties(in Network network);
-
- NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName,
- String callingAttributionTag);
-
- @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
- NetworkState[] getAllNetworkState();
-
- List<NetworkStateSnapshot> getAllNetworkStateSnapshots();
-
- boolean isActiveNetworkMetered();
-
- boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress,
- String callingPackageName, String callingAttributionTag);
-
- @UnsupportedAppUsage(maxTargetSdk = 29,
- publicAlternatives = "Use {@code TetheringManager#getLastTetherError} as alternative")
- int getLastTetherError(String iface);
-
- @UnsupportedAppUsage(maxTargetSdk = 29,
- publicAlternatives = "Use {@code TetheringManager#getTetherableIfaces} as alternative")
- String[] getTetherableIfaces();
-
- @UnsupportedAppUsage(maxTargetSdk = 29,
- publicAlternatives = "Use {@code TetheringManager#getTetheredIfaces} as alternative")
- String[] getTetheredIfaces();
-
- @UnsupportedAppUsage(maxTargetSdk = 29,
- publicAlternatives = "Use {@code TetheringManager#getTetheringErroredIfaces} "
- + "as Alternative")
- String[] getTetheringErroredIfaces();
-
- @UnsupportedAppUsage(maxTargetSdk = 29,
- publicAlternatives = "Use {@code TetheringManager#getTetherableUsbRegexs} as alternative")
- String[] getTetherableUsbRegexs();
-
- @UnsupportedAppUsage(maxTargetSdk = 29,
- publicAlternatives = "Use {@code TetheringManager#getTetherableWifiRegexs} as alternative")
- String[] getTetherableWifiRegexs();
-
- @UnsupportedAppUsage(maxTargetSdk = 28)
- void reportInetCondition(int networkType, int percentage);
-
- void reportNetworkConnectivity(in Network network, boolean hasConnectivity);
-
- ProxyInfo getGlobalProxy();
-
- void setGlobalProxy(in ProxyInfo p);
-
- ProxyInfo getProxyForNetwork(in Network nework);
-
- void setRequireVpnForUids(boolean requireVpn, in UidRange[] ranges);
- void setLegacyLockdownVpnEnabled(boolean enabled);
-
- void setProvisioningNotificationVisible(boolean visible, int networkType, in String action);
-
- void setAirplaneMode(boolean enable);
-
- boolean requestBandwidthUpdate(in Network network);
-
- int registerNetworkProvider(in Messenger messenger, in String name);
- void unregisterNetworkProvider(in Messenger messenger);
-
- void declareNetworkRequestUnfulfillable(in NetworkRequest request);
-
- Network registerNetworkAgent(in INetworkAgent na, in NetworkInfo ni, in LinkProperties lp,
- in NetworkCapabilities nc, in NetworkScore score, in NetworkAgentConfig config,
- in int factorySerialNumber);
-
- NetworkRequest requestNetwork(int uid, in NetworkCapabilities networkCapabilities, int reqType,
- in Messenger messenger, int timeoutSec, in IBinder binder, int legacy,
- int callbackFlags, String callingPackageName, String callingAttributionTag);
-
- NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities,
- in PendingIntent operation, String callingPackageName, String callingAttributionTag);
-
- void releasePendingNetworkRequest(in PendingIntent operation);
-
- NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities,
- in Messenger messenger, in IBinder binder, int callbackFlags, String callingPackageName,
- String callingAttributionTag);
-
- void pendingListenForNetwork(in NetworkCapabilities networkCapabilities,
- in PendingIntent operation, String callingPackageName,
- String callingAttributionTag);
-
- void releaseNetworkRequest(in NetworkRequest networkRequest);
-
- void setAcceptUnvalidated(in Network network, boolean accept, boolean always);
- void setAcceptPartialConnectivity(in Network network, boolean accept, boolean always);
- void setAvoidUnvalidated(in Network network);
- void startCaptivePortalApp(in Network network);
- void startCaptivePortalAppInternal(in Network network, in Bundle appExtras);
-
- boolean shouldAvoidBadWifi();
- int getMultipathPreference(in Network Network);
-
- NetworkRequest getDefaultRequest();
-
- int getRestoreDefaultNetworkDelay(int networkType);
-
- void factoryReset();
-
- void startNattKeepalive(in Network network, int intervalSeconds,
- in ISocketKeepaliveCallback cb, String srcAddr, int srcPort, String dstAddr);
-
- void startNattKeepaliveWithFd(in Network network, in ParcelFileDescriptor pfd, int resourceId,
- int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr,
- String dstAddr);
-
- void startTcpKeepalive(in Network network, in ParcelFileDescriptor pfd, int intervalSeconds,
- in ISocketKeepaliveCallback cb);
-
- void stopKeepalive(in Network network, int slot);
-
- String getCaptivePortalServerUrl();
-
- byte[] getNetworkWatchlistConfigHash();
-
- int getConnectionOwnerUid(in ConnectionInfo connectionInfo);
-
- void registerConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback,
- in NetworkRequest request, String callingPackageName);
- void unregisterConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback);
-
- IBinder startOrGetTestNetworkService();
-
- void simulateDataStall(int detectionMethod, long timestampMillis, in Network network,
- in PersistableBundle extras);
-
- void systemReady();
-
- void registerNetworkActivityListener(in INetworkActivityListener l);
-
- void unregisterNetworkActivityListener(in INetworkActivityListener l);
-
- boolean isDefaultNetworkActive();
-
- void registerQosSocketCallback(in QosSocketInfo socketInfo, in IQosCallback callback);
- void unregisterQosCallback(in IQosCallback callback);
-
- void setOemNetworkPreference(in OemNetworkPreferences preference,
- in IOnCompleteListener listener);
-
- void setProfileNetworkPreference(in UserHandle profile, int preference,
- in IOnCompleteListener listener);
-
- int getRestrictBackgroundStatusByCaller();
-
- void offerNetwork(int providerId, in NetworkScore score,
- in NetworkCapabilities caps, in INetworkOfferCallback callback);
- void unofferNetwork(in INetworkOfferCallback callback);
-}
diff --git a/packages/Connectivity/framework/src/android/net/INetworkActivityListener.aidl b/packages/Connectivity/framework/src/android/net/INetworkActivityListener.aidl
deleted file mode 100644
index 79687dd..0000000
--- a/packages/Connectivity/framework/src/android/net/INetworkActivityListener.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Copyright 2013, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.net;
-
-/**
- * @hide
- */
-oneway interface INetworkActivityListener
-{
- void onNetworkActive();
-}
diff --git a/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
deleted file mode 100644
index d941d4b..0000000
--- a/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
+++ /dev/null
@@ -1,51 +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 perNmissions and
- * limitations under the License.
- */
-package android.net;
-
-import android.net.NattKeepalivePacketData;
-import android.net.QosFilterParcelable;
-import android.net.TcpKeepalivePacketData;
-
-import android.net.INetworkAgentRegistry;
-
-/**
- * Interface to notify NetworkAgent of connectivity events.
- * @hide
- */
-oneway interface INetworkAgent {
- void onRegistered(in INetworkAgentRegistry registry);
- void onDisconnected();
- void onBandwidthUpdateRequested();
- void onValidationStatusChanged(int validationStatus,
- in @nullable String captivePortalUrl);
- void onSaveAcceptUnvalidated(boolean acceptUnvalidated);
- void onStartNattSocketKeepalive(int slot, int intervalDurationMs,
- in NattKeepalivePacketData packetData);
- void onStartTcpSocketKeepalive(int slot, int intervalDurationMs,
- in TcpKeepalivePacketData packetData);
- void onStopSocketKeepalive(int slot);
- void onSignalStrengthThresholdsUpdated(in int[] thresholds);
- void onPreventAutomaticReconnect();
- void onAddNattKeepalivePacketFilter(int slot,
- in NattKeepalivePacketData packetData);
- void onAddTcpKeepalivePacketFilter(int slot,
- in TcpKeepalivePacketData packetData);
- void onRemoveKeepalivePacketFilter(int slot);
- void onQosFilterCallbackRegistered(int qosCallbackId, in QosFilterParcelable filterParcel);
- void onQosCallbackUnregistered(int qosCallbackId);
- void onNetworkCreated();
- void onNetworkDestroyed();
-}
diff --git a/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
deleted file mode 100644
index 9a58add..0000000
--- a/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
+++ /dev/null
@@ -1,46 +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 perNmissions and
- * limitations under the License.
- */
-package android.net;
-
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkScore;
-import android.net.QosSession;
-import android.telephony.data.EpsBearerQosSessionAttributes;
-import android.telephony.data.NrQosSessionAttributes;
-
-/**
- * Interface for NetworkAgents to send network properties.
- * @hide
- */
-oneway interface INetworkAgentRegistry {
- void sendNetworkCapabilities(in NetworkCapabilities nc);
- void sendLinkProperties(in LinkProperties lp);
- // TODO: consider replacing this by "markConnected()" and removing
- void sendNetworkInfo(in NetworkInfo info);
- void sendScore(in NetworkScore score);
- void sendExplicitlySelected(boolean explicitlySelected, boolean acceptPartial);
- void sendSocketKeepaliveEvent(int slot, int reason);
- void sendUnderlyingNetworks(in @nullable List<Network> networks);
- void sendEpsQosSessionAvailable(int callbackId, in QosSession session, in EpsBearerQosSessionAttributes attributes);
- void sendNrQosSessionAvailable(int callbackId, in QosSession session, in NrQosSessionAttributes attributes);
- void sendQosSessionLost(int qosCallbackId, in QosSession session);
- void sendQosCallbackError(int qosCallbackId, int exceptionType);
- void sendTeardownDelayMs(int teardownDelayMs);
- void sendLingerDuration(int durationMs);
-}
diff --git a/packages/Connectivity/framework/src/android/net/INetworkOfferCallback.aidl b/packages/Connectivity/framework/src/android/net/INetworkOfferCallback.aidl
deleted file mode 100644
index ecfba21..0000000
--- a/packages/Connectivity/framework/src/android/net/INetworkOfferCallback.aidl
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.net.NetworkRequest;
-
-/**
- * A callback registered with connectivity by network providers together with
- * a NetworkOffer.
- *
- * When the network for this offer is needed to satisfy some application or
- * system component, connectivity will call onNetworkNeeded on this callback.
- * When this happens, the provider should try and bring up the network.
- *
- * When the network for this offer is no longer needed, for example because
- * the application has withdrawn the request or if the request is being
- * satisfied by a network that this offer will never be able to beat,
- * connectivity calls onNetworkUnneeded. When this happens, the provider
- * should stop trying to bring up the network, or tear it down if it has
- * already been brought up.
- *
- * When NetworkProvider#offerNetwork is called, the provider can expect to
- * immediately receive all requests that can be fulfilled by that offer and
- * are not already satisfied by a better network. It is possible no such
- * request is currently outstanding, because no requests have been made that
- * can be satisfied by this offer, or because all such requests are already
- * satisfied by a better network.
- * onNetworkNeeded can be called at any time after registration and until the
- * offer is withdrawn with NetworkProvider#unofferNetwork is called. This
- * typically happens when a new network request is filed by an application,
- * or when the network satisfying a request disconnects and this offer now
- * stands a chance to supply the best network for it.
- *
- * @hide
- */
-oneway interface INetworkOfferCallback {
- /**
- * Called when a network for this offer is needed to fulfill this request.
- * @param networkRequest the request to satisfy
- */
- void onNetworkNeeded(in NetworkRequest networkRequest);
-
- /**
- * Informs the registrant that the offer is no longer valuable to fulfill this request.
- */
- void onNetworkUnneeded(in NetworkRequest networkRequest);
-}
diff --git a/packages/Connectivity/framework/src/android/net/IOnCompleteListener.aidl b/packages/Connectivity/framework/src/android/net/IOnCompleteListener.aidl
deleted file mode 100644
index 4bb89f6c..0000000
--- a/packages/Connectivity/framework/src/android/net/IOnCompleteListener.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- *
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-/** @hide */
-oneway interface IOnCompleteListener {
- void onComplete();
-}
diff --git a/packages/Connectivity/framework/src/android/net/IQosCallback.aidl b/packages/Connectivity/framework/src/android/net/IQosCallback.aidl
deleted file mode 100644
index c973541..0000000
--- a/packages/Connectivity/framework/src/android/net/IQosCallback.aidl
+++ /dev/null
@@ -1,37 +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.net;
-
-import android.os.Bundle;
-import android.net.QosSession;
-import android.telephony.data.EpsBearerQosSessionAttributes;
-import android.telephony.data.NrQosSessionAttributes;
-
-/**
- * AIDL interface for QosCallback
- *
- * @hide
- */
-oneway interface IQosCallback
-{
- void onQosEpsBearerSessionAvailable(in QosSession session,
- in EpsBearerQosSessionAttributes attributes);
- void onNrQosSessionAvailable(in QosSession session,
- in NrQosSessionAttributes attributes);
- void onQosSessionLost(in QosSession session);
- void onError(in int type);
-}
diff --git a/packages/Connectivity/framework/src/android/net/ISocketKeepaliveCallback.aidl b/packages/Connectivity/framework/src/android/net/ISocketKeepaliveCallback.aidl
deleted file mode 100644
index 020fbca..0000000
--- a/packages/Connectivity/framework/src/android/net/ISocketKeepaliveCallback.aidl
+++ /dev/null
@@ -1,34 +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 android.net;
-
-/**
- * Callback to provide status changes of keepalive offload.
- *
- * @hide
- */
-oneway interface ISocketKeepaliveCallback
-{
- /** The keepalive was successfully started. */
- void onStarted(int slot);
- /** The keepalive was successfully stopped. */
- void onStopped();
- /** The keepalive was stopped because of an error. */
- void onError(int error);
- /** The keepalive on a TCP socket was stopped because the socket received data. */
- void onDataReceived();
-}
diff --git a/packages/Connectivity/framework/src/android/net/ITestNetworkManager.aidl b/packages/Connectivity/framework/src/android/net/ITestNetworkManager.aidl
deleted file mode 100644
index 2a863ad..0000000
--- a/packages/Connectivity/framework/src/android/net/ITestNetworkManager.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.TestNetworkInterface;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-
-/**
- * Interface that allows for creation and management of test-only networks.
- *
- * @hide
- */
-interface ITestNetworkManager
-{
- TestNetworkInterface createTunInterface(in LinkAddress[] linkAddrs);
- TestNetworkInterface createTapInterface();
-
- void setupTestNetwork(in String iface, in LinkProperties lp, in boolean isMetered,
- in int[] administratorUids, in IBinder binder);
-
- void teardownTestNetwork(int netId);
-}
diff --git a/packages/Connectivity/framework/src/android/net/InetAddressCompat.java b/packages/Connectivity/framework/src/android/net/InetAddressCompat.java
deleted file mode 100644
index 6b7e75c..0000000
--- a/packages/Connectivity/framework/src/android/net/InetAddressCompat.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.util.Log;
-
-import java.lang.reflect.InvocationTargetException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-/**
- * Compatibility utility for InetAddress core platform APIs.
- *
- * Connectivity has access to such APIs, but they are not part of the module_current stubs yet
- * (only core_current). Most stable core platform APIs are included manually in the connectivity
- * build rules, but because InetAddress is also part of the base java SDK that is earlier on the
- * classpath, the extra core platform APIs are not seen.
- *
- * TODO (b/183097033): remove this utility as soon as core_current is part of module_current
- * @hide
- */
-public class InetAddressCompat {
-
- /**
- * @see InetAddress#clearDnsCache()
- */
- public static void clearDnsCache() {
- try {
- InetAddress.class.getMethod("clearDnsCache").invoke(null);
- } catch (InvocationTargetException e) {
- if (e.getCause() instanceof RuntimeException) {
- throw (RuntimeException) e.getCause();
- }
- throw new IllegalStateException("Unknown InvocationTargetException", e.getCause());
- } catch (IllegalAccessException | NoSuchMethodException e) {
- Log.wtf(InetAddressCompat.class.getSimpleName(), "Error clearing DNS cache", e);
- }
- }
-
- /**
- * @see InetAddress#getAllByNameOnNet(String, int)
- */
- public static InetAddress[] getAllByNameOnNet(String host, int netId) throws
- UnknownHostException {
- return (InetAddress[]) callGetByNameMethod("getAllByNameOnNet", host, netId);
- }
-
- /**
- * @see InetAddress#getByNameOnNet(String, int)
- */
- public static InetAddress getByNameOnNet(String host, int netId) throws
- UnknownHostException {
- return (InetAddress) callGetByNameMethod("getByNameOnNet", host, netId);
- }
-
- private static Object callGetByNameMethod(String method, String host, int netId)
- throws UnknownHostException {
- try {
- return InetAddress.class.getMethod(method, String.class, int.class)
- .invoke(null, host, netId);
- } catch (InvocationTargetException e) {
- if (e.getCause() instanceof UnknownHostException) {
- throw (UnknownHostException) e.getCause();
- }
- if (e.getCause() instanceof RuntimeException) {
- throw (RuntimeException) e.getCause();
- }
- throw new IllegalStateException("Unknown InvocationTargetException", e.getCause());
- } catch (IllegalAccessException | NoSuchMethodException e) {
- Log.wtf(InetAddressCompat.class.getSimpleName(), "Error calling " + method, e);
- throw new IllegalStateException("Error querying via " + method, e);
- }
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/InetAddresses.java b/packages/Connectivity/framework/src/android/net/InetAddresses.java
deleted file mode 100644
index 01b795e..0000000
--- a/packages/Connectivity/framework/src/android/net/InetAddresses.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.NonNull;
-
-import libcore.net.InetAddressUtils;
-
-import java.net.InetAddress;
-
-/**
- * Utility methods for {@link InetAddress} implementations.
- */
-public class InetAddresses {
-
- private InetAddresses() {}
-
- /**
- * Checks to see if the {@code address} is a numeric address (such as {@code "192.0.2.1"} or
- * {@code "2001:db8::1:2"}).
- *
- * <p>A numeric address is either an IPv4 address containing exactly 4 decimal numbers or an
- * IPv6 numeric address. IPv4 addresses that consist of either hexadecimal or octal digits or
- * do not have exactly 4 numbers are not treated as numeric.
- *
- * <p>This method will never do a DNS lookup.
- *
- * @param address the address to parse.
- * @return true if the supplied address is numeric, false otherwise.
- */
- public static boolean isNumericAddress(@NonNull String address) {
- return InetAddressUtils.isNumericAddress(address);
- }
-
- /**
- * Returns an InetAddress corresponding to the given numeric address (such
- * as {@code "192.168.0.1"} or {@code "2001:4860:800d::68"}).
- *
- * <p>See {@link #isNumericAddress(String)} (String)} for a definition as to what constitutes a
- * numeric address.
- *
- * <p>This method will never do a DNS lookup.
- *
- * @param address the address to parse, must be numeric.
- * @return an {@link InetAddress} instance corresponding to the address.
- * @throws IllegalArgumentException if {@code address} is not a numeric address.
- */
- public static @NonNull InetAddress parseNumericAddress(@NonNull String address) {
- return InetAddressUtils.parseNumericAddress(address);
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/InvalidPacketException.java b/packages/Connectivity/framework/src/android/net/InvalidPacketException.java
deleted file mode 100644
index 1873d77..0000000
--- a/packages/Connectivity/framework/src/android/net/InvalidPacketException.java
+++ /dev/null
@@ -1,66 +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 android.net;
-
-import android.annotation.IntDef;
-import android.annotation.SystemApi;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Thrown when a packet is invalid.
- * @hide
- */
-@SystemApi
-public final class InvalidPacketException extends Exception {
- private final int mError;
-
- // Must match SocketKeepalive#ERROR_INVALID_IP_ADDRESS.
- /** Invalid IP address. */
- public static final int ERROR_INVALID_IP_ADDRESS = -21;
-
- // Must match SocketKeepalive#ERROR_INVALID_PORT.
- /** Invalid port number. */
- public static final int ERROR_INVALID_PORT = -22;
-
- // Must match SocketKeepalive#ERROR_INVALID_LENGTH.
- /** Invalid packet length. */
- public static final int ERROR_INVALID_LENGTH = -23;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "ERROR_" }, value = {
- ERROR_INVALID_IP_ADDRESS,
- ERROR_INVALID_PORT,
- ERROR_INVALID_LENGTH
- })
- public @interface ErrorCode {}
-
- /**
- * This packet is invalid.
- * See the error code for details.
- */
- public InvalidPacketException(@ErrorCode final int error) {
- this.mError = error;
- }
-
- /** Get error code. */
- public int getError() {
- return mError;
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/IpConfiguration.java b/packages/Connectivity/framework/src/android/net/IpConfiguration.java
deleted file mode 100644
index d5f8b2e..0000000
--- a/packages/Connectivity/framework/src/android/net/IpConfiguration.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/**
- * A class representing a configured network.
- * @hide
- */
-@SystemApi
-public final class IpConfiguration implements Parcelable {
- private static final String TAG = "IpConfiguration";
-
- // This enum has been used by apps through reflection for many releases.
- // Therefore they can't just be removed. Duplicating these constants to
- // give an alternate SystemApi is a worse option than exposing them.
- @SuppressLint("Enum")
- public enum IpAssignment {
- /* Use statically configured IP settings. Configuration can be accessed
- * with staticIpConfiguration */
- STATIC,
- /* Use dynamically configured IP settings */
- DHCP,
- /* no IP details are assigned, this is used to indicate
- * that any existing IP settings should be retained */
- UNASSIGNED
- }
-
- /** @hide */
- public IpAssignment ipAssignment;
-
- /** @hide */
- public StaticIpConfiguration staticIpConfiguration;
-
- // This enum has been used by apps through reflection for many releases.
- // Therefore they can't just be removed. Duplicating these constants to
- // give an alternate SystemApi is a worse option than exposing them.
- @SuppressLint("Enum")
- public enum ProxySettings {
- /* No proxy is to be used. Any existing proxy settings
- * should be cleared. */
- NONE,
- /* Use statically configured proxy. Configuration can be accessed
- * with httpProxy. */
- STATIC,
- /* no proxy details are assigned, this is used to indicate
- * that any existing proxy settings should be retained */
- UNASSIGNED,
- /* Use a Pac based proxy.
- */
- PAC
- }
-
- /** @hide */
- public ProxySettings proxySettings;
-
- /** @hide */
- @UnsupportedAppUsage
- public ProxyInfo httpProxy;
-
- private void init(IpAssignment ipAssignment,
- ProxySettings proxySettings,
- StaticIpConfiguration staticIpConfiguration,
- ProxyInfo httpProxy) {
- this.ipAssignment = ipAssignment;
- this.proxySettings = proxySettings;
- this.staticIpConfiguration = (staticIpConfiguration == null) ?
- null : new StaticIpConfiguration(staticIpConfiguration);
- this.httpProxy = (httpProxy == null) ?
- null : new ProxyInfo(httpProxy);
- }
-
- public IpConfiguration() {
- init(IpAssignment.UNASSIGNED, ProxySettings.UNASSIGNED, null, null);
- }
-
- /** @hide */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public IpConfiguration(IpAssignment ipAssignment,
- ProxySettings proxySettings,
- StaticIpConfiguration staticIpConfiguration,
- ProxyInfo httpProxy) {
- init(ipAssignment, proxySettings, staticIpConfiguration, httpProxy);
- }
-
- public IpConfiguration(@NonNull IpConfiguration source) {
- this();
- if (source != null) {
- init(source.ipAssignment, source.proxySettings,
- source.staticIpConfiguration, source.httpProxy);
- }
- }
-
- public @NonNull IpAssignment getIpAssignment() {
- return ipAssignment;
- }
-
- public void setIpAssignment(@NonNull IpAssignment ipAssignment) {
- this.ipAssignment = ipAssignment;
- }
-
- public @Nullable StaticIpConfiguration getStaticIpConfiguration() {
- return staticIpConfiguration;
- }
-
- public void setStaticIpConfiguration(@Nullable StaticIpConfiguration staticIpConfiguration) {
- this.staticIpConfiguration = staticIpConfiguration;
- }
-
- public @NonNull ProxySettings getProxySettings() {
- return proxySettings;
- }
-
- public void setProxySettings(@NonNull ProxySettings proxySettings) {
- this.proxySettings = proxySettings;
- }
-
- public @Nullable ProxyInfo getHttpProxy() {
- return httpProxy;
- }
-
- public void setHttpProxy(@Nullable ProxyInfo httpProxy) {
- this.httpProxy = httpProxy;
- }
-
- @Override
- public String toString() {
- StringBuilder sbuf = new StringBuilder();
- sbuf.append("IP assignment: " + ipAssignment.toString());
- sbuf.append("\n");
- if (staticIpConfiguration != null) {
- sbuf.append("Static configuration: " + staticIpConfiguration.toString());
- sbuf.append("\n");
- }
- sbuf.append("Proxy settings: " + proxySettings.toString());
- sbuf.append("\n");
- if (httpProxy != null) {
- sbuf.append("HTTP proxy: " + httpProxy.toString());
- sbuf.append("\n");
- }
-
- return sbuf.toString();
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (o == this) {
- return true;
- }
-
- if (!(o instanceof IpConfiguration)) {
- return false;
- }
-
- IpConfiguration other = (IpConfiguration) o;
- return this.ipAssignment == other.ipAssignment &&
- this.proxySettings == other.proxySettings &&
- Objects.equals(this.staticIpConfiguration, other.staticIpConfiguration) &&
- Objects.equals(this.httpProxy, other.httpProxy);
- }
-
- @Override
- public int hashCode() {
- return 13 + (staticIpConfiguration != null ? staticIpConfiguration.hashCode() : 0) +
- 17 * ipAssignment.ordinal() +
- 47 * proxySettings.ordinal() +
- 83 * httpProxy.hashCode();
- }
-
- /** Implement the Parcelable interface */
- public int describeContents() {
- return 0;
- }
-
- /** Implement the Parcelable interface */
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeString(ipAssignment.name());
- dest.writeString(proxySettings.name());
- dest.writeParcelable(staticIpConfiguration, flags);
- dest.writeParcelable(httpProxy, flags);
- }
-
- /** Implement the Parcelable interface */
- public static final @NonNull Creator<IpConfiguration> CREATOR =
- new Creator<IpConfiguration>() {
- public IpConfiguration createFromParcel(Parcel in) {
- IpConfiguration config = new IpConfiguration();
- config.ipAssignment = IpAssignment.valueOf(in.readString());
- config.proxySettings = ProxySettings.valueOf(in.readString());
- config.staticIpConfiguration = in.readParcelable(null);
- config.httpProxy = in.readParcelable(null);
- return config;
- }
-
- public IpConfiguration[] newArray(int size) {
- return new IpConfiguration[size];
- }
- };
-}
diff --git a/packages/Connectivity/framework/src/android/net/IpPrefix.java b/packages/Connectivity/framework/src/android/net/IpPrefix.java
deleted file mode 100644
index bf4481a..0000000
--- a/packages/Connectivity/framework/src/android/net/IpPrefix.java
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Pair;
-
-import com.android.net.module.util.NetUtils;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.Comparator;
-
-/**
- * This class represents an IP prefix, i.e., a contiguous block of IP addresses aligned on a
- * power of two boundary (also known as an "IP subnet"). A prefix is specified by two pieces of
- * information:
- *
- * <ul>
- * <li>A starting IP address (IPv4 or IPv6). This is the first IP address of the prefix.
- * <li>A prefix length. This specifies the length of the prefix by specifing the number of bits
- * in the IP address, starting from the most significant bit in network byte order, that
- * are constant for all addresses in the prefix.
- * </ul>
- *
- * For example, the prefix <code>192.0.2.0/24</code> covers the 256 IPv4 addresses from
- * <code>192.0.2.0</code> to <code>192.0.2.255</code>, inclusive, and the prefix
- * <code>2001:db8:1:2</code> covers the 2^64 IPv6 addresses from <code>2001:db8:1:2::</code> to
- * <code>2001:db8:1:2:ffff:ffff:ffff:ffff</code>, inclusive.
- *
- * Objects of this class are immutable.
- */
-public final class IpPrefix implements Parcelable {
- private final byte[] address; // network byte order
- private final int prefixLength;
-
- private void checkAndMaskAddressAndPrefixLength() {
- if (address.length != 4 && address.length != 16) {
- throw new IllegalArgumentException(
- "IpPrefix has " + address.length + " bytes which is neither 4 nor 16");
- }
- NetUtils.maskRawAddress(address, prefixLength);
- }
-
- /**
- * Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in
- * network byte order and a prefix length. Silently truncates the address to the prefix length,
- * so for example {@code 192.0.2.1/24} is silently converted to {@code 192.0.2.0/24}.
- *
- * @param address the IP address. Must be non-null and exactly 4 or 16 bytes long.
- * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
- *
- * @hide
- */
- public IpPrefix(@NonNull byte[] address, @IntRange(from = 0, to = 128) int prefixLength) {
- this.address = address.clone();
- this.prefixLength = prefixLength;
- checkAndMaskAddressAndPrefixLength();
- }
-
- /**
- * Constructs a new {@code IpPrefix} from an IPv4 or IPv6 address and a prefix length. Silently
- * truncates the address to the prefix length, so for example {@code 192.0.2.1/24} is silently
- * converted to {@code 192.0.2.0/24}.
- *
- * @param address the IP address. Must be non-null.
- * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
- * @hide
- */
- @SystemApi
- public IpPrefix(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength) {
- // We don't reuse the (byte[], int) constructor because it calls clone() on the byte array,
- // which is unnecessary because getAddress() already returns a clone.
- this.address = address.getAddress();
- this.prefixLength = prefixLength;
- checkAndMaskAddressAndPrefixLength();
- }
-
- /**
- * Constructs a new IpPrefix from a string such as "192.0.2.1/24" or "2001:db8::1/64".
- * Silently truncates the address to the prefix length, so for example {@code 192.0.2.1/24}
- * is silently converted to {@code 192.0.2.0/24}.
- *
- * @param prefix the prefix to parse
- *
- * @hide
- */
- @SystemApi
- public IpPrefix(@NonNull String prefix) {
- // We don't reuse the (InetAddress, int) constructor because "error: call to this must be
- // first statement in constructor". We could factor out setting the member variables to an
- // init() method, but if we did, then we'd have to make the members non-final, or "error:
- // cannot assign a value to final variable address". So we just duplicate the code here.
- Pair<InetAddress, Integer> ipAndMask = NetworkUtils.legacyParseIpAndMask(prefix);
- this.address = ipAndMask.first.getAddress();
- this.prefixLength = ipAndMask.second;
- checkAndMaskAddressAndPrefixLength();
- }
-
- /**
- * Compares this {@code IpPrefix} object against the specified object in {@code obj}. Two
- * objects are equal if they have the same startAddress and prefixLength.
- *
- * @param obj the object to be tested for equality.
- * @return {@code true} if both objects are equal, {@code false} otherwise.
- */
- @Override
- public boolean equals(@Nullable Object obj) {
- if (!(obj instanceof IpPrefix)) {
- return false;
- }
- IpPrefix that = (IpPrefix) obj;
- return Arrays.equals(this.address, that.address) && this.prefixLength == that.prefixLength;
- }
-
- /**
- * Gets the hashcode of the represented IP prefix.
- *
- * @return the appropriate hashcode value.
- */
- @Override
- public int hashCode() {
- return Arrays.hashCode(address) + 11 * prefixLength;
- }
-
- /**
- * Returns a copy of the first IP address in the prefix. Modifying the returned object does not
- * change this object's contents.
- *
- * @return the address in the form of a byte array.
- */
- public @NonNull InetAddress getAddress() {
- try {
- return InetAddress.getByAddress(address);
- } catch (UnknownHostException e) {
- // Cannot happen. InetAddress.getByAddress can only throw an exception if the byte
- // array is the wrong length, but we check that in the constructor.
- throw new IllegalArgumentException("Address is invalid");
- }
- }
-
- /**
- * Returns a copy of the IP address bytes in network order (the highest order byte is the zeroth
- * element). Modifying the returned array does not change this object's contents.
- *
- * @return the address in the form of a byte array.
- */
- public @NonNull byte[] getRawAddress() {
- return address.clone();
- }
-
- /**
- * Returns the prefix length of this {@code IpPrefix}.
- *
- * @return the prefix length.
- */
- @IntRange(from = 0, to = 128)
- public int getPrefixLength() {
- return prefixLength;
- }
-
- /**
- * Determines whether the prefix contains the specified address.
- *
- * @param address An {@link InetAddress} to test.
- * @return {@code true} if the prefix covers the given address. {@code false} otherwise.
- */
- public boolean contains(@NonNull InetAddress address) {
- byte[] addrBytes = address.getAddress();
- if (addrBytes == null || addrBytes.length != this.address.length) {
- return false;
- }
- NetUtils.maskRawAddress(addrBytes, prefixLength);
- return Arrays.equals(this.address, addrBytes);
- }
-
- /**
- * Returns whether the specified prefix is entirely contained in this prefix.
- *
- * Note this is mathematical inclusion, so a prefix is always contained within itself.
- * @param otherPrefix the prefix to test
- * @hide
- */
- public boolean containsPrefix(@NonNull IpPrefix otherPrefix) {
- if (otherPrefix.getPrefixLength() < prefixLength) return false;
- final byte[] otherAddress = otherPrefix.getRawAddress();
- NetUtils.maskRawAddress(otherAddress, prefixLength);
- return Arrays.equals(otherAddress, address);
- }
-
- /**
- * @hide
- */
- public boolean isIPv6() {
- return getAddress() instanceof Inet6Address;
- }
-
- /**
- * @hide
- */
- public boolean isIPv4() {
- return getAddress() instanceof Inet4Address;
- }
-
- /**
- * Returns a string representation of this {@code IpPrefix}.
- *
- * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}.
- */
- public String toString() {
- try {
- return InetAddress.getByAddress(address).getHostAddress() + "/" + prefixLength;
- } catch(UnknownHostException e) {
- // Cosmic rays?
- throw new IllegalStateException("IpPrefix with invalid address! Shouldn't happen.", e);
- }
- }
-
- /**
- * Implement the Parcelable interface.
- */
- public int describeContents() {
- return 0;
- }
-
- /**
- * Implement the Parcelable interface.
- */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeByteArray(address);
- dest.writeInt(prefixLength);
- }
-
- /**
- * Returns a comparator ordering IpPrefixes by length, shorter to longer.
- * Contents of the address will break ties.
- * @hide
- */
- public static Comparator<IpPrefix> lengthComparator() {
- return new Comparator<IpPrefix>() {
- @Override
- public int compare(IpPrefix prefix1, IpPrefix prefix2) {
- if (prefix1.isIPv4()) {
- if (prefix2.isIPv6()) return -1;
- } else {
- if (prefix2.isIPv4()) return 1;
- }
- final int p1len = prefix1.getPrefixLength();
- final int p2len = prefix2.getPrefixLength();
- if (p1len < p2len) return -1;
- if (p2len < p1len) return 1;
- final byte[] a1 = prefix1.address;
- final byte[] a2 = prefix2.address;
- final int len = a1.length < a2.length ? a1.length : a2.length;
- for (int i = 0; i < len; ++i) {
- if (a1[i] < a2[i]) return -1;
- if (a1[i] > a2[i]) return 1;
- }
- if (a2.length < len) return 1;
- if (a1.length < len) return -1;
- return 0;
- }
- };
- }
-
- /**
- * Implement the Parcelable interface.
- */
- public static final @android.annotation.NonNull Creator<IpPrefix> CREATOR =
- new Creator<IpPrefix>() {
- public IpPrefix createFromParcel(Parcel in) {
- byte[] address = in.createByteArray();
- int prefixLength = in.readInt();
- return new IpPrefix(address, prefixLength);
- }
-
- public IpPrefix[] newArray(int size) {
- return new IpPrefix[size];
- }
- };
-}
diff --git a/packages/Connectivity/framework/src/android/net/KeepalivePacketData.java b/packages/Connectivity/framework/src/android/net/KeepalivePacketData.java
deleted file mode 100644
index 5877f1f..0000000
--- a/packages/Connectivity/framework/src/android/net/KeepalivePacketData.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS;
-import static android.net.InvalidPacketException.ERROR_INVALID_PORT;
-
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.util.Log;
-
-import com.android.net.module.util.IpUtils;
-
-import java.net.InetAddress;
-
-/**
- * Represents the actual packets that are sent by the
- * {@link android.net.SocketKeepalive} API.
- * @hide
- */
-@SystemApi
-public class KeepalivePacketData {
- private static final String TAG = "KeepalivePacketData";
-
- /** Source IP address */
- @NonNull
- private final InetAddress mSrcAddress;
-
- /** Destination IP address */
- @NonNull
- private final InetAddress mDstAddress;
-
- /** Source port */
- private final int mSrcPort;
-
- /** Destination port */
- private final int mDstPort;
-
- /** Packet data. A raw byte string of packet data, not including the link-layer header. */
- private final byte[] mPacket;
-
- // Note: If you add new fields, please modify the parcelling code in the child classes.
-
-
- // This should only be constructed via static factory methods, such as
- // nattKeepalivePacket.
- /**
- * A holding class for data necessary to build a keepalive packet.
- */
- protected KeepalivePacketData(@NonNull InetAddress srcAddress,
- @IntRange(from = 0, to = 65535) int srcPort, @NonNull InetAddress dstAddress,
- @IntRange(from = 0, to = 65535) int dstPort,
- @NonNull byte[] data) throws InvalidPacketException {
- this.mSrcAddress = srcAddress;
- this.mDstAddress = dstAddress;
- this.mSrcPort = srcPort;
- this.mDstPort = dstPort;
- this.mPacket = data;
-
- // Check we have two IP addresses of the same family.
- if (srcAddress == null || dstAddress == null || !srcAddress.getClass().getName()
- .equals(dstAddress.getClass().getName())) {
- Log.e(TAG, "Invalid or mismatched InetAddresses in KeepalivePacketData");
- throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
- }
-
- // Check the ports.
- if (!IpUtils.isValidUdpOrTcpPort(srcPort) || !IpUtils.isValidUdpOrTcpPort(dstPort)) {
- Log.e(TAG, "Invalid ports in KeepalivePacketData");
- throw new InvalidPacketException(ERROR_INVALID_PORT);
- }
- }
-
- /** Get source IP address. */
- @NonNull
- public InetAddress getSrcAddress() {
- return mSrcAddress;
- }
-
- /** Get destination IP address. */
- @NonNull
- public InetAddress getDstAddress() {
- return mDstAddress;
- }
-
- /** Get source port number. */
- public int getSrcPort() {
- return mSrcPort;
- }
-
- /** Get destination port number. */
- public int getDstPort() {
- return mDstPort;
- }
-
- /**
- * Returns a byte array of the given packet data.
- */
- @NonNull
- public byte[] getPacket() {
- return mPacket.clone();
- }
-
-}
diff --git a/packages/Connectivity/framework/src/android/net/LinkAddress.java b/packages/Connectivity/framework/src/android/net/LinkAddress.java
deleted file mode 100644
index d48b8c7..0000000
--- a/packages/Connectivity/framework/src/android/net/LinkAddress.java
+++ /dev/null
@@ -1,549 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.system.OsConstants.IFA_F_DADFAILED;
-import static android.system.OsConstants.IFA_F_DEPRECATED;
-import static android.system.OsConstants.IFA_F_OPTIMISTIC;
-import static android.system.OsConstants.IFA_F_PERMANENT;
-import static android.system.OsConstants.IFA_F_TENTATIVE;
-import static android.system.OsConstants.RT_SCOPE_HOST;
-import static android.system.OsConstants.RT_SCOPE_LINK;
-import static android.system.OsConstants.RT_SCOPE_SITE;
-import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
-
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.util.Pair;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InterfaceAddress;
-import java.net.UnknownHostException;
-import java.util.Objects;
-
-/**
- * Identifies an IP address on a network link.
- *
- * A {@code LinkAddress} consists of:
- * <ul>
- * <li>An IP address and prefix length (e.g., {@code 2001:db8::1/64} or {@code 192.0.2.1/24}).
- * The address must be unicast, as multicast addresses cannot be assigned to interfaces.
- * <li>Address flags: A bitmask of {@code OsConstants.IFA_F_*} values representing properties
- * of the address (e.g., {@code android.system.OsConstants.IFA_F_OPTIMISTIC}).
- * <li>Address scope: One of the {@code OsConstants.IFA_F_*} values; defines the scope in which
- * the address is unique (e.g.,
- * {@code android.system.OsConstants.RT_SCOPE_LINK} or
- * {@code android.system.OsConstants.RT_SCOPE_UNIVERSE}).
- * </ul>
- */
-public class LinkAddress implements Parcelable {
-
- /**
- * Indicates the deprecation or expiration time is unknown
- * @hide
- */
- @SystemApi
- public static final long LIFETIME_UNKNOWN = -1;
-
- /**
- * Indicates this address is permanent.
- * @hide
- */
- @SystemApi
- public static final long LIFETIME_PERMANENT = Long.MAX_VALUE;
-
- /**
- * IPv4 or IPv6 address.
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private InetAddress address;
-
- /**
- * Prefix length.
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private int prefixLength;
-
- /**
- * Address flags. A bitmask of {@code IFA_F_*} values. Note that {@link #getFlags()} may not
- * return these exact values. For example, it may set or clear the {@code IFA_F_DEPRECATED}
- * flag depending on the current preferred lifetime.
- */
- private int flags;
-
- /**
- * Address scope. One of the RT_SCOPE_* constants.
- */
- private int scope;
-
- /**
- * The time, as reported by {@link SystemClock#elapsedRealtime}, when this LinkAddress will be
- * or was deprecated. At the time existing connections can still use this address until it
- * expires, but new connections should use the new address. {@link #LIFETIME_UNKNOWN} indicates
- * this information is not available. {@link #LIFETIME_PERMANENT} indicates this
- * {@link LinkAddress} will never be deprecated.
- */
- private long deprecationTime;
-
- /**
- * The time, as reported by {@link SystemClock#elapsedRealtime}, when this {@link LinkAddress}
- * will expire and be removed from the interface. {@link #LIFETIME_UNKNOWN} indicates this
- * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
- * will never expire.
- */
- private long expirationTime;
-
- /**
- * Utility function to determines the scope of a unicast address. Per RFC 4291 section 2.5 and
- * RFC 6724 section 3.2.
- * @hide
- */
- private static int scopeForUnicastAddress(InetAddress addr) {
- if (addr.isAnyLocalAddress()) {
- return RT_SCOPE_HOST;
- }
-
- if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) {
- return RT_SCOPE_LINK;
- }
-
- // isSiteLocalAddress() returns true for private IPv4 addresses, but RFC 6724 section 3.2
- // says that they are assigned global scope.
- if (!(addr instanceof Inet4Address) && addr.isSiteLocalAddress()) {
- return RT_SCOPE_SITE;
- }
-
- return RT_SCOPE_UNIVERSE;
- }
-
- /**
- * Utility function to check if |address| is a Unique Local IPv6 Unicast Address
- * (a.k.a. "ULA"; RFC 4193).
- *
- * Per RFC 4193 section 8, fc00::/7 identifies these addresses.
- */
- private boolean isIpv6ULA() {
- if (isIpv6()) {
- byte[] bytes = address.getAddress();
- return ((bytes[0] & (byte)0xfe) == (byte)0xfc);
- }
- return false;
- }
-
- /**
- * @return true if the address is IPv6.
- * @hide
- */
- @SystemApi
- public boolean isIpv6() {
- return address instanceof Inet6Address;
- }
-
- /**
- * For backward compatibility.
- * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
- * just yet.
- * @return true if the address is IPv6.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
- public boolean isIPv6() {
- return isIpv6();
- }
-
- /**
- * @return true if the address is IPv4 or is a mapped IPv4 address.
- * @hide
- */
- @SystemApi
- public boolean isIpv4() {
- return address instanceof Inet4Address;
- }
-
- /**
- * Utility function for the constructors.
- */
- private void init(InetAddress address, int prefixLength, int flags, int scope,
- long deprecationTime, long expirationTime) {
- if (address == null ||
- address.isMulticastAddress() ||
- prefixLength < 0 ||
- (address instanceof Inet4Address && prefixLength > 32) ||
- (prefixLength > 128)) {
- throw new IllegalArgumentException("Bad LinkAddress params " + address +
- "/" + prefixLength);
- }
-
- // deprecation time and expiration time must be both provided, or neither.
- if ((deprecationTime == LIFETIME_UNKNOWN) != (expirationTime == LIFETIME_UNKNOWN)) {
- throw new IllegalArgumentException(
- "Must not specify only one of deprecation time and expiration time");
- }
-
- // deprecation time needs to be a positive value.
- if (deprecationTime != LIFETIME_UNKNOWN && deprecationTime < 0) {
- throw new IllegalArgumentException("invalid deprecation time " + deprecationTime);
- }
-
- // expiration time needs to be a positive value.
- if (expirationTime != LIFETIME_UNKNOWN && expirationTime < 0) {
- throw new IllegalArgumentException("invalid expiration time " + expirationTime);
- }
-
- // expiration time can't be earlier than deprecation time
- if (deprecationTime != LIFETIME_UNKNOWN && expirationTime != LIFETIME_UNKNOWN
- && expirationTime < deprecationTime) {
- throw new IllegalArgumentException("expiration earlier than deprecation ("
- + deprecationTime + ", " + expirationTime + ")");
- }
-
- this.address = address;
- this.prefixLength = prefixLength;
- this.flags = flags;
- this.scope = scope;
- this.deprecationTime = deprecationTime;
- this.expirationTime = expirationTime;
- }
-
- /**
- * Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with
- * the specified flags and scope. Flags and scope are not checked for validity.
- *
- * @param address The IP address.
- * @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
- * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
- * @param scope An integer defining the scope in which the address is unique (e.g.,
- * {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
- * @hide
- */
- @SystemApi
- public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
- int flags, int scope) {
- init(address, prefixLength, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
- }
-
- /**
- * Constructs a new {@code LinkAddress} from an {@code InetAddress}, prefix length, with
- * the specified flags, scope, deprecation time, and expiration time. Flags and scope are not
- * checked for validity. The value of the {@code IFA_F_DEPRECATED} and {@code IFA_F_PERMANENT}
- * flag will be adjusted based on the passed-in lifetimes.
- *
- * @param address The IP address.
- * @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
- * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
- * @param scope An integer defining the scope in which the address is unique (e.g.,
- * {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
- * @param deprecationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when
- * this {@link LinkAddress} will be or was deprecated. At the time
- * existing connections can still use this address until it expires, but
- * new connections should use the new address. {@link #LIFETIME_UNKNOWN}
- * indicates this information is not available.
- * {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will
- * never be deprecated.
- * @param expirationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when this
- * {@link LinkAddress} will expire and be removed from the interface.
- * {@link #LIFETIME_UNKNOWN} indicates this information is not available.
- * {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will
- * never expire.
- * @hide
- */
- @SystemApi
- public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
- int flags, int scope, long deprecationTime, long expirationTime) {
- init(address, prefixLength, flags, scope, deprecationTime, expirationTime);
- }
-
- /**
- * Constructs a new {@code LinkAddress} from an {@code InetAddress} and a prefix length.
- * The flags are set to zero and the scope is determined from the address.
- * @param address The IP address.
- * @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
- * @hide
- */
- @SystemApi
- public LinkAddress(@NonNull InetAddress address,
- @IntRange(from = 0, to = 128) int prefixLength) {
- this(address, prefixLength, 0, 0);
- this.scope = scopeForUnicastAddress(address);
- }
-
- /**
- * Constructs a new {@code LinkAddress} from an {@code InterfaceAddress}.
- * The flags are set to zero and the scope is determined from the address.
- * @param interfaceAddress The interface address.
- * @hide
- */
- public LinkAddress(@NonNull InterfaceAddress interfaceAddress) {
- this(interfaceAddress.getAddress(),
- interfaceAddress.getNetworkPrefixLength());
- }
-
- /**
- * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
- * "2001:db8::1/64". The flags are set to zero and the scope is determined from the address.
- * @param address The string to parse.
- * @hide
- */
- @SystemApi
- public LinkAddress(@NonNull String address) {
- this(address, 0, 0);
- this.scope = scopeForUnicastAddress(this.address);
- }
-
- /**
- * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
- * "2001:db8::1/64", with the specified flags and scope.
- * @param address The string to parse.
- * @param flags The address flags.
- * @param scope The address scope.
- * @hide
- */
- @SystemApi
- public LinkAddress(@NonNull String address, int flags, int scope) {
- // This may throw an IllegalArgumentException; catching it is the caller's responsibility.
- // TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24".
- Pair<InetAddress, Integer> ipAndMask = NetworkUtils.legacyParseIpAndMask(address);
- init(ipAndMask.first, ipAndMask.second, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
- }
-
- /**
- * Returns a string representation of this address, such as "192.0.2.1/24" or "2001:db8::1/64".
- * The string representation does not contain the flags and scope, just the address and prefix
- * length.
- */
- @Override
- public String toString() {
- return address.getHostAddress() + "/" + prefixLength;
- }
-
- /**
- * Compares this {@code LinkAddress} instance against {@code obj}. Two addresses are equal if
- * their address, prefix length, flags and scope are equal. Thus, for example, two addresses
- * that have the same address and prefix length are not equal if one of them is deprecated and
- * the other is not.
- *
- * @param obj the object to be tested for equality.
- * @return {@code true} if both objects are equal, {@code false} otherwise.
- */
- @Override
- public boolean equals(@Nullable Object obj) {
- if (!(obj instanceof LinkAddress)) {
- return false;
- }
- LinkAddress linkAddress = (LinkAddress) obj;
- return this.address.equals(linkAddress.address)
- && this.prefixLength == linkAddress.prefixLength
- && this.flags == linkAddress.flags
- && this.scope == linkAddress.scope
- && this.deprecationTime == linkAddress.deprecationTime
- && this.expirationTime == linkAddress.expirationTime;
- }
-
- /**
- * Returns a hashcode for this address.
- */
- @Override
- public int hashCode() {
- return Objects.hash(address, prefixLength, flags, scope, deprecationTime, expirationTime);
- }
-
- /**
- * Determines whether this {@code LinkAddress} and the provided {@code LinkAddress}
- * represent the same address. Two {@code LinkAddresses} represent the same address
- * if they have the same IP address and prefix length, even if their properties are
- * different.
- *
- * @param other the {@code LinkAddress} to compare to.
- * @return {@code true} if both objects have the same address and prefix length, {@code false}
- * otherwise.
- * @hide
- */
- @SystemApi
- public boolean isSameAddressAs(@Nullable LinkAddress other) {
- if (other == null) {
- return false;
- }
- return address.equals(other.address) && prefixLength == other.prefixLength;
- }
-
- /**
- * Returns the {@link InetAddress} of this {@code LinkAddress}.
- */
- public InetAddress getAddress() {
- return address;
- }
-
- /**
- * Returns the prefix length of this {@code LinkAddress}.
- */
- @IntRange(from = 0, to = 128)
- public int getPrefixLength() {
- return prefixLength;
- }
-
- /**
- * Returns the prefix length of this {@code LinkAddress}.
- * TODO: Delete all callers and remove in favour of getPrefixLength().
- * @hide
- */
- @UnsupportedAppUsage
- @IntRange(from = 0, to = 128)
- public int getNetworkPrefixLength() {
- return getPrefixLength();
- }
-
- /**
- * Returns the flags of this {@code LinkAddress}.
- */
- public int getFlags() {
- int flags = this.flags;
- if (deprecationTime != LIFETIME_UNKNOWN) {
- if (SystemClock.elapsedRealtime() >= deprecationTime) {
- flags |= IFA_F_DEPRECATED;
- } else {
- // If deprecation time is in the future, or permanent.
- flags &= ~IFA_F_DEPRECATED;
- }
- }
-
- if (expirationTime == LIFETIME_PERMANENT) {
- flags |= IFA_F_PERMANENT;
- } else if (expirationTime != LIFETIME_UNKNOWN) {
- // If we know this address expired or will expire in the future, then this address
- // should not be permanent.
- flags &= ~IFA_F_PERMANENT;
- }
-
- // Do no touch the original flags. Return the adjusted flags here.
- return flags;
- }
-
- /**
- * Returns the scope of this {@code LinkAddress}.
- */
- public int getScope() {
- return scope;
- }
-
- /**
- * Get the deprecation time, as reported by {@link SystemClock#elapsedRealtime}, when this
- * {@link LinkAddress} will be or was deprecated. At the time existing connections can still use
- * this address until it expires, but new connections should use the new address.
- *
- * @return The deprecation time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this
- * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
- * will never be deprecated.
- *
- * @hide
- */
- @SystemApi
- public long getDeprecationTime() {
- return deprecationTime;
- }
-
- /**
- * Get the expiration time, as reported by {@link SystemClock#elapsedRealtime}, when this
- * {@link LinkAddress} will expire and be removed from the interface.
- *
- * @return The expiration time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this
- * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
- * will never expire.
- *
- * @hide
- */
- @SystemApi
- public long getExpirationTime() {
- return expirationTime;
- }
-
- /**
- * Returns true if this {@code LinkAddress} is global scope and preferred (i.e., not currently
- * deprecated).
- *
- * @hide
- */
- @SystemApi
- public boolean isGlobalPreferred() {
- /**
- * Note that addresses flagged as IFA_F_OPTIMISTIC are
- * simultaneously flagged as IFA_F_TENTATIVE (when the tentative
- * state has cleared either DAD has succeeded or failed, and both
- * flags are cleared regardless).
- */
- int flags = getFlags();
- return (scope == RT_SCOPE_UNIVERSE
- && !isIpv6ULA()
- && (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L
- && ((flags & IFA_F_TENTATIVE) == 0L || (flags & IFA_F_OPTIMISTIC) != 0L));
- }
-
- /**
- * Implement the Parcelable interface.
- */
- public int describeContents() {
- return 0;
- }
-
- /**
- * Implement the Parcelable interface.
- */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeByteArray(address.getAddress());
- dest.writeInt(prefixLength);
- dest.writeInt(this.flags);
- dest.writeInt(scope);
- dest.writeLong(deprecationTime);
- dest.writeLong(expirationTime);
- }
-
- /**
- * Implement the Parcelable interface.
- */
- public static final @android.annotation.NonNull Creator<LinkAddress> CREATOR =
- new Creator<LinkAddress>() {
- public LinkAddress createFromParcel(Parcel in) {
- InetAddress address = null;
- try {
- address = InetAddress.getByAddress(in.createByteArray());
- } catch (UnknownHostException e) {
- // Nothing we can do here. When we call the constructor, we'll throw an
- // IllegalArgumentException, because a LinkAddress can't have a null
- // InetAddress.
- }
- int prefixLength = in.readInt();
- int flags = in.readInt();
- int scope = in.readInt();
- long deprecationTime = in.readLong();
- long expirationTime = in.readLong();
- return new LinkAddress(address, prefixLength, flags, scope, deprecationTime,
- expirationTime);
- }
-
- public LinkAddress[] newArray(int size) {
- return new LinkAddress[size];
- }
- };
-}
diff --git a/packages/Connectivity/framework/src/android/net/LinkProperties.java b/packages/Connectivity/framework/src/android/net/LinkProperties.java
deleted file mode 100644
index 99f48b4..0000000
--- a/packages/Connectivity/framework/src/android/net/LinkProperties.java
+++ /dev/null
@@ -1,1823 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-import com.android.net.module.util.LinkPropertiesUtils;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Objects;
-import java.util.StringJoiner;
-
-/**
- * Describes the properties of a network link.
- *
- * A link represents a connection to a network.
- * It may have multiple addresses and multiple gateways,
- * multiple dns servers but only one http proxy and one
- * network interface.
- *
- * Note that this is just a holder of data. Modifying it
- * does not affect live networks.
- *
- */
-public final class LinkProperties implements Parcelable {
- // The interface described by the network link.
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private String mIfaceName;
- private final ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
- private final ArrayList<InetAddress> mDnses = new ArrayList<>();
- // PCSCF addresses are addresses of SIP proxies that only exist for the IMS core service.
- private final ArrayList<InetAddress> mPcscfs = new ArrayList<InetAddress>();
- private final ArrayList<InetAddress> mValidatedPrivateDnses = new ArrayList<>();
- private boolean mUsePrivateDns;
- private String mPrivateDnsServerName;
- private String mDomains;
- private ArrayList<RouteInfo> mRoutes = new ArrayList<>();
- private Inet4Address mDhcpServerAddress;
- private ProxyInfo mHttpProxy;
- private int mMtu;
- // in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
- private String mTcpBufferSizes;
- private IpPrefix mNat64Prefix;
- private boolean mWakeOnLanSupported;
- private Uri mCaptivePortalApiUrl;
- private CaptivePortalData mCaptivePortalData;
-
- /**
- * Indicates whether parceling should preserve fields that are set based on permissions of
- * the process receiving the {@link LinkProperties}.
- */
- private final transient boolean mParcelSensitiveFields;
-
- private static final int MIN_MTU = 68;
-
- private static final int MIN_MTU_V6 = 1280;
-
- private static final int MAX_MTU = 10000;
-
- private static final int INET6_ADDR_LENGTH = 16;
-
- // Stores the properties of links that are "stacked" above this link.
- // Indexed by interface name to allow modification and to prevent duplicates being added.
- private Hashtable<String, LinkProperties> mStackedLinks = new Hashtable<>();
-
- /**
- * @hide
- */
- @UnsupportedAppUsage(implicitMember =
- "values()[Landroid/net/LinkProperties$ProvisioningChange;")
- public enum ProvisioningChange {
- @UnsupportedAppUsage
- STILL_NOT_PROVISIONED,
- @UnsupportedAppUsage
- LOST_PROVISIONING,
- @UnsupportedAppUsage
- GAINED_PROVISIONING,
- @UnsupportedAppUsage
- STILL_PROVISIONED,
- }
-
- /**
- * Compare the provisioning states of two LinkProperties instances.
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static ProvisioningChange compareProvisioning(
- LinkProperties before, LinkProperties after) {
- if (before.isProvisioned() && after.isProvisioned()) {
- // On dual-stack networks, DHCPv4 renewals can occasionally fail.
- // When this happens, IPv6-reachable services continue to function
- // normally but IPv4-only services (naturally) fail.
- //
- // When an application using an IPv4-only service reports a bad
- // network condition to the framework, attempts to re-validate
- // the network succeed (since we support IPv6-only networks) and
- // nothing is changed.
- //
- // For users, this is confusing and unexpected behaviour, and is
- // not necessarily easy to diagnose. Therefore, we treat changing
- // from a dual-stack network to an IPv6-only network equivalent to
- // a total loss of provisioning.
- //
- // For one such example of this, see b/18867306.
- //
- // Additionally, losing IPv6 provisioning can result in TCP
- // connections getting stuck until timeouts fire and other
- // baffling failures. Therefore, loss of either IPv4 or IPv6 on a
- // previously dual-stack network is deemed a lost of provisioning.
- if ((before.isIpv4Provisioned() && !after.isIpv4Provisioned())
- || (before.isIpv6Provisioned() && !after.isIpv6Provisioned())) {
- return ProvisioningChange.LOST_PROVISIONING;
- }
- return ProvisioningChange.STILL_PROVISIONED;
- } else if (before.isProvisioned() && !after.isProvisioned()) {
- return ProvisioningChange.LOST_PROVISIONING;
- } else if (!before.isProvisioned() && after.isProvisioned()) {
- return ProvisioningChange.GAINED_PROVISIONING;
- } else { // !before.isProvisioned() && !after.isProvisioned()
- return ProvisioningChange.STILL_NOT_PROVISIONED;
- }
- }
-
- /**
- * Constructs a new {@code LinkProperties} with default values.
- */
- public LinkProperties() {
- mParcelSensitiveFields = false;
- }
-
- /**
- * @hide
- */
- @SystemApi
- public LinkProperties(@Nullable LinkProperties source) {
- this(source, false /* parcelSensitiveFields */);
- }
-
- /**
- * Create a copy of a {@link LinkProperties} that may preserve fields that were set
- * based on the permissions of the process that originally received it.
- *
- * <p>By default {@link LinkProperties} does not preserve such fields during parceling, as
- * they should not be shared outside of the process that receives them without appropriate
- * checks.
- * @param parcelSensitiveFields Whether the sensitive fields should be kept when parceling
- * @hide
- */
- @SystemApi
- public LinkProperties(@Nullable LinkProperties source, boolean parcelSensitiveFields) {
- mParcelSensitiveFields = parcelSensitiveFields;
- if (source == null) return;
- mIfaceName = source.mIfaceName;
- mLinkAddresses.addAll(source.mLinkAddresses);
- mDnses.addAll(source.mDnses);
- mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses);
- mUsePrivateDns = source.mUsePrivateDns;
- mPrivateDnsServerName = source.mPrivateDnsServerName;
- mPcscfs.addAll(source.mPcscfs);
- mDomains = source.mDomains;
- mRoutes.addAll(source.mRoutes);
- mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy);
- for (LinkProperties l: source.mStackedLinks.values()) {
- addStackedLink(l);
- }
- setMtu(source.mMtu);
- setDhcpServerAddress(source.getDhcpServerAddress());
- mTcpBufferSizes = source.mTcpBufferSizes;
- mNat64Prefix = source.mNat64Prefix;
- mWakeOnLanSupported = source.mWakeOnLanSupported;
- mCaptivePortalApiUrl = source.mCaptivePortalApiUrl;
- mCaptivePortalData = source.mCaptivePortalData;
- }
-
- /**
- * Sets the interface name for this link. All {@link RouteInfo} already set for this
- * will have their interface changed to match this new value.
- *
- * @param iface The name of the network interface used for this link.
- */
- public void setInterfaceName(@Nullable String iface) {
- mIfaceName = iface;
- ArrayList<RouteInfo> newRoutes = new ArrayList<>(mRoutes.size());
- for (RouteInfo route : mRoutes) {
- newRoutes.add(routeWithInterface(route));
- }
- mRoutes = newRoutes;
- }
-
- /**
- * Gets the interface name for this link. May be {@code null} if not set.
- *
- * @return The interface name set for this link or {@code null}.
- */
- public @Nullable String getInterfaceName() {
- return mIfaceName;
- }
-
- /**
- * @hide
- */
- @SystemApi
- public @NonNull List<String> getAllInterfaceNames() {
- List<String> interfaceNames = new ArrayList<>(mStackedLinks.size() + 1);
- if (mIfaceName != null) interfaceNames.add(mIfaceName);
- for (LinkProperties stacked: mStackedLinks.values()) {
- interfaceNames.addAll(stacked.getAllInterfaceNames());
- }
- return interfaceNames;
- }
-
- /**
- * Returns all the addresses on this link. We often think of a link having a single address,
- * however, particularly with Ipv6 several addresses are typical. Note that the
- * {@code LinkProperties} actually contains {@link LinkAddress} objects which also include
- * prefix lengths for each address. This is a simplified utility alternative to
- * {@link LinkProperties#getLinkAddresses}.
- *
- * @return An unmodifiable {@link List} of {@link InetAddress} for this link.
- * @hide
- */
- @SystemApi
- public @NonNull List<InetAddress> getAddresses() {
- final List<InetAddress> addresses = new ArrayList<>();
- for (LinkAddress linkAddress : mLinkAddresses) {
- addresses.add(linkAddress.getAddress());
- }
- return Collections.unmodifiableList(addresses);
- }
-
- /**
- * Returns all the addresses on this link and all the links stacked above it.
- * @hide
- */
- @UnsupportedAppUsage
- public @NonNull List<InetAddress> getAllAddresses() {
- List<InetAddress> addresses = new ArrayList<>();
- for (LinkAddress linkAddress : mLinkAddresses) {
- addresses.add(linkAddress.getAddress());
- }
- for (LinkProperties stacked: mStackedLinks.values()) {
- addresses.addAll(stacked.getAllAddresses());
- }
- return addresses;
- }
-
- private int findLinkAddressIndex(LinkAddress address) {
- for (int i = 0; i < mLinkAddresses.size(); i++) {
- if (mLinkAddresses.get(i).isSameAddressAs(address)) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Adds a {@link LinkAddress} to this {@code LinkProperties} if a {@link LinkAddress} of the
- * same address/prefix does not already exist. If it does exist it is replaced.
- * @param address The {@code LinkAddress} to add.
- * @return true if {@code address} was added or updated, false otherwise.
- * @hide
- */
- @SystemApi
- public boolean addLinkAddress(@NonNull LinkAddress address) {
- if (address == null) {
- return false;
- }
- int i = findLinkAddressIndex(address);
- if (i < 0) {
- // Address was not present. Add it.
- mLinkAddresses.add(address);
- return true;
- } else if (mLinkAddresses.get(i).equals(address)) {
- // Address was present and has same properties. Do nothing.
- return false;
- } else {
- // Address was present and has different properties. Update it.
- mLinkAddresses.set(i, address);
- return true;
- }
- }
-
- /**
- * Removes a {@link LinkAddress} from this {@code LinkProperties}. Specifically, matches
- * and {@link LinkAddress} with the same address and prefix.
- *
- * @param toRemove A {@link LinkAddress} specifying the address to remove.
- * @return true if the address was removed, false if it did not exist.
- * @hide
- */
- @SystemApi
- public boolean removeLinkAddress(@NonNull LinkAddress toRemove) {
- int i = findLinkAddressIndex(toRemove);
- if (i >= 0) {
- mLinkAddresses.remove(i);
- return true;
- }
- return false;
- }
-
- /**
- * Returns all the {@link LinkAddress} on this link. Typically a link will have
- * one IPv4 address and one or more IPv6 addresses.
- *
- * @return An unmodifiable {@link List} of {@link LinkAddress} for this link.
- */
- public @NonNull List<LinkAddress> getLinkAddresses() {
- return Collections.unmodifiableList(mLinkAddresses);
- }
-
- /**
- * Returns all the addresses on this link and all the links stacked above it.
- * @hide
- */
- @SystemApi
- public @NonNull List<LinkAddress> getAllLinkAddresses() {
- List<LinkAddress> addresses = new ArrayList<>(mLinkAddresses);
- for (LinkProperties stacked: mStackedLinks.values()) {
- addresses.addAll(stacked.getAllLinkAddresses());
- }
- return addresses;
- }
-
- /**
- * Replaces the {@link LinkAddress} in this {@code LinkProperties} with
- * the given {@link Collection} of {@link LinkAddress}.
- *
- * @param addresses The {@link Collection} of {@link LinkAddress} to set in this
- * object.
- */
- public void setLinkAddresses(@NonNull Collection<LinkAddress> addresses) {
- mLinkAddresses.clear();
- for (LinkAddress address: addresses) {
- addLinkAddress(address);
- }
- }
-
- /**
- * Adds the given {@link InetAddress} to the list of DNS servers, if not present.
- *
- * @param dnsServer The {@link InetAddress} to add to the list of DNS servers.
- * @return true if the DNS server was added, false if it was already present.
- * @hide
- */
- @SystemApi
- public boolean addDnsServer(@NonNull InetAddress dnsServer) {
- if (dnsServer != null && !mDnses.contains(dnsServer)) {
- mDnses.add(dnsServer);
- return true;
- }
- return false;
- }
-
- /**
- * Removes the given {@link InetAddress} from the list of DNS servers.
- *
- * @param dnsServer The {@link InetAddress} to remove from the list of DNS servers.
- * @return true if the DNS server was removed, false if it did not exist.
- * @hide
- */
- @SystemApi
- public boolean removeDnsServer(@NonNull InetAddress dnsServer) {
- return mDnses.remove(dnsServer);
- }
-
- /**
- * Replaces the DNS servers in this {@code LinkProperties} with
- * the given {@link Collection} of {@link InetAddress} objects.
- *
- * @param dnsServers The {@link Collection} of DNS servers to set in this object.
- */
- public void setDnsServers(@NonNull Collection<InetAddress> dnsServers) {
- mDnses.clear();
- for (InetAddress dnsServer: dnsServers) {
- addDnsServer(dnsServer);
- }
- }
-
- /**
- * Returns all the {@link InetAddress} for DNS servers on this link.
- *
- * @return An unmodifiable {@link List} of {@link InetAddress} for DNS servers on
- * this link.
- */
- public @NonNull List<InetAddress> getDnsServers() {
- return Collections.unmodifiableList(mDnses);
- }
-
- /**
- * Set whether private DNS is currently in use on this network.
- *
- * @param usePrivateDns The private DNS state.
- * @hide
- */
- @SystemApi
- public void setUsePrivateDns(boolean usePrivateDns) {
- mUsePrivateDns = usePrivateDns;
- }
-
- /**
- * Returns whether private DNS is currently in use on this network. When
- * private DNS is in use, applications must not send unencrypted DNS
- * queries as doing so could reveal private user information. Furthermore,
- * if private DNS is in use and {@link #getPrivateDnsServerName} is not
- * {@code null}, DNS queries must be sent to the specified DNS server.
- *
- * @return {@code true} if private DNS is in use, {@code false} otherwise.
- */
- public boolean isPrivateDnsActive() {
- return mUsePrivateDns;
- }
-
- /**
- * Set the name of the private DNS server to which private DNS queries
- * should be sent when in strict mode. This value should be {@code null}
- * when private DNS is off or in opportunistic mode.
- *
- * @param privateDnsServerName The private DNS server name.
- * @hide
- */
- @SystemApi
- public void setPrivateDnsServerName(@Nullable String privateDnsServerName) {
- mPrivateDnsServerName = privateDnsServerName;
- }
-
- /**
- * Set DHCP server address.
- *
- * @param serverAddress the server address to set.
- */
- public void setDhcpServerAddress(@Nullable Inet4Address serverAddress) {
- mDhcpServerAddress = serverAddress;
- }
-
- /**
- * Get DHCP server address
- *
- * @return The current DHCP server address.
- */
- public @Nullable Inet4Address getDhcpServerAddress() {
- return mDhcpServerAddress;
- }
-
- /**
- * Returns the private DNS server name that is in use. If not {@code null},
- * private DNS is in strict mode. In this mode, applications should ensure
- * that all DNS queries are encrypted and sent to this hostname and that
- * queries are only sent if the hostname's certificate is valid. If
- * {@code null} and {@link #isPrivateDnsActive} is {@code true}, private
- * DNS is in opportunistic mode, and applications should ensure that DNS
- * queries are encrypted and sent to a DNS server returned by
- * {@link #getDnsServers}. System DNS will handle each of these cases
- * correctly, but applications implementing their own DNS lookups must make
- * sure to follow these requirements.
- *
- * @return The private DNS server name.
- */
- public @Nullable String getPrivateDnsServerName() {
- return mPrivateDnsServerName;
- }
-
- /**
- * Adds the given {@link InetAddress} to the list of validated private DNS servers,
- * if not present. This is distinct from the server name in that these are actually
- * resolved addresses.
- *
- * @param dnsServer The {@link InetAddress} to add to the list of validated private DNS servers.
- * @return true if the DNS server was added, false if it was already present.
- * @hide
- */
- public boolean addValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) {
- if (dnsServer != null && !mValidatedPrivateDnses.contains(dnsServer)) {
- mValidatedPrivateDnses.add(dnsServer);
- return true;
- }
- return false;
- }
-
- /**
- * Removes the given {@link InetAddress} from the list of validated private DNS servers.
- *
- * @param dnsServer The {@link InetAddress} to remove from the list of validated private DNS
- * servers.
- * @return true if the DNS server was removed, false if it did not exist.
- * @hide
- */
- public boolean removeValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) {
- return mValidatedPrivateDnses.remove(dnsServer);
- }
-
- /**
- * Replaces the validated private DNS servers in this {@code LinkProperties} with
- * the given {@link Collection} of {@link InetAddress} objects.
- *
- * @param dnsServers The {@link Collection} of validated private DNS servers to set in this
- * object.
- * @hide
- */
- @SystemApi
- public void setValidatedPrivateDnsServers(@NonNull Collection<InetAddress> dnsServers) {
- mValidatedPrivateDnses.clear();
- for (InetAddress dnsServer: dnsServers) {
- addValidatedPrivateDnsServer(dnsServer);
- }
- }
-
- /**
- * Returns all the {@link InetAddress} for validated private DNS servers on this link.
- * These are resolved from the private DNS server name.
- *
- * @return An unmodifiable {@link List} of {@link InetAddress} for validated private
- * DNS servers on this link.
- * @hide
- */
- @SystemApi
- public @NonNull List<InetAddress> getValidatedPrivateDnsServers() {
- return Collections.unmodifiableList(mValidatedPrivateDnses);
- }
-
- /**
- * Adds the given {@link InetAddress} to the list of PCSCF servers, if not present.
- *
- * @param pcscfServer The {@link InetAddress} to add to the list of PCSCF servers.
- * @return true if the PCSCF server was added, false otherwise.
- * @hide
- */
- @SystemApi
- public boolean addPcscfServer(@NonNull InetAddress pcscfServer) {
- if (pcscfServer != null && !mPcscfs.contains(pcscfServer)) {
- mPcscfs.add(pcscfServer);
- return true;
- }
- return false;
- }
-
- /**
- * Removes the given {@link InetAddress} from the list of PCSCF servers.
- *
- * @param pcscfServer The {@link InetAddress} to remove from the list of PCSCF servers.
- * @return true if the PCSCF server was removed, false otherwise.
- * @hide
- */
- public boolean removePcscfServer(@NonNull InetAddress pcscfServer) {
- return mPcscfs.remove(pcscfServer);
- }
-
- /**
- * Replaces the PCSCF servers in this {@code LinkProperties} with
- * the given {@link Collection} of {@link InetAddress} objects.
- *
- * @param pcscfServers The {@link Collection} of PCSCF servers to set in this object.
- * @hide
- */
- @SystemApi
- public void setPcscfServers(@NonNull Collection<InetAddress> pcscfServers) {
- mPcscfs.clear();
- for (InetAddress pcscfServer: pcscfServers) {
- addPcscfServer(pcscfServer);
- }
- }
-
- /**
- * Returns all the {@link InetAddress} for PCSCF servers on this link.
- *
- * @return An unmodifiable {@link List} of {@link InetAddress} for PCSCF servers on
- * this link.
- * @hide
- */
- @SystemApi
- public @NonNull List<InetAddress> getPcscfServers() {
- return Collections.unmodifiableList(mPcscfs);
- }
-
- /**
- * Sets the DNS domain search path used on this link.
- *
- * @param domains A {@link String} listing in priority order the comma separated
- * domains to search when resolving host names on this link.
- */
- public void setDomains(@Nullable String domains) {
- mDomains = domains;
- }
-
- /**
- * Get the DNS domains search path set for this link. May be {@code null} if not set.
- *
- * @return A {@link String} containing the comma separated domains to search when resolving host
- * names on this link or {@code null}.
- */
- public @Nullable String getDomains() {
- return mDomains;
- }
-
- /**
- * Sets the Maximum Transmission Unit size to use on this link. This should not be used
- * unless the system default (1500) is incorrect. Values less than 68 or greater than
- * 10000 will be ignored.
- *
- * @param mtu The MTU to use for this link.
- */
- public void setMtu(int mtu) {
- mMtu = mtu;
- }
-
- /**
- * Gets any non-default MTU size set for this link. Note that if the default is being used
- * this will return 0.
- *
- * @return The mtu value set for this link.
- */
- public int getMtu() {
- return mMtu;
- }
-
- /**
- * Sets the tcp buffers sizes to be used when this link is the system default.
- * Should be of the form "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max".
- *
- * @param tcpBufferSizes The tcp buffers sizes to use.
- *
- * @hide
- */
- @SystemApi
- public void setTcpBufferSizes(@Nullable String tcpBufferSizes) {
- mTcpBufferSizes = tcpBufferSizes;
- }
-
- /**
- * Gets the tcp buffer sizes. May be {@code null} if not set.
- *
- * @return the tcp buffer sizes to use when this link is the system default or {@code null}.
- *
- * @hide
- */
- @SystemApi
- public @Nullable String getTcpBufferSizes() {
- return mTcpBufferSizes;
- }
-
- private RouteInfo routeWithInterface(RouteInfo route) {
- return new RouteInfo(
- route.getDestination(),
- route.getGateway(),
- mIfaceName,
- route.getType(),
- route.getMtu());
- }
-
- private int findRouteIndexByRouteKey(RouteInfo route) {
- for (int i = 0; i < mRoutes.size(); i++) {
- if (mRoutes.get(i).getRouteKey().equals(route.getRouteKey())) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Adds a {@link RouteInfo} to this {@code LinkProperties}. If there is a {@link RouteInfo}
- * with the same destination, gateway and interface with different properties
- * (e.g., different MTU), it will be updated. If the {@link RouteInfo} had an
- * interface name set and that differs from the interface set for this
- * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown.
- * The proper course is to add either un-named or properly named {@link RouteInfo}.
- *
- * @param route A {@link RouteInfo} to add to this object.
- * @return {@code true} was added or updated, false otherwise.
- */
- public boolean addRoute(@NonNull RouteInfo route) {
- String routeIface = route.getInterface();
- if (routeIface != null && !routeIface.equals(mIfaceName)) {
- throw new IllegalArgumentException(
- "Route added with non-matching interface: " + routeIface
- + " vs. " + mIfaceName);
- }
- route = routeWithInterface(route);
-
- int i = findRouteIndexByRouteKey(route);
- if (i == -1) {
- // Route was not present. Add it.
- mRoutes.add(route);
- return true;
- } else if (mRoutes.get(i).equals(route)) {
- // Route was present and has same properties. Do nothing.
- return false;
- } else {
- // Route was present and has different properties. Update it.
- mRoutes.set(i, route);
- return true;
- }
- }
-
- /**
- * Removes a {@link RouteInfo} from this {@code LinkProperties}, if present. The route must
- * specify an interface and the interface must match the interface of this
- * {@code LinkProperties}, or it will not be removed.
- *
- * @param route A {@link RouteInfo} specifying the route to remove.
- * @return {@code true} if the route was removed, {@code false} if it was not present.
- *
- * @hide
- */
- @SystemApi
- public boolean removeRoute(@NonNull RouteInfo route) {
- return Objects.equals(mIfaceName, route.getInterface()) && mRoutes.remove(route);
- }
-
- /**
- * Returns all the {@link RouteInfo} set on this link.
- *
- * @return An unmodifiable {@link List} of {@link RouteInfo} for this link.
- */
- public @NonNull List<RouteInfo> getRoutes() {
- return Collections.unmodifiableList(mRoutes);
- }
-
- /**
- * Make sure this LinkProperties instance contains routes that cover the local subnet
- * of its link addresses. Add any route that is missing.
- * @hide
- */
- public void ensureDirectlyConnectedRoutes() {
- for (LinkAddress addr : mLinkAddresses) {
- addRoute(new RouteInfo(addr, null, mIfaceName));
- }
- }
-
- /**
- * Returns all the routes on this link and all the links stacked above it.
- * @hide
- */
- @SystemApi
- public @NonNull List<RouteInfo> getAllRoutes() {
- List<RouteInfo> routes = new ArrayList<>(mRoutes);
- for (LinkProperties stacked: mStackedLinks.values()) {
- routes.addAll(stacked.getAllRoutes());
- }
- return routes;
- }
-
- /**
- * Sets the recommended {@link ProxyInfo} to use on this link, or {@code null} for none.
- * Note that Http Proxies are only a hint - the system recommends their use, but it does
- * not enforce it and applications may ignore them.
- *
- * @param proxy A {@link ProxyInfo} defining the HTTP Proxy to use on this link.
- */
- public void setHttpProxy(@Nullable ProxyInfo proxy) {
- mHttpProxy = proxy;
- }
-
- /**
- * Gets the recommended {@link ProxyInfo} (or {@code null}) set on this link.
- *
- * @return The {@link ProxyInfo} set on this link or {@code null}.
- */
- public @Nullable ProxyInfo getHttpProxy() {
- return mHttpProxy;
- }
-
- /**
- * Returns the NAT64 prefix in use on this link, if any.
- *
- * @return the NAT64 prefix or {@code null}.
- */
- public @Nullable IpPrefix getNat64Prefix() {
- return mNat64Prefix;
- }
-
- /**
- * Sets the NAT64 prefix in use on this link.
- *
- * Currently, only 96-bit prefixes (i.e., where the 32-bit IPv4 address is at the end of the
- * 128-bit IPv6 address) are supported or {@code null} for no prefix.
- *
- * @param prefix the NAT64 prefix.
- */
- public void setNat64Prefix(@Nullable IpPrefix prefix) {
- if (prefix != null && prefix.getPrefixLength() != 96) {
- throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix);
- }
- mNat64Prefix = prefix; // IpPrefix objects are immutable.
- }
-
- /**
- * Adds a stacked link.
- *
- * If there is already a stacked link with the same interface name as link,
- * that link is replaced with link. Otherwise, link is added to the list
- * of stacked links.
- *
- * @param link The link to add.
- * @return true if the link was stacked, false otherwise.
- * @hide
- */
- @UnsupportedAppUsage
- public boolean addStackedLink(@NonNull LinkProperties link) {
- if (link.getInterfaceName() != null) {
- mStackedLinks.put(link.getInterfaceName(), link);
- return true;
- }
- return false;
- }
-
- /**
- * Removes a stacked link.
- *
- * If there is a stacked link with the given interface name, it is
- * removed. Otherwise, nothing changes.
- *
- * @param iface The interface name of the link to remove.
- * @return true if the link was removed, false otherwise.
- * @hide
- */
- public boolean removeStackedLink(@NonNull String iface) {
- LinkProperties removed = mStackedLinks.remove(iface);
- return removed != null;
- }
-
- /**
- * Returns all the links stacked on top of this link.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public @NonNull List<LinkProperties> getStackedLinks() {
- if (mStackedLinks.isEmpty()) {
- return Collections.emptyList();
- }
- final List<LinkProperties> stacked = new ArrayList<>();
- for (LinkProperties link : mStackedLinks.values()) {
- stacked.add(new LinkProperties(link));
- }
- return Collections.unmodifiableList(stacked);
- }
-
- /**
- * Clears this object to its initial state.
- */
- public void clear() {
- if (mParcelSensitiveFields) {
- throw new UnsupportedOperationException(
- "Cannot clear LinkProperties when parcelSensitiveFields is set");
- }
-
- mIfaceName = null;
- mLinkAddresses.clear();
- mDnses.clear();
- mUsePrivateDns = false;
- mPrivateDnsServerName = null;
- mPcscfs.clear();
- mDomains = null;
- mRoutes.clear();
- mHttpProxy = null;
- mStackedLinks.clear();
- mMtu = 0;
- mDhcpServerAddress = null;
- mTcpBufferSizes = null;
- mNat64Prefix = null;
- mWakeOnLanSupported = false;
- mCaptivePortalApiUrl = null;
- mCaptivePortalData = null;
- }
-
- /**
- * Implement the Parcelable interface
- */
- public int describeContents() {
- return 0;
- }
-
- @Override
- public String toString() {
- // Space as a separator, so no need for spaces at start/end of the individual fragments.
- final StringJoiner resultJoiner = new StringJoiner(" ", "{", "}");
-
- if (mIfaceName != null) {
- resultJoiner.add("InterfaceName:");
- resultJoiner.add(mIfaceName);
- }
-
- resultJoiner.add("LinkAddresses: [");
- if (!mLinkAddresses.isEmpty()) {
- resultJoiner.add(TextUtils.join(",", mLinkAddresses));
- }
- resultJoiner.add("]");
-
- resultJoiner.add("DnsAddresses: [");
- if (!mDnses.isEmpty()) {
- resultJoiner.add(TextUtils.join(",", mDnses));
- }
- resultJoiner.add("]");
-
- if (mUsePrivateDns) {
- resultJoiner.add("UsePrivateDns: true");
- }
-
- if (mPrivateDnsServerName != null) {
- resultJoiner.add("PrivateDnsServerName:");
- resultJoiner.add(mPrivateDnsServerName);
- }
-
- if (!mPcscfs.isEmpty()) {
- resultJoiner.add("PcscfAddresses: [");
- resultJoiner.add(TextUtils.join(",", mPcscfs));
- resultJoiner.add("]");
- }
-
- if (!mValidatedPrivateDnses.isEmpty()) {
- final StringJoiner validatedPrivateDnsesJoiner =
- new StringJoiner(",", "ValidatedPrivateDnsAddresses: [", "]");
- for (final InetAddress addr : mValidatedPrivateDnses) {
- validatedPrivateDnsesJoiner.add(addr.getHostAddress());
- }
- resultJoiner.add(validatedPrivateDnsesJoiner.toString());
- }
-
- resultJoiner.add("Domains:");
- resultJoiner.add(mDomains);
-
- resultJoiner.add("MTU:");
- resultJoiner.add(Integer.toString(mMtu));
-
- if (mWakeOnLanSupported) {
- resultJoiner.add("WakeOnLanSupported: true");
- }
-
- if (mDhcpServerAddress != null) {
- resultJoiner.add("ServerAddress:");
- resultJoiner.add(mDhcpServerAddress.toString());
- }
-
- if (mCaptivePortalApiUrl != null) {
- resultJoiner.add("CaptivePortalApiUrl: " + mCaptivePortalApiUrl);
- }
-
- if (mCaptivePortalData != null) {
- resultJoiner.add("CaptivePortalData: " + mCaptivePortalData);
- }
-
- if (mTcpBufferSizes != null) {
- resultJoiner.add("TcpBufferSizes:");
- resultJoiner.add(mTcpBufferSizes);
- }
-
- resultJoiner.add("Routes: [");
- if (!mRoutes.isEmpty()) {
- resultJoiner.add(TextUtils.join(",", mRoutes));
- }
- resultJoiner.add("]");
-
- if (mHttpProxy != null) {
- resultJoiner.add("HttpProxy:");
- resultJoiner.add(mHttpProxy.toString());
- }
-
- if (mNat64Prefix != null) {
- resultJoiner.add("Nat64Prefix:");
- resultJoiner.add(mNat64Prefix.toString());
- }
-
- final Collection<LinkProperties> stackedLinksValues = mStackedLinks.values();
- if (!stackedLinksValues.isEmpty()) {
- final StringJoiner stackedLinksJoiner = new StringJoiner(",", "Stacked: [", "]");
- for (final LinkProperties lp : stackedLinksValues) {
- stackedLinksJoiner.add("[ " + lp + " ]");
- }
- resultJoiner.add(stackedLinksJoiner.toString());
- }
-
- return resultJoiner.toString();
- }
-
- /**
- * Returns true if this link has an IPv4 address.
- *
- * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
- * @hide
- */
- @SystemApi
- public boolean hasIpv4Address() {
- for (LinkAddress address : mLinkAddresses) {
- if (address.getAddress() instanceof Inet4Address) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * For backward compatibility.
- * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
- * just yet.
- * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
- public boolean hasIPv4Address() {
- return hasIpv4Address();
- }
-
- /**
- * Returns true if this link or any of its stacked interfaces has an IPv4 address.
- *
- * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
- */
- private boolean hasIpv4AddressOnInterface(String iface) {
- // mIfaceName can be null.
- return (Objects.equals(iface, mIfaceName) && hasIpv4Address())
- || (iface != null && mStackedLinks.containsKey(iface)
- && mStackedLinks.get(iface).hasIpv4Address());
- }
-
- /**
- * Returns true if this link has a global preferred IPv6 address.
- *
- * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise.
- * @hide
- */
- @SystemApi
- public boolean hasGlobalIpv6Address() {
- for (LinkAddress address : mLinkAddresses) {
- if (address.getAddress() instanceof Inet6Address && address.isGlobalPreferred()) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns true if this link has an IPv4 unreachable default route.
- *
- * @return {@code true} if there is an IPv4 unreachable default route, {@code false} otherwise.
- * @hide
- */
- public boolean hasIpv4UnreachableDefaultRoute() {
- for (RouteInfo r : mRoutes) {
- if (r.isIPv4UnreachableDefault()) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * For backward compatibility.
- * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
- * just yet.
- * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
- public boolean hasGlobalIPv6Address() {
- return hasGlobalIpv6Address();
- }
-
- /**
- * Returns true if this link has an IPv4 default route.
- *
- * @return {@code true} if there is an IPv4 default route, {@code false} otherwise.
- * @hide
- */
- @SystemApi
- public boolean hasIpv4DefaultRoute() {
- for (RouteInfo r : mRoutes) {
- if (r.isIPv4Default()) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns true if this link has an IPv6 unreachable default route.
- *
- * @return {@code true} if there is an IPv6 unreachable default route, {@code false} otherwise.
- * @hide
- */
- public boolean hasIpv6UnreachableDefaultRoute() {
- for (RouteInfo r : mRoutes) {
- if (r.isIPv6UnreachableDefault()) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * For backward compatibility.
- * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
- * just yet.
- * @return {@code true} if there is an IPv4 default route, {@code false} otherwise.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
- public boolean hasIPv4DefaultRoute() {
- return hasIpv4DefaultRoute();
- }
-
- /**
- * Returns true if this link has an IPv6 default route.
- *
- * @return {@code true} if there is an IPv6 default route, {@code false} otherwise.
- * @hide
- */
- @SystemApi
- public boolean hasIpv6DefaultRoute() {
- for (RouteInfo r : mRoutes) {
- if (r.isIPv6Default()) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * For backward compatibility.
- * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
- * just yet.
- * @return {@code true} if there is an IPv6 default route, {@code false} otherwise.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
- public boolean hasIPv6DefaultRoute() {
- return hasIpv6DefaultRoute();
- }
-
- /**
- * Returns true if this link has an IPv4 DNS server.
- *
- * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise.
- * @hide
- */
- @SystemApi
- public boolean hasIpv4DnsServer() {
- for (InetAddress ia : mDnses) {
- if (ia instanceof Inet4Address) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * For backward compatibility.
- * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
- * just yet.
- * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
- public boolean hasIPv4DnsServer() {
- return hasIpv4DnsServer();
- }
-
- /**
- * Returns true if this link has an IPv6 DNS server.
- *
- * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise.
- * @hide
- */
- @SystemApi
- public boolean hasIpv6DnsServer() {
- for (InetAddress ia : mDnses) {
- if (ia instanceof Inet6Address) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * For backward compatibility.
- * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
- * just yet.
- * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
- public boolean hasIPv6DnsServer() {
- return hasIpv6DnsServer();
- }
-
- /**
- * Returns true if this link has an IPv4 PCSCF server.
- *
- * @return {@code true} if there is an IPv4 PCSCF server, {@code false} otherwise.
- * @hide
- */
- public boolean hasIpv4PcscfServer() {
- for (InetAddress ia : mPcscfs) {
- if (ia instanceof Inet4Address) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns true if this link has an IPv6 PCSCF server.
- *
- * @return {@code true} if there is an IPv6 PCSCF server, {@code false} otherwise.
- * @hide
- */
- public boolean hasIpv6PcscfServer() {
- for (InetAddress ia : mPcscfs) {
- if (ia instanceof Inet6Address) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns true if this link is provisioned for global IPv4 connectivity.
- * This requires an IP address, default route, and DNS server.
- *
- * @return {@code true} if the link is provisioned, {@code false} otherwise.
- * @hide
- */
- @SystemApi
- public boolean isIpv4Provisioned() {
- return (hasIpv4Address()
- && hasIpv4DefaultRoute()
- && hasIpv4DnsServer());
- }
-
- /**
- * Returns true if this link is provisioned for global IPv6 connectivity.
- * This requires an IP address, default route, and DNS server.
- *
- * @return {@code true} if the link is provisioned, {@code false} otherwise.
- * @hide
- */
- @SystemApi
- public boolean isIpv6Provisioned() {
- return (hasGlobalIpv6Address()
- && hasIpv6DefaultRoute()
- && hasIpv6DnsServer());
- }
-
- /**
- * For backward compatibility.
- * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
- * just yet.
- * @return {@code true} if the link is provisioned, {@code false} otherwise.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
- public boolean isIPv6Provisioned() {
- return isIpv6Provisioned();
- }
-
-
- /**
- * Returns true if this link is provisioned for global connectivity,
- * for at least one Internet Protocol family.
- *
- * @return {@code true} if the link is provisioned, {@code false} otherwise.
- * @hide
- */
- @SystemApi
- public boolean isProvisioned() {
- return (isIpv4Provisioned() || isIpv6Provisioned());
- }
-
- /**
- * Evaluate whether the {@link InetAddress} is considered reachable.
- *
- * @return {@code true} if the given {@link InetAddress} is considered reachable,
- * {@code false} otherwise.
- * @hide
- */
- @SystemApi
- public boolean isReachable(@NonNull InetAddress ip) {
- final List<RouteInfo> allRoutes = getAllRoutes();
- // If we don't have a route to this IP address, it's not reachable.
- final RouteInfo bestRoute = RouteInfo.selectBestRoute(allRoutes, ip);
- if (bestRoute == null) {
- return false;
- }
-
- // TODO: better source address evaluation for destination addresses.
-
- if (ip instanceof Inet4Address) {
- // For IPv4, it suffices for now to simply have any address.
- return hasIpv4AddressOnInterface(bestRoute.getInterface());
- } else if (ip instanceof Inet6Address) {
- if (ip.isLinkLocalAddress()) {
- // For now, just make sure link-local destinations have
- // scopedIds set, since transmits will generally fail otherwise.
- // TODO: verify it matches the ifindex of one of the interfaces.
- return (((Inet6Address)ip).getScopeId() != 0);
- } else {
- // For non-link-local destinations check that either the best route
- // is directly connected or that some global preferred address exists.
- // TODO: reconsider all cases (disconnected ULA networks, ...).
- return (!bestRoute.hasGateway() || hasGlobalIpv6Address());
- }
- }
-
- return false;
- }
-
- /**
- * Compares this {@code LinkProperties} interface name against the target
- *
- * @param target LinkProperties to compare.
- * @return {@code true} if both are identical, {@code false} otherwise.
- * @hide
- */
- @UnsupportedAppUsage
- public boolean isIdenticalInterfaceName(@NonNull LinkProperties target) {
- return LinkPropertiesUtils.isIdenticalInterfaceName(target, this);
- }
-
- /**
- * Compares this {@code LinkProperties} DHCP server address against the target
- *
- * @param target LinkProperties to compare.
- * @return {@code true} if both are identical, {@code false} otherwise.
- * @hide
- */
- public boolean isIdenticalDhcpServerAddress(@NonNull LinkProperties target) {
- return Objects.equals(mDhcpServerAddress, target.mDhcpServerAddress);
- }
-
- /**
- * Compares this {@code LinkProperties} interface addresses against the target
- *
- * @param target LinkProperties to compare.
- * @return {@code true} if both are identical, {@code false} otherwise.
- * @hide
- */
- @UnsupportedAppUsage
- public boolean isIdenticalAddresses(@NonNull LinkProperties target) {
- return LinkPropertiesUtils.isIdenticalAddresses(target, this);
- }
-
- /**
- * Compares this {@code LinkProperties} DNS addresses against the target
- *
- * @param target LinkProperties to compare.
- * @return {@code true} if both are identical, {@code false} otherwise.
- * @hide
- */
- @UnsupportedAppUsage
- public boolean isIdenticalDnses(@NonNull LinkProperties target) {
- return LinkPropertiesUtils.isIdenticalDnses(target, this);
- }
-
- /**
- * Compares this {@code LinkProperties} private DNS settings against the
- * target.
- *
- * @param target LinkProperties to compare.
- * @return {@code true} if both are identical, {@code false} otherwise.
- * @hide
- */
- public boolean isIdenticalPrivateDns(@NonNull LinkProperties target) {
- return (isPrivateDnsActive() == target.isPrivateDnsActive()
- && TextUtils.equals(getPrivateDnsServerName(),
- target.getPrivateDnsServerName()));
- }
-
- /**
- * Compares this {@code LinkProperties} validated private DNS addresses against
- * the target
- *
- * @param target LinkProperties to compare.
- * @return {@code true} if both are identical, {@code false} otherwise.
- * @hide
- */
- public boolean isIdenticalValidatedPrivateDnses(@NonNull LinkProperties target) {
- Collection<InetAddress> targetDnses = target.getValidatedPrivateDnsServers();
- return (mValidatedPrivateDnses.size() == targetDnses.size())
- ? mValidatedPrivateDnses.containsAll(targetDnses) : false;
- }
-
- /**
- * Compares this {@code LinkProperties} PCSCF addresses against the target
- *
- * @param target LinkProperties to compare.
- * @return {@code true} if both are identical, {@code false} otherwise.
- * @hide
- */
- public boolean isIdenticalPcscfs(@NonNull LinkProperties target) {
- Collection<InetAddress> targetPcscfs = target.getPcscfServers();
- return (mPcscfs.size() == targetPcscfs.size()) ?
- mPcscfs.containsAll(targetPcscfs) : false;
- }
-
- /**
- * Compares this {@code LinkProperties} Routes against the target
- *
- * @param target LinkProperties to compare.
- * @return {@code true} if both are identical, {@code false} otherwise.
- * @hide
- */
- @UnsupportedAppUsage
- public boolean isIdenticalRoutes(@NonNull LinkProperties target) {
- return LinkPropertiesUtils.isIdenticalRoutes(target, this);
- }
-
- /**
- * Compares this {@code LinkProperties} HttpProxy against the target
- *
- * @param target LinkProperties to compare.
- * @return {@code true} if both are identical, {@code false} otherwise.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public boolean isIdenticalHttpProxy(@NonNull LinkProperties target) {
- return LinkPropertiesUtils.isIdenticalHttpProxy(target, this);
- }
-
- /**
- * Compares this {@code LinkProperties} stacked links against the target
- *
- * @param target LinkProperties to compare.
- * @return {@code true} if both are identical, {@code false} otherwise.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public boolean isIdenticalStackedLinks(@NonNull LinkProperties target) {
- if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) {
- return false;
- }
- for (LinkProperties stacked : mStackedLinks.values()) {
- // Hashtable values can never be null.
- String iface = stacked.getInterfaceName();
- if (!stacked.equals(target.mStackedLinks.get(iface))) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Compares this {@code LinkProperties} MTU against the target
- *
- * @param target LinkProperties to compare.
- * @return {@code true} if both are identical, {@code false} otherwise.
- * @hide
- */
- public boolean isIdenticalMtu(@NonNull LinkProperties target) {
- return getMtu() == target.getMtu();
- }
-
- /**
- * Compares this {@code LinkProperties} Tcp buffer sizes against the target.
- *
- * @param target LinkProperties to compare.
- * @return {@code true} if both are identical, {@code false} otherwise.
- * @hide
- */
- public boolean isIdenticalTcpBufferSizes(@NonNull LinkProperties target) {
- return Objects.equals(mTcpBufferSizes, target.mTcpBufferSizes);
- }
-
- /**
- * Compares this {@code LinkProperties} NAT64 prefix against the target.
- *
- * @param target LinkProperties to compare.
- * @return {@code true} if both are identical, {@code false} otherwise.
- * @hide
- */
- public boolean isIdenticalNat64Prefix(@NonNull LinkProperties target) {
- return Objects.equals(mNat64Prefix, target.mNat64Prefix);
- }
-
- /**
- * Compares this {@code LinkProperties} WakeOnLan supported against the target.
- *
- * @param target LinkProperties to compare.
- * @return {@code true} if both are identical, {@code false} otherwise.
- * @hide
- */
- public boolean isIdenticalWakeOnLan(LinkProperties target) {
- return isWakeOnLanSupported() == target.isWakeOnLanSupported();
- }
-
- /**
- * Compares this {@code LinkProperties}'s CaptivePortalApiUrl against the target.
- *
- * @param target LinkProperties to compare.
- * @return {@code true} if both are identical, {@code false} otherwise.
- * @hide
- */
- public boolean isIdenticalCaptivePortalApiUrl(LinkProperties target) {
- return Objects.equals(mCaptivePortalApiUrl, target.mCaptivePortalApiUrl);
- }
-
- /**
- * Compares this {@code LinkProperties}'s CaptivePortalData against the target.
- *
- * @param target LinkProperties to compare.
- * @return {@code true} if both are identical, {@code false} otherwise.
- * @hide
- */
- public boolean isIdenticalCaptivePortalData(LinkProperties target) {
- return Objects.equals(mCaptivePortalData, target.mCaptivePortalData);
- }
-
- /**
- * Set whether the network interface supports WakeOnLAN
- *
- * @param supported WakeOnLAN supported value
- *
- * @hide
- */
- public void setWakeOnLanSupported(boolean supported) {
- mWakeOnLanSupported = supported;
- }
-
- /**
- * Returns whether the network interface supports WakeOnLAN
- *
- * @return {@code true} if interface supports WakeOnLAN, {@code false} otherwise.
- */
- public boolean isWakeOnLanSupported() {
- return mWakeOnLanSupported;
- }
-
- /**
- * Set the URL of the captive portal API endpoint to get more information about the network.
- * @hide
- */
- @SystemApi
- public void setCaptivePortalApiUrl(@Nullable Uri url) {
- mCaptivePortalApiUrl = url;
- }
-
- /**
- * Get the URL of the captive portal API endpoint to get more information about the network.
- *
- * <p>This is null unless the application has
- * {@link android.Manifest.permission.NETWORK_SETTINGS} or
- * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions, and the network provided
- * the URL.
- * @hide
- */
- @SystemApi
- @Nullable
- public Uri getCaptivePortalApiUrl() {
- return mCaptivePortalApiUrl;
- }
-
- /**
- * Set the CaptivePortalData obtained from the captive portal API (RFC7710bis).
- * @hide
- */
- @SystemApi
- public void setCaptivePortalData(@Nullable CaptivePortalData data) {
- mCaptivePortalData = data;
- }
-
- /**
- * Get the CaptivePortalData obtained from the captive portal API (RFC7710bis).
- *
- * <p>This is null unless the application has
- * {@link android.Manifest.permission.NETWORK_SETTINGS} or
- * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions.
- * @hide
- */
- @SystemApi
- @Nullable
- public CaptivePortalData getCaptivePortalData() {
- return mCaptivePortalData;
- }
-
- /**
- * Compares this {@code LinkProperties} instance against the target
- * LinkProperties in {@code obj}. Two LinkPropertieses are equal if
- * all their fields are equal in values.
- *
- * For collection fields, such as mDnses, containsAll() is used to check
- * if two collections contains the same elements, independent of order.
- * There are two thoughts regarding containsAll()
- * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
- * 2. Worst case performance is O(n^2).
- *
- * @param obj the object to be tested for equality.
- * @return {@code true} if both objects are equal, {@code false} otherwise.
- */
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) return true;
-
- if (!(obj instanceof LinkProperties)) return false;
-
- LinkProperties target = (LinkProperties) obj;
- /*
- * This method does not check that stacked interfaces are equal, because
- * stacked interfaces are not so much a property of the link as a
- * description of connections between links.
- */
- return isIdenticalInterfaceName(target)
- && isIdenticalAddresses(target)
- && isIdenticalDhcpServerAddress(target)
- && isIdenticalDnses(target)
- && isIdenticalPrivateDns(target)
- && isIdenticalValidatedPrivateDnses(target)
- && isIdenticalPcscfs(target)
- && isIdenticalRoutes(target)
- && isIdenticalHttpProxy(target)
- && isIdenticalStackedLinks(target)
- && isIdenticalMtu(target)
- && isIdenticalTcpBufferSizes(target)
- && isIdenticalNat64Prefix(target)
- && isIdenticalWakeOnLan(target)
- && isIdenticalCaptivePortalApiUrl(target)
- && isIdenticalCaptivePortalData(target);
- }
-
- /**
- * Generate hashcode based on significant fields
- *
- * Equal objects must produce the same hash code, while unequal objects
- * may have the same hash codes.
- */
- @Override
- public int hashCode() {
- return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
- + mLinkAddresses.size() * 31
- + mDnses.size() * 37
- + mValidatedPrivateDnses.size() * 61
- + ((null == mDomains) ? 0 : mDomains.hashCode())
- + mRoutes.size() * 41
- + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())
- + mStackedLinks.hashCode() * 47)
- + mMtu * 51
- + ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode())
- + (mUsePrivateDns ? 57 : 0)
- + ((null == mDhcpServerAddress) ? 0 : mDhcpServerAddress.hashCode())
- + mPcscfs.size() * 67
- + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode())
- + Objects.hash(mNat64Prefix)
- + (mWakeOnLanSupported ? 71 : 0)
- + Objects.hash(mCaptivePortalApiUrl, mCaptivePortalData);
- }
-
- /**
- * Implement the Parcelable interface.
- */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(getInterfaceName());
- dest.writeInt(mLinkAddresses.size());
- for (LinkAddress linkAddress : mLinkAddresses) {
- dest.writeParcelable(linkAddress, flags);
- }
-
- writeAddresses(dest, mDnses);
- writeAddresses(dest, mValidatedPrivateDnses);
- dest.writeBoolean(mUsePrivateDns);
- dest.writeString(mPrivateDnsServerName);
- writeAddresses(dest, mPcscfs);
- dest.writeString(mDomains);
- writeAddress(dest, mDhcpServerAddress);
- dest.writeInt(mMtu);
- dest.writeString(mTcpBufferSizes);
- dest.writeInt(mRoutes.size());
- for (RouteInfo route : mRoutes) {
- dest.writeParcelable(route, flags);
- }
-
- if (mHttpProxy != null) {
- dest.writeByte((byte)1);
- dest.writeParcelable(mHttpProxy, flags);
- } else {
- dest.writeByte((byte)0);
- }
- dest.writeParcelable(mNat64Prefix, 0);
-
- ArrayList<LinkProperties> stackedLinks = new ArrayList<>(mStackedLinks.values());
- dest.writeList(stackedLinks);
-
- dest.writeBoolean(mWakeOnLanSupported);
- dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalApiUrl : null, 0);
- dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalData : null, 0);
- }
-
- private static void writeAddresses(@NonNull Parcel dest, @NonNull List<InetAddress> list) {
- dest.writeInt(list.size());
- for (InetAddress d : list) {
- writeAddress(dest, d);
- }
- }
-
- private static void writeAddress(@NonNull Parcel dest, @Nullable InetAddress addr) {
- byte[] addressBytes = (addr == null ? null : addr.getAddress());
- dest.writeByteArray(addressBytes);
- if (addr instanceof Inet6Address) {
- final Inet6Address v6Addr = (Inet6Address) addr;
- final boolean hasScopeId = v6Addr.getScopeId() != 0;
- dest.writeBoolean(hasScopeId);
- if (hasScopeId) dest.writeInt(v6Addr.getScopeId());
- }
- }
-
- @Nullable
- private static InetAddress readAddress(@NonNull Parcel p) throws UnknownHostException {
- final byte[] addr = p.createByteArray();
- if (addr == null) return null;
-
- if (addr.length == INET6_ADDR_LENGTH) {
- final boolean hasScopeId = p.readBoolean();
- final int scopeId = hasScopeId ? p.readInt() : 0;
- return Inet6Address.getByAddress(null /* host */, addr, scopeId);
- }
-
- return InetAddress.getByAddress(addr);
- }
-
- /**
- * Implement the Parcelable interface.
- */
- public static final @android.annotation.NonNull Creator<LinkProperties> CREATOR =
- new Creator<LinkProperties>() {
- public LinkProperties createFromParcel(Parcel in) {
- LinkProperties netProp = new LinkProperties();
-
- String iface = in.readString();
- if (iface != null) {
- netProp.setInterfaceName(iface);
- }
- int addressCount = in.readInt();
- for (int i = 0; i < addressCount; i++) {
- netProp.addLinkAddress(in.readParcelable(null));
- }
- addressCount = in.readInt();
- for (int i = 0; i < addressCount; i++) {
- try {
- netProp.addDnsServer(readAddress(in));
- } catch (UnknownHostException e) { }
- }
- addressCount = in.readInt();
- for (int i = 0; i < addressCount; i++) {
- try {
- netProp.addValidatedPrivateDnsServer(readAddress(in));
- } catch (UnknownHostException e) { }
- }
- netProp.setUsePrivateDns(in.readBoolean());
- netProp.setPrivateDnsServerName(in.readString());
- addressCount = in.readInt();
- for (int i = 0; i < addressCount; i++) {
- try {
- netProp.addPcscfServer(readAddress(in));
- } catch (UnknownHostException e) { }
- }
- netProp.setDomains(in.readString());
- try {
- netProp.setDhcpServerAddress((Inet4Address) InetAddress
- .getByAddress(in.createByteArray()));
- } catch (UnknownHostException e) { }
- netProp.setMtu(in.readInt());
- netProp.setTcpBufferSizes(in.readString());
- addressCount = in.readInt();
- for (int i = 0; i < addressCount; i++) {
- netProp.addRoute(in.readParcelable(null));
- }
- if (in.readByte() == 1) {
- netProp.setHttpProxy(in.readParcelable(null));
- }
- netProp.setNat64Prefix(in.readParcelable(null));
- ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
- in.readList(stackedLinks, LinkProperties.class.getClassLoader());
- for (LinkProperties stackedLink: stackedLinks) {
- netProp.addStackedLink(stackedLink);
- }
- netProp.setWakeOnLanSupported(in.readBoolean());
-
- netProp.setCaptivePortalApiUrl(in.readParcelable(null));
- netProp.setCaptivePortalData(in.readParcelable(null));
- return netProp;
- }
-
- public LinkProperties[] newArray(int size) {
- return new LinkProperties[size];
- }
- };
-
- /**
- * Check the valid MTU range based on IPv4 or IPv6.
- * @hide
- */
- public static boolean isValidMtu(int mtu, boolean ipv6) {
- if (ipv6) {
- return mtu >= MIN_MTU_V6 && mtu <= MAX_MTU;
- } else {
- return mtu >= MIN_MTU && mtu <= MAX_MTU;
- }
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/MacAddress.java b/packages/Connectivity/framework/src/android/net/MacAddress.java
deleted file mode 100644
index 26a504a..0000000
--- a/packages/Connectivity/framework/src/android/net/MacAddress.java
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.net.wifi.WifiInfo;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.net.module.util.MacAddressUtils;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.net.Inet6Address;
-import java.net.UnknownHostException;
-import java.security.SecureRandom;
-import java.util.Arrays;
-import java.util.Objects;
-
-/**
- * Representation of a MAC address.
- *
- * This class only supports 48 bits long addresses and does not support 64 bits long addresses.
- * Instances of this class are immutable. This class provides implementations of hashCode()
- * and equals() that make it suitable for use as keys in standard implementations of
- * {@link java.util.Map}.
- */
-public final class MacAddress implements Parcelable {
-
- private static final int ETHER_ADDR_LEN = 6;
- private static final byte[] ETHER_ADDR_BROADCAST = addr(0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
-
- /**
- * The MacAddress representing the unique broadcast MAC address.
- */
- public static final MacAddress BROADCAST_ADDRESS = MacAddress.fromBytes(ETHER_ADDR_BROADCAST);
-
- /**
- * The MacAddress zero MAC address.
- *
- * <p>Not publicly exposed or treated specially since the OUI 00:00:00 is registered.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final MacAddress ALL_ZEROS_ADDRESS = new MacAddress(0);
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "TYPE_" }, value = {
- TYPE_UNKNOWN,
- TYPE_UNICAST,
- TYPE_MULTICAST,
- TYPE_BROADCAST,
- })
- public @interface MacAddressType { }
-
- /** @hide Indicates a MAC address of unknown type. */
- public static final int TYPE_UNKNOWN = 0;
- /** Indicates a MAC address is a unicast address. */
- public static final int TYPE_UNICAST = 1;
- /** Indicates a MAC address is a multicast address. */
- public static final int TYPE_MULTICAST = 2;
- /** Indicates a MAC address is the broadcast address. */
- public static final int TYPE_BROADCAST = 3;
-
- private static final long VALID_LONG_MASK = (1L << 48) - 1;
- private static final long LOCALLY_ASSIGNED_MASK = MacAddress.fromString("2:0:0:0:0:0").mAddr;
- private static final long MULTICAST_MASK = MacAddress.fromString("1:0:0:0:0:0").mAddr;
- private static final long OUI_MASK = MacAddress.fromString("ff:ff:ff:0:0:0").mAddr;
- private static final long NIC_MASK = MacAddress.fromString("0:0:0:ff:ff:ff").mAddr;
- private static final MacAddress BASE_GOOGLE_MAC = MacAddress.fromString("da:a1:19:0:0:0");
- /** Default wifi MAC address used for a special purpose **/
- private static final MacAddress DEFAULT_MAC_ADDRESS =
- MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
-
- // Internal representation of the MAC address as a single 8 byte long.
- // The encoding scheme sets the two most significant bytes to 0. The 6 bytes of the
- // MAC address are encoded in the 6 least significant bytes of the long, where the first
- // byte of the array is mapped to the 3rd highest logical byte of the long, the second
- // byte of the array is mapped to the 4th highest logical byte of the long, and so on.
- private final long mAddr;
-
- private MacAddress(long addr) {
- mAddr = (VALID_LONG_MASK & addr);
- }
-
- /**
- * Returns the type of this address.
- *
- * @return the int constant representing the MAC address type of this MacAddress.
- */
- public @MacAddressType int getAddressType() {
- if (equals(BROADCAST_ADDRESS)) {
- return TYPE_BROADCAST;
- }
- if ((mAddr & MULTICAST_MASK) != 0) {
- return TYPE_MULTICAST;
- }
- return TYPE_UNICAST;
- }
-
- /**
- * @return true if this MacAddress is a locally assigned address.
- */
- public boolean isLocallyAssigned() {
- return (mAddr & LOCALLY_ASSIGNED_MASK) != 0;
- }
-
- /**
- * Convert this MacAddress to a byte array.
- *
- * The returned array is in network order. For example, if this MacAddress is 1:2:3:4:5:6,
- * the returned array is [1, 2, 3, 4, 5, 6].
- *
- * @return a byte array representation of this MacAddress.
- */
- public @NonNull byte[] toByteArray() {
- return byteAddrFromLongAddr(mAddr);
- }
-
- /**
- * Returns a human-readable representation of this MacAddress.
- * The exact format is implementation-dependent and should not be assumed to have any
- * particular format.
- */
- @Override
- public @NonNull String toString() {
- return stringAddrFromLongAddr(mAddr);
- }
-
- /**
- * @return a String representation of the OUI part of this MacAddress made of 3 hexadecimal
- * numbers in [0,ff] joined by ':' characters.
- */
- public @NonNull String toOuiString() {
- return String.format(
- "%02x:%02x:%02x", (mAddr >> 40) & 0xff, (mAddr >> 32) & 0xff, (mAddr >> 24) & 0xff);
- }
-
- @Override
- public int hashCode() {
- return (int) ((mAddr >> 32) ^ mAddr);
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- return (o instanceof MacAddress) && ((MacAddress) o).mAddr == mAddr;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeLong(mAddr);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<MacAddress> CREATOR =
- new Parcelable.Creator<MacAddress>() {
- public MacAddress createFromParcel(Parcel in) {
- return new MacAddress(in.readLong());
- }
-
- public MacAddress[] newArray(int size) {
- return new MacAddress[size];
- }
- };
-
- /**
- * Returns true if the given byte array is an valid MAC address.
- * A valid byte array representation for a MacAddress is a non-null array of length 6.
- *
- * @param addr a byte array.
- * @return true if the given byte array is not null and has the length of a MAC address.
- *
- * @hide
- */
- public static boolean isMacAddress(byte[] addr) {
- return MacAddressUtils.isMacAddress(addr);
- }
-
- /**
- * Returns the MAC address type of the MAC address represented by the given byte array,
- * or null if the given byte array does not represent a MAC address.
- * A valid byte array representation for a MacAddress is a non-null array of length 6.
- *
- * @param addr a byte array representing a MAC address.
- * @return the int constant representing the MAC address type of the MAC address represented
- * by the given byte array, or type UNKNOWN if the byte array is not a valid MAC address.
- *
- * @hide
- */
- public static int macAddressType(byte[] addr) {
- if (!isMacAddress(addr)) {
- return TYPE_UNKNOWN;
- }
- return MacAddress.fromBytes(addr).getAddressType();
- }
-
- /**
- * Converts a String representation of a MAC address to a byte array representation.
- * A valid String representation for a MacAddress is a series of 6 values in the
- * range [0,ff] printed in hexadecimal and joined by ':' characters.
- *
- * @param addr a String representation of a MAC address.
- * @return the byte representation of the MAC address.
- * @throws IllegalArgumentException if the given String is not a valid representation.
- *
- * @hide
- */
- public static @NonNull byte[] byteAddrFromStringAddr(String addr) {
- Objects.requireNonNull(addr);
- String[] parts = addr.split(":");
- if (parts.length != ETHER_ADDR_LEN) {
- throw new IllegalArgumentException(addr + " was not a valid MAC address");
- }
- byte[] bytes = new byte[ETHER_ADDR_LEN];
- for (int i = 0; i < ETHER_ADDR_LEN; i++) {
- int x = Integer.valueOf(parts[i], 16);
- if (x < 0 || 0xff < x) {
- throw new IllegalArgumentException(addr + "was not a valid MAC address");
- }
- bytes[i] = (byte) x;
- }
- return bytes;
- }
-
- /**
- * Converts a byte array representation of a MAC address to a String representation made
- * of 6 hexadecimal numbers in [0,ff] joined by ':' characters.
- * A valid byte array representation for a MacAddress is a non-null array of length 6.
- *
- * @param addr a byte array representation of a MAC address.
- * @return the String representation of the MAC address.
- * @throws IllegalArgumentException if the given byte array is not a valid representation.
- *
- * @hide
- */
- public static @NonNull String stringAddrFromByteAddr(byte[] addr) {
- if (!isMacAddress(addr)) {
- return null;
- }
- return String.format("%02x:%02x:%02x:%02x:%02x:%02x",
- addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
- }
-
- private static byte[] byteAddrFromLongAddr(long addr) {
- return MacAddressUtils.byteAddrFromLongAddr(addr);
- }
-
- private static long longAddrFromByteAddr(byte[] addr) {
- return MacAddressUtils.longAddrFromByteAddr(addr);
- }
-
- // Internal conversion function equivalent to longAddrFromByteAddr(byteAddrFromStringAddr(addr))
- // that avoids the allocation of an intermediary byte[].
- private static long longAddrFromStringAddr(String addr) {
- Objects.requireNonNull(addr);
- String[] parts = addr.split(":");
- if (parts.length != ETHER_ADDR_LEN) {
- throw new IllegalArgumentException(addr + " was not a valid MAC address");
- }
- long longAddr = 0;
- for (int i = 0; i < parts.length; i++) {
- int x = Integer.valueOf(parts[i], 16);
- if (x < 0 || 0xff < x) {
- throw new IllegalArgumentException(addr + "was not a valid MAC address");
- }
- longAddr = x + (longAddr << 8);
- }
- return longAddr;
- }
-
- // Internal conversion function equivalent to stringAddrFromByteAddr(byteAddrFromLongAddr(addr))
- // that avoids the allocation of an intermediary byte[].
- private static @NonNull String stringAddrFromLongAddr(long addr) {
- return String.format("%02x:%02x:%02x:%02x:%02x:%02x",
- (addr >> 40) & 0xff,
- (addr >> 32) & 0xff,
- (addr >> 24) & 0xff,
- (addr >> 16) & 0xff,
- (addr >> 8) & 0xff,
- addr & 0xff);
- }
-
- /**
- * Creates a MacAddress from the given String representation. A valid String representation
- * for a MacAddress is a series of 6 values in the range [0,ff] printed in hexadecimal
- * and joined by ':' characters.
- *
- * @param addr a String representation of a MAC address.
- * @return the MacAddress corresponding to the given String representation.
- * @throws IllegalArgumentException if the given String is not a valid representation.
- */
- public static @NonNull MacAddress fromString(@NonNull String addr) {
- return new MacAddress(longAddrFromStringAddr(addr));
- }
-
- /**
- * Creates a MacAddress from the given byte array representation.
- * A valid byte array representation for a MacAddress is a non-null array of length 6.
- *
- * @param addr a byte array representation of a MAC address.
- * @return the MacAddress corresponding to the given byte array representation.
- * @throws IllegalArgumentException if the given byte array is not a valid representation.
- */
- public static @NonNull MacAddress fromBytes(@NonNull byte[] addr) {
- return new MacAddress(longAddrFromByteAddr(addr));
- }
-
- /**
- * Returns a generated MAC address whose 24 least significant bits constituting the
- * NIC part of the address are randomly selected and has Google OUI base.
- *
- * The locally assigned bit is always set to 1. The multicast bit is always set to 0.
- *
- * @return a random locally assigned, unicast MacAddress with Google OUI.
- *
- * @hide
- */
- public static @NonNull MacAddress createRandomUnicastAddressWithGoogleBase() {
- return MacAddressUtils.createRandomUnicastAddress(BASE_GOOGLE_MAC, new SecureRandom());
- }
-
- // Convenience function for working around the lack of byte literals.
- private static byte[] addr(int... in) {
- if (in.length != ETHER_ADDR_LEN) {
- throw new IllegalArgumentException(Arrays.toString(in)
- + " was not an array with length equal to " + ETHER_ADDR_LEN);
- }
- byte[] out = new byte[ETHER_ADDR_LEN];
- for (int i = 0; i < ETHER_ADDR_LEN; i++) {
- out[i] = (byte) in[i];
- }
- return out;
- }
-
- /**
- * Checks if this MAC Address matches the provided range.
- *
- * @param baseAddress MacAddress representing the base address to compare with.
- * @param mask MacAddress representing the mask to use during comparison.
- * @return true if this MAC Address matches the given range.
- *
- */
- public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
- Objects.requireNonNull(baseAddress);
- Objects.requireNonNull(mask);
- return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr);
- }
-
- /**
- * Create a link-local Inet6Address from the MAC address. The EUI-48 MAC address is converted
- * to an EUI-64 MAC address per RFC 4291. The resulting EUI-64 is used to construct a link-local
- * IPv6 address per RFC 4862.
- *
- * @return A link-local Inet6Address constructed from the MAC address.
- */
- public @Nullable Inet6Address getLinkLocalIpv6FromEui48Mac() {
- byte[] macEui48Bytes = toByteArray();
- byte[] addr = new byte[16];
-
- addr[0] = (byte) 0xfe;
- addr[1] = (byte) 0x80;
- addr[8] = (byte) (macEui48Bytes[0] ^ (byte) 0x02); // flip the link-local bit
- addr[9] = macEui48Bytes[1];
- addr[10] = macEui48Bytes[2];
- addr[11] = (byte) 0xff;
- addr[12] = (byte) 0xfe;
- addr[13] = macEui48Bytes[3];
- addr[14] = macEui48Bytes[4];
- addr[15] = macEui48Bytes[5];
-
- try {
- return Inet6Address.getByAddress(null, addr, 0);
- } catch (UnknownHostException e) {
- return null;
- }
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/NattKeepalivePacketData.java b/packages/Connectivity/framework/src/android/net/NattKeepalivePacketData.java
deleted file mode 100644
index c4f8fc2..0000000
--- a/packages/Connectivity/framework/src/android/net/NattKeepalivePacketData.java
+++ /dev/null
@@ -1,144 +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 android.net;
-
-import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS;
-import static android.net.InvalidPacketException.ERROR_INVALID_PORT;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.system.OsConstants;
-
-import com.android.net.module.util.IpUtils;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Objects;
-
-/** @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
- 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)
- throws InvalidPacketException {
-
- if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) {
- throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
- }
-
- if (dstPort != NattSocketKeepalive.NATT_PORT) {
- throw new InvalidPacketException(ERROR_INVALID_PORT);
- }
-
- int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1;
- ByteBuffer buf = ByteBuffer.allocate(length);
- buf.order(ByteOrder.BIG_ENDIAN);
- buf.putShort((short) 0x4500); // IP version and TOS
- buf.putShort((short) length);
- buf.putInt(0); // ID, flags, offset
- buf.put((byte) 64); // TTL
- buf.put((byte) OsConstants.IPPROTO_UDP);
- int ipChecksumOffset = buf.position();
- buf.putShort((short) 0); // IP checksum
- buf.put(srcAddress.getAddress());
- buf.put(dstAddress.getAddress());
- buf.putShort((short) srcPort);
- buf.putShort((short) dstPort);
- buf.putShort((short) (length - 20)); // UDP length
- int udpChecksumOffset = buf.position();
- buf.putShort((short) 0); // UDP checksum
- buf.put((byte) 0xff); // NAT-T keepalive
- buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
- buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH));
-
- return new NattKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
- }
-
- /** Parcelable Implementation */
- public int describeContents() {
- return 0;
- }
-
- /** Write to parcel */
- public void writeToParcel(@NonNull Parcel out, int flags) {
- out.writeString(getSrcAddress().getHostAddress());
- out.writeString(getDstAddress().getHostAddress());
- out.writeInt(getSrcPort());
- out.writeInt(getDstPort());
- }
-
- /** Parcelable Creator */
- public static final @NonNull Parcelable.Creator<NattKeepalivePacketData> CREATOR =
- new Parcelable.Creator<NattKeepalivePacketData>() {
- public NattKeepalivePacketData createFromParcel(Parcel in) {
- final InetAddress srcAddress =
- InetAddresses.parseNumericAddress(in.readString());
- final InetAddress dstAddress =
- InetAddresses.parseNumericAddress(in.readString());
- final int srcPort = in.readInt();
- final int dstPort = in.readInt();
- try {
- return NattKeepalivePacketData.nattKeepalivePacket(srcAddress, srcPort,
- dstAddress, dstPort);
- } catch (InvalidPacketException e) {
- throw new IllegalArgumentException(
- "Invalid NAT-T keepalive data: " + e.getError());
- }
- }
-
- public NattKeepalivePacketData[] newArray(int size) {
- return new NattKeepalivePacketData[size];
- }
- };
-
- @Override
- public boolean equals(@Nullable final Object o) {
- if (!(o instanceof NattKeepalivePacketData)) return false;
- final NattKeepalivePacketData other = (NattKeepalivePacketData) o;
- final InetAddress srcAddress = getSrcAddress();
- final InetAddress dstAddress = getDstAddress();
- return srcAddress.equals(other.getSrcAddress())
- && dstAddress.equals(other.getDstAddress())
- && getSrcPort() == other.getSrcPort()
- && getDstPort() == other.getDstPort();
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort());
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/NattSocketKeepalive.java b/packages/Connectivity/framework/src/android/net/NattSocketKeepalive.java
deleted file mode 100644
index a15d165..0000000
--- a/packages/Connectivity/framework/src/android/net/NattSocketKeepalive.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.NonNull;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.net.InetAddress;
-import java.util.concurrent.Executor;
-
-/** @hide */
-public final class NattSocketKeepalive extends SocketKeepalive {
- /** The NAT-T destination port for IPsec */
- public static final int NATT_PORT = 4500;
-
- @NonNull private final InetAddress mSource;
- @NonNull private final InetAddress mDestination;
- private final int mResourceId;
-
- NattSocketKeepalive(@NonNull IConnectivityManager service,
- @NonNull Network network,
- @NonNull ParcelFileDescriptor pfd,
- int resourceId,
- @NonNull InetAddress source,
- @NonNull InetAddress destination,
- @NonNull Executor executor,
- @NonNull Callback callback) {
- super(service, network, pfd, executor, callback);
- mSource = source;
- mDestination = destination;
- mResourceId = resourceId;
- }
-
- @Override
- void startImpl(int intervalSec) {
- mExecutor.execute(() -> {
- try {
- mService.startNattKeepaliveWithFd(mNetwork, mPfd, mResourceId,
- intervalSec, mCallback,
- mSource.getHostAddress(), mDestination.getHostAddress());
- } catch (RemoteException e) {
- Log.e(TAG, "Error starting socket keepalive: ", e);
- throw e.rethrowFromSystemServer();
- }
- });
- }
-
- @Override
- void stopImpl() {
- mExecutor.execute(() -> {
- try {
- if (mSlot != null) {
- mService.stopKeepalive(mNetwork, mSlot);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Error stopping socket keepalive: ", e);
- throw e.rethrowFromSystemServer();
- }
- });
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/Network.java b/packages/Connectivity/framework/src/android/net/Network.java
deleted file mode 100644
index 1f49033..0000000
--- a/packages/Connectivity/framework/src/android/net/Network.java
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
-
-import com.android.internal.annotations.GuardedBy;
-
-import libcore.io.IoUtils;
-import libcore.net.http.Dns;
-import libcore.net.http.HttpURLConnectionFactory;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.MalformedURLException;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.net.SocketException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.concurrent.TimeUnit;
-
-import javax.net.SocketFactory;
-
-/**
- * Identifies a {@code Network}. This is supplied to applications via
- * {@link ConnectivityManager.NetworkCallback} in response to the active
- * {@link ConnectivityManager#requestNetwork} or passive
- * {@link ConnectivityManager#registerNetworkCallback} calls.
- * It is used to direct traffic to the given {@code Network}, either on a {@link Socket} basis
- * through a targeted {@link SocketFactory} or process-wide via
- * {@link ConnectivityManager#bindProcessToNetwork}.
- */
-public class Network implements Parcelable {
-
- /**
- * The unique id of the network.
- * @hide
- */
- @UnsupportedAppUsage
- public final int netId;
-
- // Objects used to perform per-network operations such as getSocketFactory
- // and openConnection, and a lock to protect access to them.
- private volatile NetworkBoundSocketFactory mNetworkBoundSocketFactory = null;
- // mUrlConnectionFactory is initialized lazily when it is first needed.
- @GuardedBy("mLock")
- private HttpURLConnectionFactory mUrlConnectionFactory;
- private final Object mLock = new Object();
-
- // Default connection pool values. These are evaluated at startup, just
- // like the OkHttp code. Also like the OkHttp code, we will throw parse
- // exceptions at class loading time if the properties are set but are not
- // valid integers.
- private static final boolean httpKeepAlive =
- Boolean.parseBoolean(System.getProperty("http.keepAlive", "true"));
- private static final int httpMaxConnections =
- httpKeepAlive ? Integer.parseInt(System.getProperty("http.maxConnections", "5")) : 0;
- private static final long httpKeepAliveDurationMs =
- Long.parseLong(System.getProperty("http.keepAliveDuration", "300000")); // 5 minutes.
- // Value used to obfuscate network handle longs.
- // The HANDLE_MAGIC value MUST be kept in sync with the corresponding
- // value in the native/android/net.c NDK implementation.
- private static final long HANDLE_MAGIC = 0xcafed00dL;
- private static final int HANDLE_MAGIC_SIZE = 32;
- private static final int USE_LOCAL_NAMESERVERS_FLAG = 0x80000000;
-
- // A boolean to control how getAllByName()/getByName() behaves in the face
- // of Private DNS.
- //
- // When true, these calls will request that DNS resolution bypass any
- // Private DNS that might otherwise apply. Use of this feature is restricted
- // and permission checks are made by netd (attempts to bypass Private DNS
- // without appropriate permission are silently turned into vanilla DNS
- // requests). This only affects DNS queries made using this network object.
- //
- // It it not parceled to receivers because (a) it can be set or cleared at
- // anytime and (b) receivers should be explicit about attempts to bypass
- // Private DNS so that the intent of the code is easily determined and
- // code search audits are possible.
- private final transient boolean mPrivateDnsBypass;
-
- /**
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public Network(int netId) {
- this(netId, false);
- }
-
- /**
- * @hide
- */
- public Network(int netId, boolean privateDnsBypass) {
- this.netId = netId;
- this.mPrivateDnsBypass = privateDnsBypass;
- }
-
- /**
- * @hide
- */
- @SystemApi
- public Network(@NonNull Network that) {
- this(that.netId, that.mPrivateDnsBypass);
- }
-
- /**
- * Operates the same as {@code InetAddress.getAllByName} except that host
- * resolution is done on this network.
- *
- * @param host the hostname or literal IP string to be resolved.
- * @return the array of addresses associated with the specified host.
- * @throws UnknownHostException if the address lookup fails.
- */
- public InetAddress[] getAllByName(String host) throws UnknownHostException {
- return InetAddressCompat.getAllByNameOnNet(host, getNetIdForResolv());
- }
-
- /**
- * Operates the same as {@code InetAddress.getByName} except that host
- * resolution is done on this network.
- *
- * @param host the hostname to be resolved to an address or {@code null}.
- * @return the {@code InetAddress} instance representing the host.
- * @throws UnknownHostException
- * if the address lookup fails.
- */
- public InetAddress getByName(String host) throws UnknownHostException {
- return InetAddressCompat.getByNameOnNet(host, getNetIdForResolv());
- }
-
- /**
- * Obtain a Network object for which Private DNS is to be bypassed when attempting
- * to use {@link #getAllByName(String)}/{@link #getByName(String)} methods on the given
- * instance for hostname resolution.
- *
- * @hide
- */
- @SystemApi
- public @NonNull Network getPrivateDnsBypassingCopy() {
- return new Network(netId, true);
- }
-
- /**
- * Get the unique id of the network.
- *
- * @hide
- */
- @SystemApi
- public int getNetId() {
- return netId;
- }
-
- /**
- * Returns a netid marked with the Private DNS bypass flag.
- *
- * This flag must be kept in sync with the NETID_USE_LOCAL_NAMESERVERS flag
- * in system/netd/include/NetdClient.h.
- *
- * @hide
- */
- public int getNetIdForResolv() {
- return mPrivateDnsBypass
- ? (USE_LOCAL_NAMESERVERS_FLAG | netId) // Non-portable DNS resolution flag.
- : netId;
- }
-
- /**
- * A {@code SocketFactory} that produces {@code Socket}'s bound to this network.
- */
- private class NetworkBoundSocketFactory extends SocketFactory {
- private Socket connectToHost(String host, int port, SocketAddress localAddress)
- throws IOException {
- // Lookup addresses only on this Network.
- InetAddress[] hostAddresses = getAllByName(host);
- // Try all addresses.
- for (int i = 0; i < hostAddresses.length; i++) {
- try {
- Socket socket = createSocket();
- boolean failed = true;
- try {
- if (localAddress != null) socket.bind(localAddress);
- socket.connect(new InetSocketAddress(hostAddresses[i], port));
- failed = false;
- return socket;
- } finally {
- if (failed) IoUtils.closeQuietly(socket);
- }
- } catch (IOException e) {
- if (i == (hostAddresses.length - 1)) throw e;
- }
- }
- throw new UnknownHostException(host);
- }
-
- @Override
- public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
- throws IOException {
- return connectToHost(host, port, new InetSocketAddress(localHost, localPort));
- }
-
- @Override
- public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
- int localPort) throws IOException {
- Socket socket = createSocket();
- boolean failed = true;
- try {
- socket.bind(new InetSocketAddress(localAddress, localPort));
- socket.connect(new InetSocketAddress(address, port));
- failed = false;
- } finally {
- if (failed) IoUtils.closeQuietly(socket);
- }
- return socket;
- }
-
- @Override
- public Socket createSocket(InetAddress host, int port) throws IOException {
- Socket socket = createSocket();
- boolean failed = true;
- try {
- socket.connect(new InetSocketAddress(host, port));
- failed = false;
- } finally {
- if (failed) IoUtils.closeQuietly(socket);
- }
- return socket;
- }
-
- @Override
- public Socket createSocket(String host, int port) throws IOException {
- return connectToHost(host, port, null);
- }
-
- @Override
- public Socket createSocket() throws IOException {
- Socket socket = new Socket();
- boolean failed = true;
- try {
- bindSocket(socket);
- failed = false;
- } finally {
- if (failed) IoUtils.closeQuietly(socket);
- }
- return socket;
- }
- }
-
- /**
- * Returns a {@link SocketFactory} bound to this network. Any {@link Socket} created by
- * this factory will have its traffic sent over this {@code Network}. Note that if this
- * {@code Network} ever disconnects, this factory and any {@link Socket} it produced in the
- * past or future will cease to work.
- *
- * @return a {@link SocketFactory} which produces {@link Socket} instances bound to this
- * {@code Network}.
- */
- public SocketFactory getSocketFactory() {
- if (mNetworkBoundSocketFactory == null) {
- synchronized (mLock) {
- if (mNetworkBoundSocketFactory == null) {
- mNetworkBoundSocketFactory = new NetworkBoundSocketFactory();
- }
- }
- }
- return mNetworkBoundSocketFactory;
- }
-
- private static HttpURLConnectionFactory createUrlConnectionFactory(Dns dnsLookup) {
- // Set configuration on the HttpURLConnectionFactory that will be good for all
- // connections created by this Network. Configuration that might vary is left
- // until openConnection() and passed as arguments.
- HttpURLConnectionFactory urlConnectionFactory = HttpURLConnectionFactory.createInstance();
- urlConnectionFactory.setDns(dnsLookup); // Let traffic go via dnsLookup
- // A private connection pool just for this Network.
- urlConnectionFactory.setNewConnectionPool(httpMaxConnections,
- httpKeepAliveDurationMs, TimeUnit.MILLISECONDS);
- return urlConnectionFactory;
- }
-
- /**
- * Opens the specified {@link URL} on this {@code Network}, such that all traffic will be sent
- * on this Network. The URL protocol must be {@code HTTP} or {@code HTTPS}.
- *
- * @return a {@code URLConnection} to the resource referred to by this URL.
- * @throws MalformedURLException if the URL protocol is not HTTP or HTTPS.
- * @throws IOException if an error occurs while opening the connection.
- * @see java.net.URL#openConnection()
- */
- public URLConnection openConnection(URL url) throws IOException {
- final ConnectivityManager cm = ConnectivityManager.getInstanceOrNull();
- if (cm == null) {
- throw new IOException("No ConnectivityManager yet constructed, please construct one");
- }
- // TODO: Should this be optimized to avoid fetching the global proxy for every request?
- final ProxyInfo proxyInfo = cm.getProxyForNetwork(this);
- final java.net.Proxy proxy;
- if (proxyInfo != null) {
- proxy = proxyInfo.makeProxy();
- } else {
- proxy = java.net.Proxy.NO_PROXY;
- }
- return openConnection(url, proxy);
- }
-
- /**
- * Opens the specified {@link URL} on this {@code Network}, such that all traffic will be sent
- * on this Network. The URL protocol must be {@code HTTP} or {@code HTTPS}.
- *
- * @param proxy the proxy through which the connection will be established.
- * @return a {@code URLConnection} to the resource referred to by this URL.
- * @throws MalformedURLException if the URL protocol is not HTTP or HTTPS.
- * @throws IllegalArgumentException if the argument proxy is null.
- * @throws IOException if an error occurs while opening the connection.
- * @see java.net.URL#openConnection()
- */
- public URLConnection openConnection(URL url, java.net.Proxy proxy) throws IOException {
- if (proxy == null) throw new IllegalArgumentException("proxy is null");
- // TODO: This creates a connection pool and host resolver for
- // every Network object, instead of one for every NetId. This is
- // suboptimal, because an app could potentially have more than one
- // Network object for the same NetId, causing increased memory footprint
- // and performance penalties due to lack of connection reuse (connection
- // setup time, congestion window growth time, etc.).
- //
- // Instead, investigate only having one connection pool and host resolver
- // for every NetId, perhaps by using a static HashMap of NetIds to
- // connection pools and host resolvers. The tricky part is deciding when
- // to remove a map entry; a WeakHashMap shouldn't be used because whether
- // a Network is referenced doesn't correlate with whether a new Network
- // will be instantiated in the near future with the same NetID. A good
- // solution would involve purging empty (or when all connections are timed
- // out) ConnectionPools.
- final HttpURLConnectionFactory urlConnectionFactory;
- synchronized (mLock) {
- if (mUrlConnectionFactory == null) {
- Dns dnsLookup = hostname -> Arrays.asList(getAllByName(hostname));
- mUrlConnectionFactory = createUrlConnectionFactory(dnsLookup);
- }
- urlConnectionFactory = mUrlConnectionFactory;
- }
- SocketFactory socketFactory = getSocketFactory();
- return urlConnectionFactory.openConnection(url, socketFactory, proxy);
- }
-
- /**
- * Binds the specified {@link DatagramSocket} to this {@code Network}. All data traffic on the
- * socket will be sent on this {@code Network}, irrespective of any process-wide network binding
- * set by {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be
- * connected.
- */
- public void bindSocket(DatagramSocket socket) throws IOException {
- // Query a property of the underlying socket to ensure that the socket's file descriptor
- // exists, is available to bind to a network and is not closed.
- socket.getReuseAddress();
- final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket);
- bindSocket(pfd.getFileDescriptor());
- // ParcelFileDescriptor.fromSocket() creates a dup of the original fd. The original and the
- // dup share the underlying socket in the kernel. The socket is never truly closed until the
- // last fd pointing to the socket being closed. So close the dup one after binding the
- // socket to control the lifetime of the dup fd.
- pfd.close();
- }
-
- /**
- * Binds the specified {@link Socket} to this {@code Network}. All data traffic on the socket
- * will be sent on this {@code Network}, irrespective of any process-wide network binding set by
- * {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be connected.
- */
- public void bindSocket(Socket socket) throws IOException {
- // Query a property of the underlying socket to ensure that the socket's file descriptor
- // exists, is available to bind to a network and is not closed.
- socket.getReuseAddress();
- final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
- bindSocket(pfd.getFileDescriptor());
- // ParcelFileDescriptor.fromSocket() creates a dup of the original fd. The original and the
- // dup share the underlying socket in the kernel. The socket is never truly closed until the
- // last fd pointing to the socket being closed. So close the dup one after binding the
- // socket to control the lifetime of the dup fd.
- pfd.close();
- }
-
- /**
- * Binds the specified {@link FileDescriptor} to this {@code Network}. All data traffic on the
- * socket represented by this file descriptor will be sent on this {@code Network},
- * irrespective of any process-wide network binding set by
- * {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be connected.
- */
- public void bindSocket(FileDescriptor fd) throws IOException {
- try {
- final SocketAddress peer = Os.getpeername(fd);
- final InetAddress inetPeer = ((InetSocketAddress) peer).getAddress();
- if (!inetPeer.isAnyLocalAddress()) {
- // Apparently, the kernel doesn't update a connected UDP socket's
- // routing upon mark changes.
- throw new SocketException("Socket is connected");
- }
- } catch (ErrnoException e) {
- // getpeername() failed.
- if (e.errno != OsConstants.ENOTCONN) {
- throw e.rethrowAsSocketException();
- }
- } catch (ClassCastException e) {
- // Wasn't an InetSocketAddress.
- throw new SocketException("Only AF_INET/AF_INET6 sockets supported");
- }
-
- final int err = NetworkUtils.bindSocketToNetwork(fd, netId);
- if (err != 0) {
- // bindSocketToNetwork returns negative errno.
- throw new ErrnoException("Binding socket to network " + netId, -err)
- .rethrowAsSocketException();
- }
- }
-
- /**
- * Returns a {@link Network} object given a handle returned from {@link #getNetworkHandle}.
- *
- * @param networkHandle a handle returned from {@link #getNetworkHandle}.
- * @return A {@link Network} object derived from {@code networkHandle}.
- */
- public static Network fromNetworkHandle(long networkHandle) {
- if (networkHandle == 0) {
- throw new IllegalArgumentException(
- "Network.fromNetworkHandle refusing to instantiate NETID_UNSET Network.");
- }
- if ((networkHandle & ((1L << HANDLE_MAGIC_SIZE) - 1)) != HANDLE_MAGIC) {
- throw new IllegalArgumentException(
- "Value passed to fromNetworkHandle() is not a network handle.");
- }
- final int netIdForResolv = (int) (networkHandle >>> HANDLE_MAGIC_SIZE);
- return new Network((netIdForResolv & ~USE_LOCAL_NAMESERVERS_FLAG),
- ((netIdForResolv & USE_LOCAL_NAMESERVERS_FLAG) != 0) /* privateDnsBypass */);
- }
-
- /**
- * Returns a handle representing this {@code Network}, for use with the NDK API.
- */
- public long getNetworkHandle() {
- // The network handle is explicitly not the same as the netId.
- //
- // The netId is an implementation detail which might be changed in the
- // future, or which alone (i.e. in the absence of some additional
- // context) might not be sufficient to fully identify a Network.
- //
- // As such, the intention is to prevent accidental misuse of the API
- // that might result if a developer assumed that handles and netIds
- // were identical and passing a netId to a call expecting a handle
- // "just worked". Such accidental misuse, if widely deployed, might
- // prevent future changes to the semantics of the netId field or
- // inhibit the expansion of state required for Network objects.
- //
- // This extra layer of indirection might be seen as paranoia, and might
- // never end up being necessary, but the added complexity is trivial.
- // At some future date it may be desirable to realign the handle with
- // Multiple Provisioning Domains API recommendations, as made by the
- // IETF mif working group.
- if (netId == 0) {
- return 0L; // make this zero condition obvious for debugging
- }
- return (((long) getNetIdForResolv()) << HANDLE_MAGIC_SIZE) | HANDLE_MAGIC;
- }
-
- // implement the Parcelable interface
- public int describeContents() {
- return 0;
- }
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(netId);
- }
-
- public static final @android.annotation.NonNull Creator<Network> CREATOR =
- new Creator<Network>() {
- public Network createFromParcel(Parcel in) {
- int netId = in.readInt();
-
- return new Network(netId);
- }
-
- public Network[] newArray(int size) {
- return new Network[size];
- }
- };
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (!(obj instanceof Network)) return false;
- Network other = (Network)obj;
- return this.netId == other.netId;
- }
-
- @Override
- public int hashCode() {
- return netId * 11;
- }
-
- @Override
- public String toString() {
- return Integer.toString(netId);
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgent.java b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
deleted file mode 100644
index adcf338..0000000
--- a/packages/Connectivity/framework/src/android/net/NetworkAgent.java
+++ /dev/null
@@ -1,1324 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.IntDef;
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.annotation.TestApi;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.Context;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.telephony.data.EpsBearerQosSessionAttributes;
-import android.telephony.data.NrQosSessionAttributes;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * A utility class for handling for communicating between bearer-specific
- * code and ConnectivityService.
- *
- * An agent manages the life cycle of a network. A network starts its
- * life cycle when {@link register} is called on NetworkAgent. The network
- * is then connecting. When full L3 connectivity has been established,
- * the agent should call {@link markConnected} to inform the system that
- * this network is ready to use. When the network disconnects its life
- * ends and the agent should call {@link unregister}, at which point the
- * system will clean up and free resources.
- * Any reconnection becomes a new logical network, so after a network
- * is disconnected the agent cannot be used any more. Network providers
- * should create a new NetworkAgent instance to handle new connections.
- *
- * A bearer may have more than one NetworkAgent if it can simultaneously
- * support separate networks (IMS / Internet / MMS Apns on cellular, or
- * perhaps connections with different SSID or P2P for Wi-Fi).
- *
- * This class supports methods to start and stop sending keepalive packets.
- * Keepalive packets are typically sent at periodic intervals over a network
- * with NAT when there is no other traffic to avoid the network forcefully
- * closing the connection. NetworkAgents that manage technologies that
- * have hardware support for keepalive should implement the related
- * methods to save battery life. NetworkAgent that cannot get support
- * without waking up the CPU should not, as this would be prohibitive in
- * terms of battery - these agents should simply not override the related
- * methods, which results in the implementation returning
- * {@link SocketKeepalive.ERROR_UNSUPPORTED} as appropriate.
- *
- * Keepalive packets need to be sent at relatively frequent intervals
- * (a few seconds to a few minutes). As the contents of keepalive packets
- * depend on the current network status, hardware needs to be configured
- * to send them and has a limited amount of memory to do so. The HAL
- * formalizes this as slots that an implementation can configure to send
- * the correct packets. Devices typically have a small number of slots
- * per radio technology, and the specific number of slots for each
- * technology is specified in configuration files.
- * {@see SocketKeepalive} for details.
- *
- * @hide
- */
-@SystemApi
-public abstract class NetworkAgent {
- /**
- * The {@link Network} corresponding to this object.
- */
- @Nullable
- private volatile Network mNetwork;
-
- @Nullable
- private volatile INetworkAgentRegistry mRegistry;
-
- private interface RegistryAction {
- void execute(@NonNull INetworkAgentRegistry registry) throws RemoteException;
- }
-
- private final Handler mHandler;
- private final String LOG_TAG;
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
- /** @hide */
- @TestApi
- public static final int MIN_LINGER_TIMER_MS = 2000;
- private final ArrayList<RegistryAction> mPreConnectedQueue = new ArrayList<>();
- private volatile long mLastBwRefreshTime = 0;
- private static final long BW_REFRESH_MIN_WIN_MS = 500;
- private boolean mBandwidthUpdateScheduled = false;
- private AtomicBoolean mBandwidthUpdatePending = new AtomicBoolean(false);
- @NonNull
- private NetworkInfo mNetworkInfo;
- @NonNull
- private final Object mRegisterLock = new Object();
-
- /**
- * The ID of the {@link NetworkProvider} that created this object, or
- * {@link NetworkProvider#ID_NONE} if unknown.
- * @hide
- */
- public final int providerId;
-
- // ConnectivityService parses message constants from itself and NetworkAgent with MessageUtils
- // for debugging purposes, and crashes if some messages have the same values.
- // TODO: have ConnectivityService store message names in different maps and remove this base
- private static final int BASE = 200;
-
- /**
- * Sent by ConnectivityService to the NetworkAgent to inform it of
- * suspected connectivity problems on its network. The NetworkAgent
- * should take steps to verify and correct connectivity.
- * @hide
- */
- public static final int CMD_SUSPECT_BAD = BASE;
-
- /**
- * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to
- * ConnectivityService to pass the current NetworkInfo (connection state).
- * Sent when the NetworkInfo changes, mainly due to change of state.
- * obj = NetworkInfo
- * @hide
- */
- public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 1;
-
- /**
- * Sent by the NetworkAgent to ConnectivityService to pass the current
- * NetworkCapabilties.
- * obj = NetworkCapabilities
- * @hide
- */
- public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 2;
-
- /**
- * Sent by the NetworkAgent to ConnectivityService to pass the current
- * NetworkProperties.
- * obj = NetworkProperties
- * @hide
- */
- public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3;
-
- /**
- * Centralize the place where base network score, and network score scaling, will be
- * stored, so as we can consistently compare apple and oranges, or wifi, ethernet and LTE
- * @hide
- */
- public static final int WIFI_BASE_SCORE = 60;
-
- /**
- * Sent by the NetworkAgent to ConnectivityService to pass the current
- * network score.
- * arg1 = network score int
- * @hide
- */
- public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4;
-
- /**
- * Sent by the NetworkAgent to ConnectivityService to pass the current
- * list of underlying networks.
- * obj = array of Network objects
- * @hide
- */
- public static final int EVENT_UNDERLYING_NETWORKS_CHANGED = BASE + 5;
-
- /**
- * Sent by the NetworkAgent to ConnectivityService to pass the current value of the teardown
- * delay.
- * arg1 = teardown delay in milliseconds
- * @hide
- */
- public static final int EVENT_TEARDOWN_DELAY_CHANGED = BASE + 6;
-
- /**
- * The maximum value for the teardown delay, in milliseconds.
- * @hide
- */
- public static final int MAX_TEARDOWN_DELAY_MS = 5000;
-
- /**
- * Sent by ConnectivityService to the NetworkAgent to inform the agent of the
- * networks status - whether we could use the network or could not, due to
- * either a bad network configuration (no internet link) or captive portal.
- *
- * arg1 = either {@code VALID_NETWORK} or {@code INVALID_NETWORK}
- * obj = Bundle containing map from {@code REDIRECT_URL_KEY} to {@code String}
- * representing URL that Internet probe was redirect to, if it was redirected,
- * or mapping to {@code null} otherwise.
- * @hide
- */
- public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7;
-
- /**
- * Network validation suceeded.
- * Corresponds to {@link NetworkCapabilities.NET_CAPABILITY_VALIDATED}.
- */
- public static final int VALIDATION_STATUS_VALID = 1;
-
- /**
- * Network validation was attempted and failed. This may be received more than once as
- * subsequent validation attempts are made.
- */
- public static final int VALIDATION_STATUS_NOT_VALID = 2;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "VALIDATION_STATUS_" }, value = {
- VALIDATION_STATUS_VALID,
- VALIDATION_STATUS_NOT_VALID
- })
- public @interface ValidationStatus {}
-
- // TODO: remove.
- /** @hide */
- public static final int VALID_NETWORK = 1;
- /** @hide */
- public static final int INVALID_NETWORK = 2;
-
- /**
- * The key for the redirect URL in the Bundle argument of {@code CMD_REPORT_NETWORK_STATUS}.
- * @hide
- */
- public static final String REDIRECT_URL_KEY = "redirect URL";
-
- /**
- * Sent by the NetworkAgent to ConnectivityService to indicate this network was
- * explicitly selected. This should be sent before the NetworkInfo is marked
- * CONNECTED so it can be given special treatment at that time.
- *
- * obj = boolean indicating whether to use this network even if unvalidated
- * @hide
- */
- public static final int EVENT_SET_EXPLICITLY_SELECTED = BASE + 8;
-
- /**
- * Sent by ConnectivityService to the NetworkAgent to inform the agent of
- * whether the network should in the future be used even if not validated.
- * This decision is made by the user, but it is the network transport's
- * responsibility to remember it.
- *
- * arg1 = 1 if true, 0 if false
- * @hide
- */
- public static final int CMD_SAVE_ACCEPT_UNVALIDATED = BASE + 9;
-
- /**
- * Sent by ConnectivityService to the NetworkAgent to inform the agent to pull
- * the underlying network connection for updated bandwidth information.
- * @hide
- */
- public static final int CMD_REQUEST_BANDWIDTH_UPDATE = BASE + 10;
-
- /**
- * Sent by ConnectivityService to the NetworkAgent to request that the specified packet be sent
- * periodically on the given interval.
- *
- * arg1 = the hardware slot number of the keepalive to start
- * arg2 = interval in seconds
- * obj = KeepalivePacketData object describing the data to be sent
- *
- * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics.
- * @hide
- */
- public static final int CMD_START_SOCKET_KEEPALIVE = BASE + 11;
-
- /**
- * Requests that the specified keepalive packet be stopped.
- *
- * arg1 = hardware slot number of the keepalive to stop.
- *
- * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics.
- * @hide
- */
- public static final int CMD_STOP_SOCKET_KEEPALIVE = BASE + 12;
-
- /**
- * Sent by the NetworkAgent to ConnectivityService to provide status on a socket keepalive
- * request. This may either be the reply to a CMD_START_SOCKET_KEEPALIVE, or an asynchronous
- * error notification.
- *
- * This is also sent by KeepaliveTracker to the app's {@link SocketKeepalive},
- * so that the app's {@link SocketKeepalive.Callback} methods can be called.
- *
- * arg1 = hardware slot number of the keepalive
- * arg2 = error code
- * @hide
- */
- public static final int EVENT_SOCKET_KEEPALIVE = BASE + 13;
-
- /**
- * Sent by ConnectivityService to inform this network transport of signal strength thresholds
- * that when crossed should trigger a system wakeup and a NetworkCapabilities update.
- *
- * obj = int[] describing signal strength thresholds.
- * @hide
- */
- public static final int CMD_SET_SIGNAL_STRENGTH_THRESHOLDS = BASE + 14;
-
- /**
- * Sent by ConnectivityService to the NeworkAgent to inform the agent to avoid
- * automatically reconnecting to this network (e.g. via autojoin). Happens
- * when user selects "No" option on the "Stay connected?" dialog box.
- * @hide
- */
- public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15;
-
- /**
- * Sent by the KeepaliveTracker to NetworkAgent to add a packet filter.
- *
- * For TCP keepalive offloads, keepalive packets are sent by the firmware. However, because the
- * remote site will send ACK packets in response to the keepalive packets, the firmware also
- * needs to be configured to properly filter the ACKs to prevent the system from waking up.
- * This does not happen with UDP, so this message is TCP-specific.
- * arg1 = hardware slot number of the keepalive to filter for.
- * obj = the keepalive packet to send repeatedly.
- * @hide
- */
- public static final int CMD_ADD_KEEPALIVE_PACKET_FILTER = BASE + 16;
-
- /**
- * Sent by the KeepaliveTracker to NetworkAgent to remove a packet filter. See
- * {@link #CMD_ADD_KEEPALIVE_PACKET_FILTER}.
- * arg1 = hardware slot number of the keepalive packet filter to remove.
- * @hide
- */
- public static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER = BASE + 17;
-
- /**
- * Sent by ConnectivityService to the NetworkAgent to complete the bidirectional connection.
- * obj = INetworkAgentRegistry
- */
- private static final int EVENT_AGENT_CONNECTED = BASE + 18;
-
- /**
- * Sent by ConnectivityService to the NetworkAgent to inform the agent that it was disconnected.
- */
- private static final int EVENT_AGENT_DISCONNECTED = BASE + 19;
-
- /**
- * Sent by QosCallbackTracker to {@link NetworkAgent} to register a new filter with
- * callback.
- *
- * arg1 = QoS agent callback ID
- * obj = {@link QosFilter}
- * @hide
- */
- public static final int CMD_REGISTER_QOS_CALLBACK = BASE + 20;
-
- /**
- * Sent by QosCallbackTracker to {@link NetworkAgent} to unregister a callback.
- *
- * arg1 = QoS agent callback ID
- * @hide
- */
- public static final int CMD_UNREGISTER_QOS_CALLBACK = BASE + 21;
-
- /**
- * Sent by ConnectivityService to {@link NetworkAgent} to inform the agent that its native
- * network was created and the Network object is now valid.
- *
- * @hide
- */
- public static final int CMD_NETWORK_CREATED = BASE + 22;
-
- /**
- * Sent by ConnectivityService to {@link NetworkAgent} to inform the agent that its native
- * network was destroyed.
- *
- * @hide
- */
- public static final int CMD_NETWORK_DESTROYED = BASE + 23;
-
- /**
- * Sent by the NetworkAgent to ConnectivityService to set the linger duration for this network
- * agent.
- * arg1 = the linger duration, represents by {@link Duration}.
- *
- * @hide
- */
- public static final int EVENT_LINGER_DURATION_CHANGED = BASE + 24;
-
- private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
- final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacySubType,
- config.legacyTypeName, config.legacySubTypeName);
- ni.setIsAvailable(true);
- ni.setDetailedState(NetworkInfo.DetailedState.CONNECTING, null /* reason */,
- config.getLegacyExtraInfo());
- return ni;
- }
-
- // Temporary backward compatibility constructor
- public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag,
- @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score,
- @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider) {
- this(context, looper, logTag, nc, lp,
- new NetworkScore.Builder().setLegacyInt(score).build(), config, provider);
- }
-
- /**
- * Create a new network agent.
- * @param context a {@link Context} to get system services from.
- * @param looper the {@link Looper} on which to invoke the callbacks.
- * @param logTag the tag for logs
- * @param nc the initial {@link NetworkCapabilities} of this network. Update with
- * sendNetworkCapabilities.
- * @param lp the initial {@link LinkProperties} of this network. Update with sendLinkProperties.
- * @param score the initial score of this network. Update with sendNetworkScore.
- * @param config an immutable {@link NetworkAgentConfig} for this agent.
- * @param provider the {@link NetworkProvider} managing this agent.
- */
- public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag,
- @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp,
- @NonNull NetworkScore score, @NonNull NetworkAgentConfig config,
- @Nullable NetworkProvider provider) {
- this(looper, context, logTag, nc, lp, score, config,
- provider == null ? NetworkProvider.ID_NONE : provider.getProviderId(),
- getLegacyNetworkInfo(config));
- }
-
- private static class InitialConfiguration {
- public final Context context;
- public final NetworkCapabilities capabilities;
- public final LinkProperties properties;
- public final NetworkScore score;
- public final NetworkAgentConfig config;
- public final NetworkInfo info;
- InitialConfiguration(@NonNull Context context, @NonNull NetworkCapabilities capabilities,
- @NonNull LinkProperties properties, @NonNull NetworkScore score,
- @NonNull NetworkAgentConfig config, @NonNull NetworkInfo info) {
- this.context = context;
- this.capabilities = capabilities;
- this.properties = properties;
- this.score = score;
- this.config = config;
- this.info = info;
- }
- }
- private volatile InitialConfiguration mInitialConfiguration;
-
- private NetworkAgent(@NonNull Looper looper, @NonNull Context context, @NonNull String logTag,
- @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp,
- @NonNull NetworkScore score, @NonNull NetworkAgentConfig config, int providerId,
- @NonNull NetworkInfo ni) {
- mHandler = new NetworkAgentHandler(looper);
- LOG_TAG = logTag;
- mNetworkInfo = new NetworkInfo(ni);
- this.providerId = providerId;
- if (ni == null || nc == null || lp == null) {
- throw new IllegalArgumentException();
- }
-
- mInitialConfiguration = new InitialConfiguration(context,
- new NetworkCapabilities(nc, NetworkCapabilities.REDACT_NONE),
- new LinkProperties(lp), score, config, ni);
- }
-
- private class NetworkAgentHandler extends Handler {
- NetworkAgentHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case EVENT_AGENT_CONNECTED: {
- if (mRegistry != null) {
- log("Received new connection while already connected!");
- } else {
- if (VDBG) log("NetworkAgent fully connected");
- synchronized (mPreConnectedQueue) {
- final INetworkAgentRegistry registry = (INetworkAgentRegistry) msg.obj;
- mRegistry = registry;
- for (RegistryAction a : mPreConnectedQueue) {
- try {
- a.execute(registry);
- } catch (RemoteException e) {
- Log.wtf(LOG_TAG, "Communication error with registry", e);
- // Fall through
- }
- }
- mPreConnectedQueue.clear();
- }
- }
- break;
- }
- case EVENT_AGENT_DISCONNECTED: {
- if (DBG) log("NetworkAgent channel lost");
- // let the client know CS is done with us.
- onNetworkUnwanted();
- synchronized (mPreConnectedQueue) {
- mRegistry = null;
- }
- break;
- }
- case CMD_SUSPECT_BAD: {
- log("Unhandled Message " + msg);
- break;
- }
- case CMD_REQUEST_BANDWIDTH_UPDATE: {
- long currentTimeMs = System.currentTimeMillis();
- if (VDBG) {
- log("CMD_REQUEST_BANDWIDTH_UPDATE request received.");
- }
- if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) {
- mBandwidthUpdateScheduled = false;
- if (!mBandwidthUpdatePending.getAndSet(true)) {
- onBandwidthUpdateRequested();
- }
- } else {
- // deliver the request at a later time rather than discard it completely.
- if (!mBandwidthUpdateScheduled) {
- long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS
- - currentTimeMs + 1;
- mBandwidthUpdateScheduled = sendEmptyMessageDelayed(
- CMD_REQUEST_BANDWIDTH_UPDATE, waitTime);
- }
- }
- break;
- }
- case CMD_REPORT_NETWORK_STATUS: {
- String redirectUrl = ((Bundle) msg.obj).getString(REDIRECT_URL_KEY);
- if (VDBG) {
- log("CMD_REPORT_NETWORK_STATUS("
- + (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ")
- + redirectUrl);
- }
- Uri uri = null;
- try {
- if (null != redirectUrl) {
- uri = Uri.parse(redirectUrl);
- }
- } catch (Exception e) {
- Log.wtf(LOG_TAG, "Surprising URI : " + redirectUrl, e);
- }
- onValidationStatus(msg.arg1 /* status */, uri);
- break;
- }
- case CMD_SAVE_ACCEPT_UNVALIDATED: {
- onSaveAcceptUnvalidated(msg.arg1 != 0);
- break;
- }
- case CMD_START_SOCKET_KEEPALIVE: {
- onStartSocketKeepalive(msg.arg1 /* slot */,
- Duration.ofSeconds(msg.arg2) /* interval */,
- (KeepalivePacketData) msg.obj /* packet */);
- break;
- }
- case CMD_STOP_SOCKET_KEEPALIVE: {
- onStopSocketKeepalive(msg.arg1 /* slot */);
- break;
- }
-
- case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: {
- onSignalStrengthThresholdsUpdated((int[]) msg.obj);
- break;
- }
- case CMD_PREVENT_AUTOMATIC_RECONNECT: {
- onAutomaticReconnectDisabled();
- break;
- }
- case CMD_ADD_KEEPALIVE_PACKET_FILTER: {
- onAddKeepalivePacketFilter(msg.arg1 /* slot */,
- (KeepalivePacketData) msg.obj /* packet */);
- break;
- }
- case CMD_REMOVE_KEEPALIVE_PACKET_FILTER: {
- onRemoveKeepalivePacketFilter(msg.arg1 /* slot */);
- break;
- }
- case CMD_REGISTER_QOS_CALLBACK: {
- onQosCallbackRegistered(
- msg.arg1 /* QoS callback id */,
- (QosFilter) msg.obj /* QoS filter */);
- break;
- }
- case CMD_UNREGISTER_QOS_CALLBACK: {
- onQosCallbackUnregistered(
- msg.arg1 /* QoS callback id */);
- break;
- }
- case CMD_NETWORK_CREATED: {
- onNetworkCreated();
- break;
- }
- case CMD_NETWORK_DESTROYED: {
- onNetworkDestroyed();
- break;
- }
- }
- }
- }
-
- /**
- * Register this network agent with ConnectivityService.
- *
- * This method can only be called once per network agent.
- *
- * @return the Network associated with this network agent (which can also be obtained later
- * by calling getNetwork() on this agent).
- * @throws IllegalStateException thrown by the system server if this network agent is
- * already registered.
- */
- @NonNull
- public Network register() {
- if (VDBG) log("Registering NetworkAgent");
- synchronized (mRegisterLock) {
- if (mNetwork != null) {
- throw new IllegalStateException("Agent already registered");
- }
- final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context
- .getSystemService(Context.CONNECTIVITY_SERVICE);
- mNetwork = cm.registerNetworkAgent(new NetworkAgentBinder(mHandler),
- new NetworkInfo(mInitialConfiguration.info),
- mInitialConfiguration.properties, mInitialConfiguration.capabilities,
- mInitialConfiguration.score, mInitialConfiguration.config, providerId);
- mInitialConfiguration = null; // All this memory can now be GC'd
- }
- return mNetwork;
- }
-
- private static class NetworkAgentBinder extends INetworkAgent.Stub {
- private static final String LOG_TAG = NetworkAgentBinder.class.getSimpleName();
-
- private final Handler mHandler;
-
- private NetworkAgentBinder(Handler handler) {
- mHandler = handler;
- }
-
- @Override
- public void onRegistered(@NonNull INetworkAgentRegistry registry) {
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_AGENT_CONNECTED, registry));
- }
-
- @Override
- public void onDisconnected() {
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_AGENT_DISCONNECTED));
- }
-
- @Override
- public void onBandwidthUpdateRequested() {
- mHandler.sendMessage(mHandler.obtainMessage(CMD_REQUEST_BANDWIDTH_UPDATE));
- }
-
- @Override
- public void onValidationStatusChanged(
- int validationStatus, @Nullable String captivePortalUrl) {
- // TODO: consider using a parcelable as argument when the interface is structured
- Bundle redirectUrlBundle = new Bundle();
- redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, captivePortalUrl);
- mHandler.sendMessage(mHandler.obtainMessage(CMD_REPORT_NETWORK_STATUS,
- validationStatus, 0, redirectUrlBundle));
- }
-
- @Override
- public void onSaveAcceptUnvalidated(boolean acceptUnvalidated) {
- mHandler.sendMessage(mHandler.obtainMessage(CMD_SAVE_ACCEPT_UNVALIDATED,
- acceptUnvalidated ? 1 : 0, 0));
- }
-
- @Override
- public void onStartNattSocketKeepalive(int slot, int intervalDurationMs,
- @NonNull NattKeepalivePacketData packetData) {
- mHandler.sendMessage(mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE,
- slot, intervalDurationMs, packetData));
- }
-
- @Override
- public void onStartTcpSocketKeepalive(int slot, int intervalDurationMs,
- @NonNull TcpKeepalivePacketData packetData) {
- mHandler.sendMessage(mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE,
- slot, intervalDurationMs, packetData));
- }
-
- @Override
- public void onStopSocketKeepalive(int slot) {
- mHandler.sendMessage(mHandler.obtainMessage(CMD_STOP_SOCKET_KEEPALIVE, slot, 0));
- }
-
- @Override
- public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) {
- mHandler.sendMessage(mHandler.obtainMessage(
- CMD_SET_SIGNAL_STRENGTH_THRESHOLDS, thresholds));
- }
-
- @Override
- public void onPreventAutomaticReconnect() {
- mHandler.sendMessage(mHandler.obtainMessage(CMD_PREVENT_AUTOMATIC_RECONNECT));
- }
-
- @Override
- public void onAddNattKeepalivePacketFilter(int slot,
- @NonNull NattKeepalivePacketData packetData) {
- mHandler.sendMessage(mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER,
- slot, 0, packetData));
- }
-
- @Override
- public void onAddTcpKeepalivePacketFilter(int slot,
- @NonNull TcpKeepalivePacketData packetData) {
- mHandler.sendMessage(mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER,
- slot, 0, packetData));
- }
-
- @Override
- public void onRemoveKeepalivePacketFilter(int slot) {
- mHandler.sendMessage(mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER,
- slot, 0));
- }
-
- @Override
- public void onQosFilterCallbackRegistered(final int qosCallbackId,
- final QosFilterParcelable qosFilterParcelable) {
- if (qosFilterParcelable.getQosFilter() != null) {
- mHandler.sendMessage(
- mHandler.obtainMessage(CMD_REGISTER_QOS_CALLBACK, qosCallbackId, 0,
- qosFilterParcelable.getQosFilter()));
- return;
- }
-
- Log.wtf(LOG_TAG, "onQosFilterCallbackRegistered: qos filter is null.");
- }
-
- @Override
- public void onQosCallbackUnregistered(final int qosCallbackId) {
- mHandler.sendMessage(mHandler.obtainMessage(
- CMD_UNREGISTER_QOS_CALLBACK, qosCallbackId, 0, null));
- }
-
- @Override
- public void onNetworkCreated() {
- mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_CREATED));
- }
-
- @Override
- public void onNetworkDestroyed() {
- mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_DESTROYED));
- }
- }
-
- /**
- * Register this network agent with a testing harness.
- *
- * The returned Messenger sends messages to the Handler. This allows a test to send
- * this object {@code CMD_*} messages as if they came from ConnectivityService, which
- * is useful for testing the behavior.
- *
- * @hide
- */
- public INetworkAgent registerForTest(final Network network) {
- log("Registering NetworkAgent for test");
- synchronized (mRegisterLock) {
- mNetwork = network;
- mInitialConfiguration = null;
- }
- return new NetworkAgentBinder(mHandler);
- }
-
- /**
- * Waits for the handler to be idle.
- * This is useful for testing, and has smaller scope than an accessor to mHandler.
- * TODO : move the implementation in common library with the tests
- * @hide
- */
- @VisibleForTesting
- public boolean waitForIdle(final long timeoutMs) {
- final ConditionVariable cv = new ConditionVariable(false);
- mHandler.post(cv::open);
- return cv.block(timeoutMs);
- }
-
- /**
- * @return The Network associated with this agent, or null if it's not registered yet.
- */
- @Nullable
- public Network getNetwork() {
- return mNetwork;
- }
-
- private void queueOrSendMessage(@NonNull RegistryAction action) {
- synchronized (mPreConnectedQueue) {
- if (mRegistry != null) {
- try {
- action.execute(mRegistry);
- } catch (RemoteException e) {
- Log.wtf(LOG_TAG, "Error executing registry action", e);
- // Fall through: the channel is asynchronous and does not report errors back
- }
- } else {
- mPreConnectedQueue.add(action);
- }
- }
- }
-
- /**
- * Must be called by the agent when the network's {@link LinkProperties} change.
- * @param linkProperties the new LinkProperties.
- */
- public final void sendLinkProperties(@NonNull LinkProperties linkProperties) {
- Objects.requireNonNull(linkProperties);
- final LinkProperties lp = new LinkProperties(linkProperties);
- queueOrSendMessage(reg -> reg.sendLinkProperties(lp));
- }
-
- /**
- * Must be called by the agent when the network's underlying networks change.
- *
- * <p>{@code networks} is one of the following:
- * <ul>
- * <li><strong>a non-empty array</strong>: an array of one or more {@link Network}s, in
- * decreasing preference order. For example, if this VPN uses both wifi and mobile (cellular)
- * networks to carry app traffic, but prefers or uses wifi more than mobile, wifi should appear
- * first in the array.</li>
- * <li><strong>an empty array</strong>: a zero-element array, meaning that the VPN has no
- * underlying network connection, and thus, app traffic will not be sent or received.</li>
- * <li><strong>null</strong>: (default) signifies that the VPN uses whatever is the system's
- * default network. I.e., it doesn't use the {@code bindSocket} or {@code bindDatagramSocket}
- * APIs mentioned above to send traffic over specific channels.</li>
- * </ul>
- *
- * @param underlyingNetworks the new list of underlying networks.
- * @see {@link VpnService.Builder#setUnderlyingNetworks(Network[])}
- */
- public final void setUnderlyingNetworks(
- @SuppressLint("NullableCollection") @Nullable List<Network> underlyingNetworks) {
- final ArrayList<Network> underlyingArray = (underlyingNetworks != null)
- ? new ArrayList<>(underlyingNetworks) : null;
- queueOrSendMessage(reg -> reg.sendUnderlyingNetworks(underlyingArray));
- }
-
- /**
- * Inform ConnectivityService that this agent has now connected.
- * Call {@link #unregister} to disconnect.
- */
- public void markConnected() {
- mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null /* reason */,
- mNetworkInfo.getExtraInfo());
- queueOrSendNetworkInfo(mNetworkInfo);
- }
-
- /**
- * Unregister this network agent.
- *
- * This signals the network has disconnected and ends its lifecycle. After this is called,
- * the network is torn down and this agent can no longer be used.
- */
- public void unregister() {
- // When unregistering an agent nobody should use the extrainfo (or reason) any more.
- mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null /* reason */,
- null /* extraInfo */);
- queueOrSendNetworkInfo(mNetworkInfo);
- }
-
- /**
- * Sets the value of the teardown delay.
- *
- * The teardown delay is the time between when the network disconnects and when the native
- * network corresponding to this {@code NetworkAgent} is destroyed. By default, the native
- * network is destroyed immediately. If {@code teardownDelayMs} is non-zero, then when this
- * network disconnects, the system will instead immediately mark the network as restricted
- * and unavailable to unprivileged apps, but will defer destroying the native network until the
- * teardown delay timer expires.
- *
- * The interfaces in use by this network will remain in use until the native network is
- * destroyed and cannot be reused until {@link #onNetworkDestroyed()} is called.
- *
- * This method may be called at any time while the network is connected. It has no effect if
- * the network is already disconnected and the teardown delay timer is running.
- *
- * @param teardownDelayMillis the teardown delay to set, or 0 to disable teardown delay.
- */
- public void setTeardownDelayMillis(
- @IntRange(from = 0, to = MAX_TEARDOWN_DELAY_MS) int teardownDelayMillis) {
- queueOrSendMessage(reg -> reg.sendTeardownDelayMs(teardownDelayMillis));
- }
-
- /**
- * Change the legacy subtype of this network agent.
- *
- * This is only for backward compatibility and should not be used by non-legacy network agents,
- * or agents that did not use to set a subtype. As such, only TYPE_MOBILE type agents can use
- * this and others will be thrown an exception if they try.
- *
- * @deprecated this is for backward compatibility only.
- * @param legacySubtype the legacy subtype.
- * @hide
- */
- @Deprecated
- @SystemApi
- public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) {
- mNetworkInfo.setSubtype(legacySubtype, legacySubtypeName);
- queueOrSendNetworkInfo(mNetworkInfo);
- }
-
- /**
- * Set the ExtraInfo of this network agent.
- *
- * This sets the ExtraInfo field inside the NetworkInfo returned by legacy public API and the
- * broadcasts about the corresponding Network.
- * This is only for backward compatibility and should not be used by non-legacy network agents,
- * who will be thrown an exception if they try. The extra info should only be :
- * <ul>
- * <li>For cellular agents, the APN name.</li>
- * <li>For ethernet agents, the interface name.</li>
- * </ul>
- *
- * @deprecated this is for backward compatibility only.
- * @param extraInfo the ExtraInfo.
- * @hide
- */
- @Deprecated
- public void setLegacyExtraInfo(@Nullable final String extraInfo) {
- mNetworkInfo.setExtraInfo(extraInfo);
- queueOrSendNetworkInfo(mNetworkInfo);
- }
-
- /**
- * Must be called by the agent when it has a new NetworkInfo object.
- * @hide TODO: expose something better.
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public final void sendNetworkInfo(NetworkInfo networkInfo) {
- queueOrSendNetworkInfo(new NetworkInfo(networkInfo));
- }
-
- private void queueOrSendNetworkInfo(NetworkInfo networkInfo) {
- queueOrSendMessage(reg -> reg.sendNetworkInfo(networkInfo));
- }
-
- /**
- * Must be called by the agent when the network's {@link NetworkCapabilities} change.
- * @param networkCapabilities the new NetworkCapabilities.
- */
- public final void sendNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
- Objects.requireNonNull(networkCapabilities);
- mBandwidthUpdatePending.set(false);
- mLastBwRefreshTime = System.currentTimeMillis();
- final NetworkCapabilities nc =
- new NetworkCapabilities(networkCapabilities, NetworkCapabilities.REDACT_NONE);
- queueOrSendMessage(reg -> reg.sendNetworkCapabilities(nc));
- }
-
- /**
- * Must be called by the agent to update the score of this network.
- *
- * @param score the new score.
- */
- public final void sendNetworkScore(@NonNull NetworkScore score) {
- Objects.requireNonNull(score);
- queueOrSendMessage(reg -> reg.sendScore(score));
- }
-
- /**
- * Must be called by the agent to update the score of this network.
- *
- * @param score the new score, between 0 and 99.
- * deprecated use sendNetworkScore(NetworkScore) TODO : remove in S.
- */
- public final void sendNetworkScore(@IntRange(from = 0, to = 99) int score) {
- sendNetworkScore(new NetworkScore.Builder().setLegacyInt(score).build());
- }
-
- /**
- * Must be called by the agent to indicate this network was manually selected by the user.
- * This should be called before the NetworkInfo is marked CONNECTED so that this
- * Network can be given special treatment at that time. If {@code acceptUnvalidated} is
- * {@code true}, then the system will switch to this network. If it is {@code false} and the
- * network cannot be validated, the system will ask the user whether to switch to this network.
- * If the user confirms and selects "don't ask again", then the system will call
- * {@link #saveAcceptUnvalidated} to persist the user's choice. Thus, if the transport ever
- * calls this method with {@code acceptUnvalidated} set to {@code false}, it must also implement
- * {@link #saveAcceptUnvalidated} to respect the user's choice.
- * @hide should move to NetworkAgentConfig.
- */
- public void explicitlySelected(boolean acceptUnvalidated) {
- explicitlySelected(true /* explicitlySelected */, acceptUnvalidated);
- }
-
- /**
- * Must be called by the agent to indicate whether the network was manually selected by the
- * user. This should be called before the network becomes connected, so it can be given
- * special treatment when it does.
- *
- * If {@code explicitlySelected} is {@code true}, and {@code acceptUnvalidated} is {@code true},
- * then the system will switch to this network. If {@code explicitlySelected} is {@code true}
- * and {@code acceptUnvalidated} is {@code false}, and the network cannot be validated, the
- * system will ask the user whether to switch to this network. If the user confirms and selects
- * "don't ask again", then the system will call {@link #saveAcceptUnvalidated} to persist the
- * user's choice. Thus, if the transport ever calls this method with {@code explicitlySelected}
- * set to {@code true} and {@code acceptUnvalidated} set to {@code false}, it must also
- * implement {@link #saveAcceptUnvalidated} to respect the user's choice.
- *
- * If {@code explicitlySelected} is {@code false} and {@code acceptUnvalidated} is
- * {@code true}, the system will interpret this as the user having accepted partial connectivity
- * on this network. Thus, the system will switch to the network and consider it validated even
- * if it only provides partial connectivity, but the network is not otherwise treated specially.
- * @hide should move to NetworkAgentConfig.
- */
- public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) {
- queueOrSendMessage(reg -> reg.sendExplicitlySelected(
- explicitlySelected, acceptUnvalidated));
- }
-
- /**
- * Called when ConnectivityService has indicated they no longer want this network.
- * The parent factory should (previously) have received indication of the change
- * as well, either canceling NetworkRequests or altering their score such that this
- * network won't be immediately requested again.
- */
- public void onNetworkUnwanted() {
- unwanted();
- }
- /** @hide TODO delete once subclasses have moved to onNetworkUnwanted. */
- protected void unwanted() {
- }
-
- /**
- * Called when ConnectivityService request a bandwidth update. The parent factory
- * shall try to overwrite this method and produce a bandwidth update if capable.
- * @hide
- */
- @SystemApi
- public void onBandwidthUpdateRequested() {
- pollLceData();
- }
- /** @hide TODO delete once subclasses have moved to onBandwidthUpdateRequested. */
- protected void pollLceData() {
- }
-
- /**
- * Called when the system determines the usefulness of this network.
- *
- * The system attempts to validate Internet connectivity on networks that provide the
- * {@link NetworkCapabilities#NET_CAPABILITY_INTERNET} capability.
- *
- * Currently there are two possible values:
- * {@code VALIDATION_STATUS_VALID} if Internet connectivity was validated,
- * {@code VALIDATION_STATUS_NOT_VALID} if Internet connectivity was not validated.
- *
- * This is guaranteed to be called again when the network status changes, but the system
- * may also call this multiple times even if the status does not change.
- *
- * @param status one of {@code VALIDATION_STATUS_VALID} or {@code VALIDATION_STATUS_NOT_VALID}.
- * @param redirectUri If Internet connectivity is being redirected (e.g., on a captive portal),
- * this is the destination the probes are being redirected to, otherwise {@code null}.
- */
- public void onValidationStatus(@ValidationStatus int status, @Nullable Uri redirectUri) {
- networkStatus(status, null == redirectUri ? "" : redirectUri.toString());
- }
- /** @hide TODO delete once subclasses have moved to onValidationStatus */
- protected void networkStatus(int status, String redirectUrl) {
- }
-
-
- /**
- * Called when the user asks to remember the choice to use this network even if unvalidated.
- * The transport is responsible for remembering the choice, and the next time the user connects
- * to the network, should explicitlySelected with {@code acceptUnvalidated} set to {@code true}.
- * This method will only be called if {@link #explicitlySelected} was called with
- * {@code acceptUnvalidated} set to {@code false}.
- * @param accept whether the user wants to use the network even if unvalidated.
- */
- public void onSaveAcceptUnvalidated(boolean accept) {
- saveAcceptUnvalidated(accept);
- }
- /** @hide TODO delete once subclasses have moved to onSaveAcceptUnvalidated */
- protected void saveAcceptUnvalidated(boolean accept) {
- }
-
- /**
- * Called when ConnectivityService has successfully created this NetworkAgent's native network.
- */
- public void onNetworkCreated() {}
-
-
- /**
- * Called when ConnectivityService has successfully destroy this NetworkAgent's native network.
- */
- public void onNetworkDestroyed() {}
-
- /**
- * Requests that the network hardware send the specified packet at the specified interval.
- *
- * @param slot the hardware slot on which to start the keepalive.
- * @param interval the interval between packets, between 10 and 3600. Note that this API
- * does not support sub-second precision and will round off the request.
- * @param packet the packet to send.
- */
- // seconds is from SocketKeepalive.MIN_INTERVAL_SEC to MAX_INTERVAL_SEC, but these should
- // not be exposed as constants because they may change in the future (API guideline 4.8)
- // and should have getters if exposed at all. Getters can't be used in the annotation,
- // so the values unfortunately need to be copied.
- public void onStartSocketKeepalive(int slot, @NonNull Duration interval,
- @NonNull KeepalivePacketData packet) {
- final long intervalSeconds = interval.getSeconds();
- if (intervalSeconds < SocketKeepalive.MIN_INTERVAL_SEC
- || intervalSeconds > SocketKeepalive.MAX_INTERVAL_SEC) {
- throw new IllegalArgumentException("Interval needs to be comprised between "
- + SocketKeepalive.MIN_INTERVAL_SEC + " and " + SocketKeepalive.MAX_INTERVAL_SEC
- + " but was " + intervalSeconds);
- }
- final Message msg = mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, slot,
- (int) intervalSeconds, packet);
- startSocketKeepalive(msg);
- msg.recycle();
- }
- /** @hide TODO delete once subclasses have moved to onStartSocketKeepalive */
- protected void startSocketKeepalive(Message msg) {
- onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED);
- }
-
- /**
- * Requests that the network hardware stop a previously-started keepalive.
- *
- * @param slot the hardware slot on which to stop the keepalive.
- */
- public void onStopSocketKeepalive(int slot) {
- Message msg = mHandler.obtainMessage(CMD_STOP_SOCKET_KEEPALIVE, slot, 0, null);
- stopSocketKeepalive(msg);
- msg.recycle();
- }
- /** @hide TODO delete once subclasses have moved to onStopSocketKeepalive */
- protected void stopSocketKeepalive(Message msg) {
- onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED);
- }
-
- /**
- * Must be called by the agent when a socket keepalive event occurs.
- *
- * @param slot the hardware slot on which the event occurred.
- * @param event the event that occurred, as one of the SocketKeepalive.ERROR_*
- * or SocketKeepalive.SUCCESS constants.
- */
- public final void sendSocketKeepaliveEvent(int slot,
- @SocketKeepalive.KeepaliveEvent int event) {
- queueOrSendMessage(reg -> reg.sendSocketKeepaliveEvent(slot, event));
- }
- /** @hide TODO delete once callers have moved to sendSocketKeepaliveEvent */
- public void onSocketKeepaliveEvent(int slot, int reason) {
- sendSocketKeepaliveEvent(slot, reason);
- }
-
- /**
- * Called by ConnectivityService to add specific packet filter to network hardware to block
- * replies (e.g., TCP ACKs) matching the sent keepalive packets. Implementations that support
- * this feature must override this method.
- *
- * @param slot the hardware slot on which the keepalive should be sent.
- * @param packet the packet that is being sent.
- */
- public void onAddKeepalivePacketFilter(int slot, @NonNull KeepalivePacketData packet) {
- Message msg = mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0, packet);
- addKeepalivePacketFilter(msg);
- msg.recycle();
- }
- /** @hide TODO delete once subclasses have moved to onAddKeepalivePacketFilter */
- protected void addKeepalivePacketFilter(Message msg) {
- }
-
- /**
- * Called by ConnectivityService to remove a packet filter installed with
- * {@link #addKeepalivePacketFilter(Message)}. Implementations that support this feature
- * must override this method.
- *
- * @param slot the hardware slot on which the keepalive is being sent.
- */
- public void onRemoveKeepalivePacketFilter(int slot) {
- Message msg = mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, slot, 0, null);
- removeKeepalivePacketFilter(msg);
- msg.recycle();
- }
- /** @hide TODO delete once subclasses have moved to onRemoveKeepalivePacketFilter */
- protected void removeKeepalivePacketFilter(Message msg) {
- }
-
- /**
- * Called by ConnectivityService to inform this network agent of signal strength thresholds
- * that when crossed should trigger a system wakeup and a NetworkCapabilities update.
- *
- * When the system updates the list of thresholds that should wake up the CPU for a
- * given agent it will call this method on the agent. The agent that implement this
- * should implement it in hardware so as to ensure the CPU will be woken up on breach.
- * Agents are expected to react to a breach by sending an updated NetworkCapabilities
- * object with the appropriate signal strength to sendNetworkCapabilities.
- *
- * The specific units are bearer-dependent. See details on the units and requests in
- * {@link NetworkCapabilities.Builder#setSignalStrength}.
- *
- * @param thresholds the array of thresholds that should trigger wakeups.
- */
- public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) {
- setSignalStrengthThresholds(thresholds);
- }
- /** @hide TODO delete once subclasses have moved to onSetSignalStrengthThresholds */
- protected void setSignalStrengthThresholds(int[] thresholds) {
- }
-
- /**
- * Called when the user asks to not stay connected to this network because it was found to not
- * provide Internet access. Usually followed by call to {@code unwanted}. The transport is
- * responsible for making sure the device does not automatically reconnect to the same network
- * after the {@code unwanted} call.
- */
- public void onAutomaticReconnectDisabled() {
- preventAutomaticReconnect();
- }
- /** @hide TODO delete once subclasses have moved to onAutomaticReconnectDisabled */
- protected void preventAutomaticReconnect() {
- }
-
- /**
- * Called when a qos callback is registered with a filter.
- * @param qosCallbackId the id for the callback registered
- * @param filter the filter being registered
- */
- public void onQosCallbackRegistered(final int qosCallbackId, final @NonNull QosFilter filter) {
- }
-
- /**
- * Called when a qos callback is registered with a filter.
- * <p/>
- * Any QoS events that are sent with the same callback id after this method is called
- * are a no-op.
- *
- * @param qosCallbackId the id for the callback being unregistered
- */
- public void onQosCallbackUnregistered(final int qosCallbackId) {
- }
-
-
- /**
- * Sends the attributes of Qos Session back to the Application
- *
- * @param qosCallbackId the callback id that the session belongs to
- * @param sessionId the unique session id across all Qos Sessions
- * @param attributes the attributes of the Qos Session
- */
- public final void sendQosSessionAvailable(final int qosCallbackId, final int sessionId,
- @NonNull final QosSessionAttributes attributes) {
- Objects.requireNonNull(attributes, "The attributes must be non-null");
- if (attributes instanceof EpsBearerQosSessionAttributes) {
- queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId,
- new QosSession(sessionId, QosSession.TYPE_EPS_BEARER),
- (EpsBearerQosSessionAttributes)attributes));
- } else if (attributes instanceof NrQosSessionAttributes) {
- queueOrSendMessage(ra -> ra.sendNrQosSessionAvailable(qosCallbackId,
- new QosSession(sessionId, QosSession.TYPE_NR_BEARER),
- (NrQosSessionAttributes)attributes));
- }
- }
-
- /**
- * Sends event that the Qos Session was lost.
- *
- * @param qosCallbackId the callback id that the session belongs to
- * @param sessionId the unique session id across all Qos Sessions
- * @param qosSessionType the session type {@code QosSesson#QosSessionType}
- */
- public final void sendQosSessionLost(final int qosCallbackId,
- final int sessionId, final int qosSessionType) {
- queueOrSendMessage(ra -> ra.sendQosSessionLost(qosCallbackId,
- new QosSession(sessionId, qosSessionType)));
- }
-
- /**
- * Sends the exception type back to the application.
- *
- * The NetworkAgent should not send anymore messages with this id.
- *
- * @param qosCallbackId the callback id this exception belongs to
- * @param exceptionType the type of exception
- */
- public final void sendQosCallbackError(final int qosCallbackId,
- @QosCallbackException.ExceptionType final int exceptionType) {
- queueOrSendMessage(ra -> ra.sendQosCallbackError(qosCallbackId, exceptionType));
- }
-
- /**
- * Set the linger duration for this network agent.
- * @param duration the delay between the moment the network becomes unneeded and the
- * moment the network is disconnected or moved into the background.
- * Note that If this duration has greater than millisecond precision, then
- * the internal implementation will drop any excess precision.
- */
- public void setLingerDuration(@NonNull final Duration duration) {
- Objects.requireNonNull(duration);
- final long durationMs = duration.toMillis();
- if (durationMs < MIN_LINGER_TIMER_MS || durationMs > Integer.MAX_VALUE) {
- throw new IllegalArgumentException("Duration must be within ["
- + MIN_LINGER_TIMER_MS + "," + Integer.MAX_VALUE + "]ms");
- }
- queueOrSendMessage(ra -> ra.sendLingerDuration((int) durationMs));
- }
-
- /** @hide */
- protected void log(final String s) {
- Log.d(LOG_TAG, "NetworkAgent: " + s);
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
deleted file mode 100644
index ad8396b..0000000
--- a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
+++ /dev/null
@@ -1,505 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/**
- * 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
- */
-@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;
-
- /**
- * Set if the network was manually/explicitly connected to by the user either from settings
- * or a 3rd party app. For example, turning on cell data is not explicit but tapping on a wifi
- * 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.
- * TODO : this is a bad name, because it sounds like the user just tapped on the network.
- * It's not necessarily the case ; auto-reconnection to WiFi has this true for example.
- * @hide
- */
- public boolean explicitlySelected;
-
- /**
- * @return whether this network was explicitly selected by the user.
- */
- public boolean isExplicitlySelected() {
- return explicitlySelected;
- }
-
- /**
- * @return whether this VPN connection can be bypassed by the apps.
- *
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public boolean isBypassableVpn() {
- return allowBypass;
- }
-
- /**
- * 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.
- *
- * TODO : rename this field to match its accessor
- * @hide
- */
- public boolean acceptUnvalidated;
-
- /**
- * @return whether the system should accept this network even if it doesn't validate.
- */
- public boolean isUnvalidatedConnectivityAcceptable() {
- return acceptUnvalidated;
- }
-
- /**
- * Whether the user explicitly set that this network should be validated even if presence of
- * only partial internet connectivity.
- *
- * TODO : rename this field to match its accessor
- * @hide
- */
- public boolean acceptPartialConnectivity;
-
- /**
- * @return whether the system should validate this network even if it only offers partial
- * Internet connectivity.
- */
- public boolean isPartialConnectivityAcceptable() {
- return acceptPartialConnectivity;
- }
-
- /**
- * Set to avoid surfacing the "Sign in to network" notification.
- * if carrier receivers/apps are registered to handle the carrier-specific provisioning
- * 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.
- * @hide
- */
- 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.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- @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.
- * @hide
- */
- public boolean isNat64DetectionEnabled() {
- return !skip464xlat;
- }
-
- /**
- * The legacy type of this network agent, or TYPE_NONE if unset.
- * @hide
- */
- public int legacyType = ConnectivityManager.TYPE_NONE;
-
- /**
- * @return the legacy type
- */
- @ConnectivityManager.LegacyNetworkType
- public int getLegacyType() {
- return legacyType;
- }
-
- /**
- * The legacy Sub type of this network agent, or TYPE_NONE if unset.
- * @hide
- */
- public int legacySubType = ConnectivityManager.TYPE_NONE;
-
- /**
- * 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.
- *
- * This is not parceled, because it would not make sense.
- *
- * @hide
- */
- public transient boolean hasShownBroken;
-
- /**
- * The name of the legacy network type. It's a free-form string used in logging.
- * @hide
- */
- @NonNull
- public String legacyTypeName = "";
-
- /**
- * @return the name of the legacy network type. It's a free-form string used in logging.
- */
- @NonNull
- public String getLegacyTypeName() {
- return legacyTypeName;
- }
-
- /**
- * The name of the legacy Sub network type. It's a free-form string.
- * @hide
- */
- @NonNull
- public String legacySubTypeName = "";
-
- /**
- * The legacy extra info of the agent. The extra info should only be :
- * <ul>
- * <li>For cellular agents, the APN name.</li>
- * <li>For ethernet agents, the interface name.</li>
- * </ul>
- * @hide
- */
- @NonNull
- private String mLegacyExtraInfo = "";
-
- /**
- * The legacy extra info of the agent.
- * @hide
- */
- @NonNull
- public String getLegacyExtraInfo() {
- return mLegacyExtraInfo;
- }
-
- /** @hide */
- public NetworkAgentConfig() {
- }
-
- /** @hide */
- public NetworkAgentConfig(@Nullable NetworkAgentConfig nac) {
- if (nac != null) {
- allowBypass = nac.allowBypass;
- explicitlySelected = nac.explicitlySelected;
- acceptUnvalidated = nac.acceptUnvalidated;
- acceptPartialConnectivity = nac.acceptPartialConnectivity;
- subscriberId = nac.subscriberId;
- provisioningNotificationDisabled = nac.provisioningNotificationDisabled;
- skip464xlat = nac.skip464xlat;
- legacyType = nac.legacyType;
- legacyTypeName = nac.legacyTypeName;
- legacySubType = nac.legacySubType;
- legacySubTypeName = nac.legacySubTypeName;
- mLegacyExtraInfo = nac.mLegacyExtraInfo;
- }
- }
-
- /**
- * Builder class to facilitate constructing {@link NetworkAgentConfig} objects.
- */
- public static final class Builder {
- private final NetworkAgentConfig mConfig = new NetworkAgentConfig();
-
- /**
- * Sets whether the network was explicitly selected by the user.
- *
- * @return this builder, to facilitate chaining.
- */
- @NonNull
- public Builder setExplicitlySelected(final boolean explicitlySelected) {
- mConfig.explicitlySelected = explicitlySelected;
- return this;
- }
-
- /**
- * Sets whether the system should validate this network even if it is found not to offer
- * Internet connectivity.
- *
- * @return this builder, to facilitate chaining.
- */
- @NonNull
- public Builder setUnvalidatedConnectivityAcceptable(
- final boolean unvalidatedConnectivityAcceptable) {
- mConfig.acceptUnvalidated = unvalidatedConnectivityAcceptable;
- return this;
- }
-
- /**
- * Sets whether the system should validate this network even if it is found to only offer
- * partial Internet connectivity.
- *
- * @return this builder, to facilitate chaining.
- */
- @NonNull
- public Builder setPartialConnectivityAcceptable(
- final boolean partialConnectivityAcceptable) {
- mConfig.acceptPartialConnectivity = partialConnectivityAcceptable;
- return this;
- }
-
- /**
- * Sets the subscriber ID for this network.
- *
- * @return this builder, to facilitate chaining.
- * @hide
- */
- @NonNull
- @SystemApi(client = MODULE_LIBRARIES)
- public Builder setSubscriberId(@Nullable String subscriberId) {
- mConfig.subscriberId = subscriberId;
- return this;
- }
-
- /**
- * Enables or 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. By default, NAT64 detection is enabled.
- *
- * @return this builder, to facilitate chaining.
- */
- @NonNull
- public Builder setNat64DetectionEnabled(boolean enabled) {
- mConfig.skip464xlat = !enabled;
- return this;
- }
-
- /**
- * Enables or disables the "Sign in to network" notification. Used if the network transport
- * will perform its own carrier-specific provisioning procedure. By default, the
- * notification is enabled.
- *
- * @return this builder, to facilitate chaining.
- */
- @NonNull
- public Builder setProvisioningNotificationEnabled(boolean enabled) {
- mConfig.provisioningNotificationDisabled = !enabled;
- return this;
- }
-
- /**
- * Sets the legacy type for this network.
- *
- * @param legacyType the type
- * @return this builder, to facilitate chaining.
- */
- @NonNull
- public Builder setLegacyType(int legacyType) {
- mConfig.legacyType = legacyType;
- return this;
- }
-
- /**
- * Sets the legacy sub-type for this network.
- *
- * @param legacySubType the type
- * @return this builder, to facilitate chaining.
- */
- @NonNull
- public Builder setLegacySubType(final int legacySubType) {
- mConfig.legacySubType = legacySubType;
- return this;
- }
-
- /**
- * Sets the name of the legacy type of the agent. It's a free-form string used in logging.
- * @param legacyTypeName the name
- * @return this builder, to facilitate chaining.
- */
- @NonNull
- public Builder setLegacyTypeName(@NonNull String legacyTypeName) {
- mConfig.legacyTypeName = legacyTypeName;
- return this;
- }
-
- /**
- * Sets the name of the legacy Sub-type of the agent. It's a free-form string.
- * @param legacySubTypeName the name
- * @return this builder, to facilitate chaining.
- */
- @NonNull
- public Builder setLegacySubTypeName(@NonNull String legacySubTypeName) {
- mConfig.legacySubTypeName = legacySubTypeName;
- return this;
- }
-
- /**
- * Sets the legacy extra info of the agent.
- * @param legacyExtraInfo the legacy extra info.
- * @return this builder, to facilitate chaining.
- */
- @NonNull
- public Builder setLegacyExtraInfo(@NonNull String legacyExtraInfo) {
- mConfig.mLegacyExtraInfo = legacyExtraInfo;
- return this;
- }
-
- /**
- * Sets whether the apps can bypass the VPN connection.
- *
- * @return this builder, to facilitate chaining.
- * @hide
- */
- @NonNull
- @SystemApi(client = MODULE_LIBRARIES)
- public Builder setBypassableVpn(boolean allowBypass) {
- mConfig.allowBypass = allowBypass;
- return this;
- }
-
- /**
- * Returns the constructed {@link NetworkAgentConfig} object.
- */
- @NonNull
- public NetworkAgentConfig build() {
- return mConfig;
- }
- }
-
- @Override
- public boolean equals(final Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- final NetworkAgentConfig that = (NetworkAgentConfig) o;
- return allowBypass == that.allowBypass
- && explicitlySelected == that.explicitlySelected
- && acceptUnvalidated == that.acceptUnvalidated
- && acceptPartialConnectivity == that.acceptPartialConnectivity
- && provisioningNotificationDisabled == that.provisioningNotificationDisabled
- && skip464xlat == that.skip464xlat
- && legacyType == that.legacyType
- && Objects.equals(subscriberId, that.subscriberId)
- && Objects.equals(legacyTypeName, that.legacyTypeName)
- && Objects.equals(mLegacyExtraInfo, that.mLegacyExtraInfo);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(allowBypass, explicitlySelected, acceptUnvalidated,
- acceptPartialConnectivity, provisioningNotificationDisabled, subscriberId,
- skip464xlat, legacyType, legacyTypeName, mLegacyExtraInfo);
- }
-
- @Override
- public String toString() {
- return "NetworkAgentConfig {"
- + " allowBypass = " + allowBypass
- + ", explicitlySelected = " + explicitlySelected
- + ", acceptUnvalidated = " + acceptUnvalidated
- + ", acceptPartialConnectivity = " + acceptPartialConnectivity
- + ", provisioningNotificationDisabled = " + provisioningNotificationDisabled
- + ", subscriberId = '" + subscriberId + '\''
- + ", skip464xlat = " + skip464xlat
- + ", legacyType = " + legacyType
- + ", hasShownBroken = " + hasShownBroken
- + ", legacyTypeName = '" + legacyTypeName + '\''
- + ", legacyExtraInfo = '" + mLegacyExtraInfo + '\''
- + "}";
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel out, int flags) {
- out.writeInt(allowBypass ? 1 : 0);
- out.writeInt(explicitlySelected ? 1 : 0);
- out.writeInt(acceptUnvalidated ? 1 : 0);
- out.writeInt(acceptPartialConnectivity ? 1 : 0);
- out.writeString(subscriberId);
- out.writeInt(provisioningNotificationDisabled ? 1 : 0);
- out.writeInt(skip464xlat ? 1 : 0);
- out.writeInt(legacyType);
- out.writeString(legacyTypeName);
- out.writeInt(legacySubType);
- out.writeString(legacySubTypeName);
- out.writeString(mLegacyExtraInfo);
- }
-
- public static final @NonNull Creator<NetworkAgentConfig> CREATOR =
- new Creator<NetworkAgentConfig>() {
- @Override
- public NetworkAgentConfig createFromParcel(Parcel in) {
- NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig();
- networkAgentConfig.allowBypass = in.readInt() != 0;
- networkAgentConfig.explicitlySelected = in.readInt() != 0;
- networkAgentConfig.acceptUnvalidated = in.readInt() != 0;
- networkAgentConfig.acceptPartialConnectivity = in.readInt() != 0;
- networkAgentConfig.subscriberId = in.readString();
- networkAgentConfig.provisioningNotificationDisabled = in.readInt() != 0;
- networkAgentConfig.skip464xlat = in.readInt() != 0;
- networkAgentConfig.legacyType = in.readInt();
- networkAgentConfig.legacyTypeName = in.readString();
- networkAgentConfig.legacySubType = in.readInt();
- networkAgentConfig.legacySubTypeName = in.readString();
- networkAgentConfig.mLegacyExtraInfo = in.readString();
- return networkAgentConfig;
- }
-
- @Override
- public NetworkAgentConfig[] newArray(int size) {
- return new NetworkAgentConfig[size];
- }
- };
-}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
deleted file mode 100644
index 4932952..0000000
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ /dev/null
@@ -1,2779 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
-
-import android.annotation.IntDef;
-import android.annotation.LongDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.wifi.WifiNetworkSuggestion;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.Process;
-import android.text.TextUtils;
-import android.util.ArraySet;
-import android.util.Range;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.net.module.util.CollectionUtils;
-import com.android.net.module.util.NetworkCapabilitiesUtils;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
-import java.util.Objects;
-import java.util.Set;
-import java.util.StringJoiner;
-
-/**
- * Representation of the capabilities of an active network. Instances are
- * typically obtained through
- * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)}
- * or {@link ConnectivityManager#getNetworkCapabilities(Network)}.
- * <p>
- * This replaces the old {@link ConnectivityManager#TYPE_MOBILE} method of
- * network selection. Rather than indicate a need for Wi-Fi because an
- * application needs high bandwidth and risk obsolescence when a new, fast
- * network appears (like LTE), the application should specify it needs high
- * bandwidth. Similarly if an application needs an unmetered network for a bulk
- * transfer it can specify that rather than assuming all cellular based
- * connections are metered and all Wi-Fi based connections are not.
- */
-public final class NetworkCapabilities implements Parcelable {
- private static final String TAG = "NetworkCapabilities";
-
- /**
- * Mechanism to support redaction of fields in NetworkCapabilities that are guarded by specific
- * app permissions.
- **/
- /**
- * Don't redact any fields since the receiving app holds all the necessary permissions.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final long REDACT_NONE = 0;
-
- /**
- * Redact any fields that need {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
- * permission since the receiving app does not hold this permission or the location toggle
- * is off.
- *
- * @see android.Manifest.permission#ACCESS_FINE_LOCATION
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1 << 0;
-
- /**
- * Redact any fields that need {@link android.Manifest.permission#LOCAL_MAC_ADDRESS}
- * permission since the receiving app does not hold this permission.
- *
- * @see android.Manifest.permission#LOCAL_MAC_ADDRESS
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 1 << 1;
-
- /**
- *
- * Redact any fields that need {@link android.Manifest.permission#NETWORK_SETTINGS}
- * permission since the receiving app does not hold this permission.
- *
- * @see android.Manifest.permission#NETWORK_SETTINGS
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final long REDACT_FOR_NETWORK_SETTINGS = 1 << 2;
-
- /**
- * Redact all fields in this object that require any relevant permission.
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final long REDACT_ALL = -1L;
-
- /** @hide */
- @LongDef(flag = true, prefix = { "REDACT_" }, value = {
- REDACT_NONE,
- REDACT_FOR_ACCESS_FINE_LOCATION,
- REDACT_FOR_LOCAL_MAC_ADDRESS,
- REDACT_FOR_NETWORK_SETTINGS,
- REDACT_ALL
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface RedactionType {}
-
- // Set to true when private DNS is broken.
- private boolean mPrivateDnsBroken;
-
- /**
- * Uid of the app making the request.
- */
- private int mRequestorUid;
-
- /**
- * Package name of the app making the request.
- */
- private String mRequestorPackageName;
-
- public NetworkCapabilities() {
- clearAll();
- mNetworkCapabilities = DEFAULT_CAPABILITIES;
- }
-
- public NetworkCapabilities(NetworkCapabilities nc) {
- this(nc, REDACT_NONE);
- }
-
- /**
- * Make a copy of NetworkCapabilities.
- *
- * @param nc Original NetworkCapabilities
- * @param redactions bitmask of redactions that needs to be performed on this new instance of
- * {@link NetworkCapabilities}.
- * @hide
- */
- public NetworkCapabilities(@Nullable NetworkCapabilities nc, @RedactionType long redactions) {
- if (nc != null) {
- set(nc);
- }
- if (mTransportInfo != null) {
- mTransportInfo = nc.mTransportInfo.makeCopy(redactions);
- }
- }
-
- /**
- * Completely clears the contents of this object, removing even the capabilities that are set
- * by default when the object is constructed.
- * @hide
- */
- public void clearAll() {
- mNetworkCapabilities = mTransportTypes = mForbiddenNetworkCapabilities = 0;
- mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
- mNetworkSpecifier = null;
- mTransportInfo = null;
- mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
- mUids = null;
- mAdministratorUids = new int[0];
- mOwnerUid = Process.INVALID_UID;
- mSSID = null;
- mPrivateDnsBroken = false;
- mRequestorUid = Process.INVALID_UID;
- mRequestorPackageName = null;
- mSubIds = new ArraySet<>();
- }
-
- /**
- * Set all contents of this object to the contents of a NetworkCapabilities.
- *
- * @param nc Original NetworkCapabilities
- * @hide
- */
- public void set(@NonNull NetworkCapabilities nc) {
- mNetworkCapabilities = nc.mNetworkCapabilities;
- mTransportTypes = nc.mTransportTypes;
- mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
- mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
- mNetworkSpecifier = nc.mNetworkSpecifier;
- if (nc.getTransportInfo() != null) {
- setTransportInfo(nc.getTransportInfo());
- } else {
- setTransportInfo(null);
- }
- mSignalStrength = nc.mSignalStrength;
- mUids = (nc.mUids == null) ? null : new ArraySet<>(nc.mUids);
- setAdministratorUids(nc.getAdministratorUids());
- mOwnerUid = nc.mOwnerUid;
- mForbiddenNetworkCapabilities = nc.mForbiddenNetworkCapabilities;
- mSSID = nc.mSSID;
- mPrivateDnsBroken = nc.mPrivateDnsBroken;
- mRequestorUid = nc.mRequestorUid;
- mRequestorPackageName = nc.mRequestorPackageName;
- mSubIds = new ArraySet<>(nc.mSubIds);
- }
-
- /**
- * Represents the network's capabilities. If any are specified they will be satisfied
- * by any Network that matches all of them.
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- private long mNetworkCapabilities;
-
- /**
- * If any capabilities specified here they must not exist in the matching Network.
- */
- private long mForbiddenNetworkCapabilities;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "NET_CAPABILITY_" }, value = {
- NET_CAPABILITY_MMS,
- NET_CAPABILITY_SUPL,
- NET_CAPABILITY_DUN,
- NET_CAPABILITY_FOTA,
- NET_CAPABILITY_IMS,
- NET_CAPABILITY_CBS,
- NET_CAPABILITY_WIFI_P2P,
- NET_CAPABILITY_IA,
- NET_CAPABILITY_RCS,
- NET_CAPABILITY_XCAP,
- NET_CAPABILITY_EIMS,
- NET_CAPABILITY_NOT_METERED,
- NET_CAPABILITY_INTERNET,
- NET_CAPABILITY_NOT_RESTRICTED,
- NET_CAPABILITY_TRUSTED,
- NET_CAPABILITY_NOT_VPN,
- NET_CAPABILITY_VALIDATED,
- NET_CAPABILITY_CAPTIVE_PORTAL,
- NET_CAPABILITY_NOT_ROAMING,
- NET_CAPABILITY_FOREGROUND,
- NET_CAPABILITY_NOT_CONGESTED,
- NET_CAPABILITY_NOT_SUSPENDED,
- NET_CAPABILITY_OEM_PAID,
- NET_CAPABILITY_MCX,
- NET_CAPABILITY_PARTIAL_CONNECTIVITY,
- NET_CAPABILITY_TEMPORARILY_NOT_METERED,
- NET_CAPABILITY_OEM_PRIVATE,
- NET_CAPABILITY_VEHICLE_INTERNAL,
- NET_CAPABILITY_NOT_VCN_MANAGED,
- NET_CAPABILITY_ENTERPRISE,
- NET_CAPABILITY_VSIM,
- NET_CAPABILITY_BIP,
- NET_CAPABILITY_HEAD_UNIT,
- })
- public @interface NetCapability { }
-
- /**
- * Indicates this is a network that has the ability to reach the
- * carrier's MMSC for sending and receiving MMS messages.
- */
- public static final int NET_CAPABILITY_MMS = 0;
-
- /**
- * Indicates this is a network that has the ability to reach the carrier's
- * SUPL server, used to retrieve GPS information.
- */
- public static final int NET_CAPABILITY_SUPL = 1;
-
- /**
- * Indicates this is a network that has the ability to reach the carrier's
- * DUN or tethering gateway.
- */
- public static final int NET_CAPABILITY_DUN = 2;
-
- /**
- * Indicates this is a network that has the ability to reach the carrier's
- * FOTA portal, used for over the air updates.
- */
- public static final int NET_CAPABILITY_FOTA = 3;
-
- /**
- * Indicates this is a network that has the ability to reach the carrier's
- * IMS servers, used for network registration and signaling.
- */
- public static final int NET_CAPABILITY_IMS = 4;
-
- /**
- * Indicates this is a network that has the ability to reach the carrier's
- * CBS servers, used for carrier specific services.
- */
- public static final int NET_CAPABILITY_CBS = 5;
-
- /**
- * Indicates this is a network that has the ability to reach a Wi-Fi direct
- * peer.
- */
- public static final int NET_CAPABILITY_WIFI_P2P = 6;
-
- /**
- * Indicates this is a network that has the ability to reach a carrier's
- * Initial Attach servers.
- */
- public static final int NET_CAPABILITY_IA = 7;
-
- /**
- * Indicates this is a network that has the ability to reach a carrier's
- * RCS servers, used for Rich Communication Services.
- */
- public static final int NET_CAPABILITY_RCS = 8;
-
- /**
- * Indicates this is a network that has the ability to reach a carrier's
- * XCAP servers, used for configuration and control.
- */
- public static final int NET_CAPABILITY_XCAP = 9;
-
- /**
- * Indicates this is a network that has the ability to reach a carrier's
- * Emergency IMS servers or other services, used for network signaling
- * during emergency calls.
- */
- public static final int NET_CAPABILITY_EIMS = 10;
-
- /**
- * Indicates that this network is unmetered.
- */
- public static final int NET_CAPABILITY_NOT_METERED = 11;
-
- /**
- * Indicates that this network should be able to reach the internet.
- */
- public static final int NET_CAPABILITY_INTERNET = 12;
-
- /**
- * Indicates that this network is available for general use. If this is not set
- * applications should not attempt to communicate on this network. Note that this
- * is simply informative and not enforcement - enforcement is handled via other means.
- * Set by default.
- */
- public static final int NET_CAPABILITY_NOT_RESTRICTED = 13;
-
- /**
- * Indicates that the user has indicated implicit trust of this network. This
- * generally means it's a sim-selected carrier, a plugged in ethernet, a paired
- * BT device or a wifi the user asked to connect to. Untrusted networks
- * are probably limited to unknown wifi AP. Set by default.
- */
- public static final int NET_CAPABILITY_TRUSTED = 14;
-
- /**
- * Indicates that this network is not a VPN. This capability is set by default and should be
- * explicitly cleared for VPN networks.
- */
- public static final int NET_CAPABILITY_NOT_VPN = 15;
-
- /**
- * Indicates that connectivity on this network was successfully validated. For example, for a
- * network with NET_CAPABILITY_INTERNET, it means that Internet connectivity was successfully
- * detected.
- */
- public static final int NET_CAPABILITY_VALIDATED = 16;
-
- /**
- * Indicates that this network was found to have a captive portal in place last time it was
- * probed.
- */
- public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17;
-
- /**
- * Indicates that this network is not roaming.
- */
- public static final int NET_CAPABILITY_NOT_ROAMING = 18;
-
- /**
- * Indicates that this network is available for use by apps, and not a network that is being
- * kept up in the background to facilitate fast network switching.
- */
- public static final int NET_CAPABILITY_FOREGROUND = 19;
-
- /**
- * Indicates that this network is not congested.
- * <p>
- * When a network is congested, applications should defer network traffic
- * that can be done at a later time, such as uploading analytics.
- */
- public static final int NET_CAPABILITY_NOT_CONGESTED = 20;
-
- /**
- * Indicates that this network is not currently suspended.
- * <p>
- * When a network is suspended, the network's IP addresses and any connections
- * established on the network remain valid, but the network is temporarily unable
- * to transfer data. This can happen, for example, if a cellular network experiences
- * a temporary loss of signal, such as when driving through a tunnel, etc.
- * A network with this capability is not suspended, so is expected to be able to
- * transfer data.
- */
- public static final int NET_CAPABILITY_NOT_SUSPENDED = 21;
-
- /**
- * Indicates that traffic that goes through this network is paid by oem. For example,
- * this network can be used by system apps to upload telemetry data.
- * @hide
- */
- @SystemApi
- public static final int NET_CAPABILITY_OEM_PAID = 22;
-
- /**
- * Indicates this is a network that has the ability to reach a carrier's Mission Critical
- * servers.
- */
- public static final int NET_CAPABILITY_MCX = 23;
-
- /**
- * Indicates that this network was tested to only provide partial connectivity.
- * @hide
- */
- @SystemApi
- public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24;
-
- /**
- * Indicates that this network is temporarily unmetered.
- * <p>
- * This capability will be set for networks that are generally metered, but are currently
- * unmetered, e.g., because the user is in a particular area. This capability can be changed at
- * any time. When it is removed, applications are responsible for stopping any data transfer
- * that should not occur on a metered network.
- * Note that most apps should use {@link #NET_CAPABILITY_NOT_METERED} instead. For more
- * information, see https://developer.android.com/about/versions/11/features/5g#meteredness.
- */
- public static final int NET_CAPABILITY_TEMPORARILY_NOT_METERED = 25;
-
- /**
- * Indicates that this network is private to the OEM and meant only for OEM use.
- * @hide
- */
- @SystemApi
- public static final int NET_CAPABILITY_OEM_PRIVATE = 26;
-
- /**
- * Indicates this is an internal vehicle network, meant to communicate with other
- * automotive systems.
- *
- * @hide
- */
- @SystemApi
- public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27;
-
- /**
- * Indicates that this network is not subsumed by a Virtual Carrier Network (VCN).
- * <p>
- * To provide an experience on a VCN similar to a single traditional carrier network, in
- * some cases the system sets this bit is set by default in application's network requests,
- * and may choose to remove it at its own discretion when matching the request to a network.
- * <p>
- * Applications that want to know about a Virtual Carrier Network's underlying networks,
- * for example to use them for multipath purposes, should remove this bit from their network
- * requests ; the system will not add it back once removed.
- * @hide
- */
- @SystemApi
- public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28;
-
- /**
- * Indicates that this network is intended for enterprise use.
- * <p>
- * 5G URSP rules may indicate that all data should use a connection dedicated for enterprise
- * use. If the enterprise capability is requested, all enterprise traffic will be routed over
- * the connection with this capability.
- */
- public static final int NET_CAPABILITY_ENTERPRISE = 29;
-
- /**
- * Indicates that this network has ability to access the carrier's Virtual Sim service.
- * @hide
- */
- @SystemApi
- public static final int NET_CAPABILITY_VSIM = 30;
-
- /**
- * Indicates that this network has ability to support Bearer Independent Protol.
- * @hide
- */
- @SystemApi
- public static final int NET_CAPABILITY_BIP = 31;
-
- /**
- * Indicates that this network is connected to an automotive head unit.
- */
- public static final int NET_CAPABILITY_HEAD_UNIT = 32;
-
- private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
- private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_HEAD_UNIT;
-
- /**
- * Network capabilities that are expected to be mutable, i.e., can change while a particular
- * network is connected.
- */
- private static final long MUTABLE_CAPABILITIES =
- // TRUSTED can change when user explicitly connects to an untrusted network in Settings.
- // http://b/18206275
- (1 << NET_CAPABILITY_TRUSTED)
- | (1 << NET_CAPABILITY_VALIDATED)
- | (1 << NET_CAPABILITY_CAPTIVE_PORTAL)
- | (1 << NET_CAPABILITY_NOT_ROAMING)
- | (1 << NET_CAPABILITY_FOREGROUND)
- | (1 << NET_CAPABILITY_NOT_CONGESTED)
- | (1 << NET_CAPABILITY_NOT_SUSPENDED)
- | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY)
- | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED)
- | (1 << NET_CAPABILITY_NOT_VCN_MANAGED)
- // The value of NET_CAPABILITY_HEAD_UNIT is 32, which cannot use int to do bit shift,
- // otherwise there will be an overflow. Use long to do bit shift instead.
- | (1L << NET_CAPABILITY_HEAD_UNIT);
-
- /**
- * Network capabilities that are not allowed in NetworkRequests. This exists because the
- * NetworkFactory / NetworkAgent model does not deal well with the situation where a
- * capability's presence cannot be known in advance. If such a capability is requested, then we
- * can get into a cycle where the NetworkFactory endlessly churns out NetworkAgents that then
- * get immediately torn down because they do not have the requested capability.
- */
- // Note that as a historical exception, the TRUSTED and NOT_VCN_MANAGED capabilities
- // are mutable but requestable. Factories are responsible for not getting
- // in an infinite loop about these.
- private static final long NON_REQUESTABLE_CAPABILITIES =
- MUTABLE_CAPABILITIES
- & ~(1 << NET_CAPABILITY_TRUSTED)
- & ~(1 << NET_CAPABILITY_NOT_VCN_MANAGED);
-
- /**
- * Capabilities that are set by default when the object is constructed.
- */
- private static final long DEFAULT_CAPABILITIES =
- (1 << NET_CAPABILITY_NOT_RESTRICTED)
- | (1 << NET_CAPABILITY_TRUSTED)
- | (1 << NET_CAPABILITY_NOT_VPN);
-
- /**
- * Capabilities that are managed by ConnectivityService.
- */
- private static final long CONNECTIVITY_MANAGED_CAPABILITIES =
- (1 << NET_CAPABILITY_VALIDATED)
- | (1 << NET_CAPABILITY_CAPTIVE_PORTAL)
- | (1 << NET_CAPABILITY_FOREGROUND)
- | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY);
-
- /**
- * Capabilities that are allowed for test networks. This list must be set so that it is safe
- * for an unprivileged user to create a network with these capabilities via shell. As such,
- * it must never contain capabilities that are generally useful to the system, such as
- * INTERNET, IMS, SUPL, etc.
- */
- private static final long TEST_NETWORKS_ALLOWED_CAPABILITIES =
- (1 << NET_CAPABILITY_NOT_METERED)
- | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED)
- | (1 << NET_CAPABILITY_NOT_RESTRICTED)
- | (1 << NET_CAPABILITY_NOT_VPN)
- | (1 << NET_CAPABILITY_NOT_ROAMING)
- | (1 << NET_CAPABILITY_NOT_CONGESTED)
- | (1 << NET_CAPABILITY_NOT_SUSPENDED)
- | (1 << NET_CAPABILITY_NOT_VCN_MANAGED);
-
- /**
- * Adds the given capability to this {@code NetworkCapability} instance.
- * Note that when searching for a network to satisfy a request, all capabilities
- * requested must be satisfied.
- *
- * @param capability the capability to be added.
- * @return This NetworkCapabilities instance, to facilitate chaining.
- * @hide
- */
- public @NonNull NetworkCapabilities addCapability(@NetCapability int capability) {
- // If the given capability was previously added to the list of forbidden capabilities
- // then the capability will also be removed from the list of forbidden capabilities.
- // TODO: Consider adding forbidden capabilities to the public API and mention this
- // in the documentation.
- checkValidCapability(capability);
- mNetworkCapabilities |= 1L << capability;
- // remove from forbidden capability list
- mForbiddenNetworkCapabilities &= ~(1L << capability);
- return this;
- }
-
- /**
- * Adds the given capability to the list of forbidden capabilities of this
- * {@code NetworkCapability} instance. Note that when searching for a network to
- * satisfy a request, the network must not contain any capability from forbidden capability
- * list.
- * <p>
- * If the capability was previously added to the list of required capabilities (for
- * example, it was there by default or added using {@link #addCapability(int)} method), then
- * it will be removed from the list of required capabilities as well.
- *
- * @see #addCapability(int)
- * @hide
- */
- public void addForbiddenCapability(@NetCapability int capability) {
- checkValidCapability(capability);
- mForbiddenNetworkCapabilities |= 1L << capability;
- mNetworkCapabilities &= ~(1L << capability); // remove from requested capabilities
- }
-
- /**
- * Removes (if found) the given capability from this {@code NetworkCapability}
- * instance that were added via addCapability(int) or setCapabilities(int[], int[]).
- *
- * @param capability the capability to be removed.
- * @return This NetworkCapabilities instance, to facilitate chaining.
- * @hide
- */
- public @NonNull NetworkCapabilities removeCapability(@NetCapability int capability) {
- checkValidCapability(capability);
- final long mask = ~(1L << capability);
- mNetworkCapabilities &= mask;
- return this;
- }
-
- /**
- * Removes (if found) the given forbidden capability from this {@code NetworkCapability}
- * instance that were added via addForbiddenCapability(int) or setCapabilities(int[], int[]).
- *
- * @param capability the capability to be removed.
- * @return This NetworkCapabilities instance, to facilitate chaining.
- * @hide
- */
- public @NonNull NetworkCapabilities removeForbiddenCapability(@NetCapability int capability) {
- checkValidCapability(capability);
- mForbiddenNetworkCapabilities &= ~(1L << capability);
- return this;
- }
-
- /**
- * Sets (or clears) the given capability on this {@link NetworkCapabilities}
- * instance.
- * @hide
- */
- public @NonNull NetworkCapabilities setCapability(@NetCapability int capability,
- boolean value) {
- if (value) {
- addCapability(capability);
- } else {
- removeCapability(capability);
- }
- return this;
- }
-
- /**
- * Gets all the capabilities set on this {@code NetworkCapability} instance.
- *
- * @return an array of capability values for this instance.
- */
- public @NonNull @NetCapability int[] getCapabilities() {
- return NetworkCapabilitiesUtils.unpackBits(mNetworkCapabilities);
- }
-
- /**
- * Gets all the forbidden capabilities set on this {@code NetworkCapability} instance.
- *
- * @return an array of forbidden capability values for this instance.
- * @hide
- */
- public @NetCapability int[] getForbiddenCapabilities() {
- return NetworkCapabilitiesUtils.unpackBits(mForbiddenNetworkCapabilities);
- }
-
-
- /**
- * Sets all the capabilities set on this {@code NetworkCapability} instance.
- * This overwrites any existing capabilities.
- *
- * @hide
- */
- public void setCapabilities(@NetCapability int[] capabilities,
- @NetCapability int[] forbiddenCapabilities) {
- mNetworkCapabilities = NetworkCapabilitiesUtils.packBits(capabilities);
- mForbiddenNetworkCapabilities = NetworkCapabilitiesUtils.packBits(forbiddenCapabilities);
- }
-
- /**
- * @deprecated use {@link #setCapabilities(int[], int[])}
- * @hide
- */
- @Deprecated
- public void setCapabilities(@NetCapability int[] capabilities) {
- setCapabilities(capabilities, new int[] {});
- }
-
- /**
- * Tests for the presence of a capability on this instance.
- *
- * @param capability the capabilities to be tested for.
- * @return {@code true} if set on this instance.
- */
- public boolean hasCapability(@NetCapability int capability) {
- return isValidCapability(capability)
- && ((mNetworkCapabilities & (1L << capability)) != 0);
- }
-
- /** @hide */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public boolean hasForbiddenCapability(@NetCapability int capability) {
- return isValidCapability(capability)
- && ((mForbiddenNetworkCapabilities & (1L << capability)) != 0);
- }
-
- /**
- * Check if this NetworkCapabilities has system managed capabilities or not.
- * @hide
- */
- public boolean hasConnectivityManagedCapability() {
- return ((mNetworkCapabilities & CONNECTIVITY_MANAGED_CAPABILITIES) != 0);
- }
-
- /**
- * Get the name of the given capability that carriers use.
- * If the capability does not have a carrier-name, returns null.
- *
- * @param capability The capability to get the carrier-name of.
- * @return The carrier-name of the capability, or null if it doesn't exist.
- * @hide
- */
- @SystemApi
- public static @Nullable String getCapabilityCarrierName(@NetCapability int capability) {
- if (capability == NET_CAPABILITY_ENTERPRISE) {
- return capabilityNameOf(capability);
- } else {
- return null;
- }
- }
-
- private void combineNetCapabilities(@NonNull NetworkCapabilities nc) {
- final long wantedCaps = this.mNetworkCapabilities | nc.mNetworkCapabilities;
- final long forbiddenCaps =
- this.mForbiddenNetworkCapabilities | nc.mForbiddenNetworkCapabilities;
- if ((wantedCaps & forbiddenCaps) != 0) {
- throw new IllegalArgumentException(
- "Cannot have the same capability in wanted and forbidden lists.");
- }
- this.mNetworkCapabilities = wantedCaps;
- this.mForbiddenNetworkCapabilities = forbiddenCaps;
- }
-
- /**
- * Convenience function that returns a human-readable description of the first mutable
- * capability we find. Used to present an error message to apps that request mutable
- * capabilities.
- *
- * @hide
- */
- public @Nullable String describeFirstNonRequestableCapability() {
- final long nonRequestable = (mNetworkCapabilities | mForbiddenNetworkCapabilities)
- & NON_REQUESTABLE_CAPABILITIES;
-
- if (nonRequestable != 0) {
- return capabilityNameOf(NetworkCapabilitiesUtils.unpackBits(nonRequestable)[0]);
- }
- if (mLinkUpBandwidthKbps != 0 || mLinkDownBandwidthKbps != 0) return "link bandwidth";
- if (hasSignalStrength()) return "signalStrength";
- if (isPrivateDnsBroken()) {
- return "privateDnsBroken";
- }
- return null;
- }
-
- private boolean satisfiedByNetCapabilities(@NonNull NetworkCapabilities nc,
- boolean onlyImmutable) {
- long requestedCapabilities = mNetworkCapabilities;
- long requestedForbiddenCapabilities = mForbiddenNetworkCapabilities;
- long providedCapabilities = nc.mNetworkCapabilities;
-
- if (onlyImmutable) {
- requestedCapabilities &= ~MUTABLE_CAPABILITIES;
- requestedForbiddenCapabilities &= ~MUTABLE_CAPABILITIES;
- }
- return ((providedCapabilities & requestedCapabilities) == requestedCapabilities)
- && ((requestedForbiddenCapabilities & providedCapabilities) == 0);
- }
-
- /** @hide */
- public boolean equalsNetCapabilities(@NonNull NetworkCapabilities nc) {
- return (nc.mNetworkCapabilities == this.mNetworkCapabilities)
- && (nc.mForbiddenNetworkCapabilities == this.mForbiddenNetworkCapabilities);
- }
-
- private boolean equalsNetCapabilitiesRequestable(@NonNull NetworkCapabilities that) {
- return ((this.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES)
- == (that.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES))
- && ((this.mForbiddenNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES)
- == (that.mForbiddenNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES));
- }
-
- /**
- * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if inferring the network is restricted.
- *
- * @hide
- */
- public void maybeMarkCapabilitiesRestricted() {
- if (NetworkCapabilitiesUtils.inferRestrictedCapability(this)) {
- removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- }
- }
-
- /**
- * Test networks have strong restrictions on what capabilities they can have. Enforce these
- * restrictions.
- * @hide
- */
- public void restrictCapabilitesForTestNetwork(int creatorUid) {
- final long originalCapabilities = mNetworkCapabilities;
- final long originalTransportTypes = mTransportTypes;
- final NetworkSpecifier originalSpecifier = mNetworkSpecifier;
- final int originalSignalStrength = mSignalStrength;
- final int originalOwnerUid = getOwnerUid();
- final int[] originalAdministratorUids = getAdministratorUids();
- final TransportInfo originalTransportInfo = getTransportInfo();
- clearAll();
- if (0 != (originalCapabilities & NET_CAPABILITY_NOT_RESTRICTED)) {
- // If the test network is not restricted, then it is only allowed to declare some
- // specific transports. This is to minimize impact on running apps in case an app
- // run from the shell creates a test a network.
- mTransportTypes =
- (originalTransportTypes & UNRESTRICTED_TEST_NETWORKS_ALLOWED_TRANSPORTS)
- | (1 << TRANSPORT_TEST);
- } else {
- // If the test transport is restricted, then it may declare any transport.
- mTransportTypes = (originalTransportTypes | (1 << TRANSPORT_TEST));
- }
- mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES;
- mNetworkSpecifier = originalSpecifier;
- mSignalStrength = originalSignalStrength;
- mTransportInfo = originalTransportInfo;
-
- // Only retain the owner and administrator UIDs if they match the app registering the remote
- // caller that registered the network.
- if (originalOwnerUid == creatorUid) {
- setOwnerUid(creatorUid);
- }
- if (CollectionUtils.contains(originalAdministratorUids, creatorUid)) {
- setAdministratorUids(new int[] {creatorUid});
- }
- // There is no need to clear the UIDs, they have already been cleared by clearAll() above.
- }
-
- /**
- * Representing the transport type. Apps should generally not care about transport. A
- * request for a fast internet connection could be satisfied by a number of different
- * transports. If any are specified here it will be satisfied a Network that matches
- * any of them. If a caller doesn't care about the transport it should not specify any.
- */
- private long mTransportTypes;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "TRANSPORT_" }, value = {
- TRANSPORT_CELLULAR,
- TRANSPORT_WIFI,
- TRANSPORT_BLUETOOTH,
- TRANSPORT_ETHERNET,
- TRANSPORT_VPN,
- TRANSPORT_WIFI_AWARE,
- TRANSPORT_LOWPAN,
- TRANSPORT_TEST,
- TRANSPORT_USB,
- })
- public @interface Transport { }
-
- /**
- * Indicates this network uses a Cellular transport.
- */
- public static final int TRANSPORT_CELLULAR = 0;
-
- /**
- * Indicates this network uses a Wi-Fi transport.
- */
- public static final int TRANSPORT_WIFI = 1;
-
- /**
- * Indicates this network uses a Bluetooth transport.
- */
- public static final int TRANSPORT_BLUETOOTH = 2;
-
- /**
- * Indicates this network uses an Ethernet transport.
- */
- public static final int TRANSPORT_ETHERNET = 3;
-
- /**
- * Indicates this network uses a VPN transport.
- */
- public static final int TRANSPORT_VPN = 4;
-
- /**
- * Indicates this network uses a Wi-Fi Aware transport.
- */
- public static final int TRANSPORT_WIFI_AWARE = 5;
-
- /**
- * Indicates this network uses a LoWPAN transport.
- */
- public static final int TRANSPORT_LOWPAN = 6;
-
- /**
- * Indicates this network uses a Test-only virtual interface as a transport.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int TRANSPORT_TEST = 7;
-
- /**
- * Indicates this network uses a USB transport.
- */
- public static final int TRANSPORT_USB = 8;
-
- /** @hide */
- public static final int MIN_TRANSPORT = TRANSPORT_CELLULAR;
- /** @hide */
- public static final int MAX_TRANSPORT = TRANSPORT_USB;
-
- /** @hide */
- public static boolean isValidTransport(@Transport int transportType) {
- return (MIN_TRANSPORT <= transportType) && (transportType <= MAX_TRANSPORT);
- }
-
- private static final String[] TRANSPORT_NAMES = {
- "CELLULAR",
- "WIFI",
- "BLUETOOTH",
- "ETHERNET",
- "VPN",
- "WIFI_AWARE",
- "LOWPAN",
- "TEST",
- "USB"
- };
-
- /**
- * Allowed transports on an unrestricted test network (in addition to TRANSPORT_TEST).
- */
- private static final int UNRESTRICTED_TEST_NETWORKS_ALLOWED_TRANSPORTS =
- 1 << TRANSPORT_TEST
- // Test ethernet networks can be created with EthernetManager#setIncludeTestInterfaces
- | 1 << TRANSPORT_ETHERNET
- // Test VPN networks can be created but their UID ranges must be empty.
- | 1 << TRANSPORT_VPN;
-
- /**
- * Adds the given transport type to this {@code NetworkCapability} instance.
- * Multiple transports may be applied. Note that when searching
- * for a network to satisfy a request, any listed in the request will satisfy the request.
- * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a
- * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network
- * to be selected. This is logically different than
- * {@code NetworkCapabilities.NET_CAPABILITY_*} listed above.
- *
- * @param transportType the transport type to be added.
- * @return This NetworkCapabilities instance, to facilitate chaining.
- * @hide
- */
- public @NonNull NetworkCapabilities addTransportType(@Transport int transportType) {
- checkValidTransportType(transportType);
- mTransportTypes |= 1 << transportType;
- setNetworkSpecifier(mNetworkSpecifier); // used for exception checking
- return this;
- }
-
- /**
- * Removes (if found) the given transport from this {@code NetworkCapability} instance.
- *
- * @param transportType the transport type to be removed.
- * @return This NetworkCapabilities instance, to facilitate chaining.
- * @hide
- */
- public @NonNull NetworkCapabilities removeTransportType(@Transport int transportType) {
- checkValidTransportType(transportType);
- mTransportTypes &= ~(1 << transportType);
- setNetworkSpecifier(mNetworkSpecifier); // used for exception checking
- return this;
- }
-
- /**
- * Sets (or clears) the given transport on this {@link NetworkCapabilities}
- * instance.
- *
- * @hide
- */
- public @NonNull NetworkCapabilities setTransportType(@Transport int transportType,
- boolean value) {
- if (value) {
- addTransportType(transportType);
- } else {
- removeTransportType(transportType);
- }
- return this;
- }
-
- /**
- * Gets all the transports set on this {@code NetworkCapability} instance.
- *
- * @return an array of transport type values for this instance.
- * @hide
- */
- @SystemApi
- @NonNull public @Transport int[] getTransportTypes() {
- return NetworkCapabilitiesUtils.unpackBits(mTransportTypes);
- }
-
- /**
- * Sets all the transports set on this {@code NetworkCapability} instance.
- * This overwrites any existing transports.
- *
- * @hide
- */
- public void setTransportTypes(@Transport int[] transportTypes) {
- mTransportTypes = NetworkCapabilitiesUtils.packBits(transportTypes);
- }
-
- /**
- * Tests for the presence of a transport on this instance.
- *
- * @param transportType the transport type to be tested for.
- * @return {@code true} if set on this instance.
- */
- public boolean hasTransport(@Transport int transportType) {
- return isValidTransport(transportType) && ((mTransportTypes & (1 << transportType)) != 0);
- }
-
- private void combineTransportTypes(NetworkCapabilities nc) {
- this.mTransportTypes |= nc.mTransportTypes;
- }
-
- private boolean satisfiedByTransportTypes(NetworkCapabilities nc) {
- return ((this.mTransportTypes == 0)
- || ((this.mTransportTypes & nc.mTransportTypes) != 0));
- }
-
- /** @hide */
- public boolean equalsTransportTypes(NetworkCapabilities nc) {
- return (nc.mTransportTypes == this.mTransportTypes);
- }
-
- /**
- * UID of the app that owns this network, or Process#INVALID_UID if none/unknown.
- *
- * <p>This field keeps track of the UID of the app that created this network and is in charge of
- * its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running
- * VPN, or Carrier Service app managing a cellular data connection.
- *
- * <p>For NetworkCapability instances being sent from ConnectivityService, this value MUST be
- * reset to Process.INVALID_UID unless all the following conditions are met:
- *
- * <p>The caller is the network owner, AND one of the following sets of requirements is met:
- *
- * <ol>
- * <li>The described Network is a VPN
- * </ol>
- *
- * <p>OR:
- *
- * <ol>
- * <li>The calling app is the network owner
- * <li>The calling app has the ACCESS_FINE_LOCATION permission granted
- * <li>The user's location toggle is on
- * </ol>
- *
- * This is because the owner UID is location-sensitive. The apps that request a network could
- * know where the device is if they can tell for sure the system has connected to the network
- * they requested.
- *
- * <p>This is populated by the network agents and for the NetworkCapabilities instance sent by
- * an app to the System Server, the value MUST be reset to Process.INVALID_UID by the system
- * server.
- */
- private int mOwnerUid = Process.INVALID_UID;
-
- /**
- * Set the UID of the owner app.
- * @hide
- */
- public @NonNull NetworkCapabilities setOwnerUid(final int uid) {
- mOwnerUid = uid;
- return this;
- }
-
- /**
- * Retrieves the UID of the app that owns this network.
- *
- * <p>For user privacy reasons, this field will only be populated if the following conditions
- * are met:
- *
- * <p>The caller is the network owner, AND one of the following sets of requirements is met:
- *
- * <ol>
- * <li>The described Network is a VPN
- * </ol>
- *
- * <p>OR:
- *
- * <ol>
- * <li>The calling app is the network owner
- * <li>The calling app has the ACCESS_FINE_LOCATION permission granted
- * <li>The user's location toggle is on
- * </ol>
- *
- * Instances of NetworkCapabilities sent to apps without the appropriate permissions will have
- * this field cleared out.
- *
- * <p>
- * This field will only be populated for VPN and wifi network suggestor apps (i.e using
- * {@link WifiNetworkSuggestion}), and only for the network they own.
- * In the case of wifi network suggestors apps, this field is also location sensitive, so the
- * app needs to hold {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission. If the
- * app targets SDK version greater than or equal to {@link Build.VERSION_CODES#S}, then they
- * also need to use {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} to get the info in their
- * callback. If the apps targets SDK version equal to {{@link Build.VERSION_CODES#R}, this field
- * will always be included. The app will be blamed for location access if this field is
- * included.
- * </p>
- */
- public int getOwnerUid() {
- return mOwnerUid;
- }
-
- private boolean equalsOwnerUid(@NonNull final NetworkCapabilities nc) {
- return mOwnerUid == nc.mOwnerUid;
- }
-
- /**
- * UIDs of packages that are administrators of this network, or empty if none.
- *
- * <p>This field tracks the UIDs of packages that have permission to manage this network.
- *
- * <p>Network owners will also be listed as administrators.
- *
- * <p>For NetworkCapability instances being sent from the System Server, this value MUST be
- * empty unless the destination is 1) the System Server, or 2) Telephony. In either case, the
- * receiving entity must have the ACCESS_FINE_LOCATION permission and target R+.
- *
- * <p>When received from an app in a NetworkRequest this is always cleared out by the system
- * server. This field is never used for matching NetworkRequests to NetworkAgents.
- */
- @NonNull private int[] mAdministratorUids = new int[0];
-
- /**
- * Sets the int[] of UIDs that are administrators of this network.
- *
- * <p>UIDs included in administratorUids gain administrator privileges over this Network.
- * Examples of UIDs that should be included in administratorUids are:
- *
- * <ul>
- * <li>Carrier apps with privileges for the relevant subscription
- * <li>Active VPN apps
- * <li>Other application groups with a particular Network-related role
- * </ul>
- *
- * <p>In general, user-supplied networks (such as WiFi networks) do not have an administrator.
- *
- * <p>An app is granted owner privileges over Networks that it supplies. The owner UID MUST
- * always be included in administratorUids.
- *
- * <p>The administrator UIDs are set by network agents.
- *
- * @param administratorUids the UIDs to be set as administrators of this Network.
- * @throws IllegalArgumentException if duplicate UIDs are contained in administratorUids
- * @see #mAdministratorUids
- * @hide
- */
- @NonNull
- public NetworkCapabilities setAdministratorUids(@NonNull final int[] administratorUids) {
- mAdministratorUids = Arrays.copyOf(administratorUids, administratorUids.length);
- Arrays.sort(mAdministratorUids);
- for (int i = 0; i < mAdministratorUids.length - 1; i++) {
- if (mAdministratorUids[i] >= mAdministratorUids[i + 1]) {
- throw new IllegalArgumentException("All administrator UIDs must be unique");
- }
- }
- return this;
- }
-
- /**
- * Retrieves the UIDs that are administrators of this Network.
- *
- * <p>This is only populated in NetworkCapabilities objects that come from network agents for
- * networks that are managed by specific apps on the system, such as carrier privileged apps or
- * wifi suggestion apps. This will include the network owner.
- *
- * @return the int[] of UIDs that are administrators of this Network
- * @see #mAdministratorUids
- * @hide
- */
- @NonNull
- @SystemApi
- public int[] getAdministratorUids() {
- return Arrays.copyOf(mAdministratorUids, mAdministratorUids.length);
- }
-
- /**
- * Tests if the set of administrator UIDs of this network is the same as that of the passed one.
- *
- * <p>The administrator UIDs must be in sorted order.
- *
- * <p>nc is assumed non-null. Else, NPE.
- *
- * @hide
- */
- @VisibleForTesting(visibility = PRIVATE)
- public boolean equalsAdministratorUids(@NonNull final NetworkCapabilities nc) {
- return Arrays.equals(mAdministratorUids, nc.mAdministratorUids);
- }
-
- /**
- * Combine the administrator UIDs of the capabilities.
- *
- * <p>This is only legal if either of the administrators lists are empty, or if they are equal.
- * Combining administrator UIDs is only possible for combining non-overlapping sets of UIDs.
- *
- * <p>If both administrator lists are non-empty but not equal, they conflict with each other. In
- * this case, it would not make sense to add them together.
- */
- private void combineAdministratorUids(@NonNull final NetworkCapabilities nc) {
- if (nc.mAdministratorUids.length == 0) return;
- if (mAdministratorUids.length == 0) {
- mAdministratorUids = Arrays.copyOf(nc.mAdministratorUids, nc.mAdministratorUids.length);
- return;
- }
- if (!equalsAdministratorUids(nc)) {
- throw new IllegalStateException("Can't combine two different administrator UID lists");
- }
- }
-
- /**
- * Value indicating that link bandwidth is unspecified.
- * @hide
- */
- public static final int LINK_BANDWIDTH_UNSPECIFIED = 0;
-
- /**
- * Passive link bandwidth. This is a rough guide of the expected peak bandwidth
- * for the first hop on the given transport. It is not measured, but may take into account
- * link parameters (Radio technology, allocated channels, etc).
- */
- private int mLinkUpBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
- private int mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
-
- /**
- * Sets the upstream bandwidth for this network in Kbps. This always only refers to
- * the estimated first hop transport bandwidth.
- * <p>
- * {@see Builder#setLinkUpstreamBandwidthKbps}
- *
- * @param upKbps the estimated first hop upstream (device to network) bandwidth.
- * @hide
- */
- public @NonNull NetworkCapabilities setLinkUpstreamBandwidthKbps(int upKbps) {
- mLinkUpBandwidthKbps = upKbps;
- return this;
- }
-
- /**
- * Retrieves the upstream bandwidth for this network in Kbps. This always only refers to
- * the estimated first hop transport bandwidth.
- *
- * @return The estimated first hop upstream (device to network) bandwidth.
- */
- public int getLinkUpstreamBandwidthKbps() {
- return mLinkUpBandwidthKbps;
- }
-
- /**
- * Sets the downstream bandwidth for this network in Kbps. This always only refers to
- * the estimated first hop transport bandwidth.
- * <p>
- * {@see Builder#setLinkUpstreamBandwidthKbps}
- *
- * @param downKbps the estimated first hop downstream (network to device) bandwidth.
- * @hide
- */
- public @NonNull NetworkCapabilities setLinkDownstreamBandwidthKbps(int downKbps) {
- mLinkDownBandwidthKbps = downKbps;
- return this;
- }
-
- /**
- * Retrieves the downstream bandwidth for this network in Kbps. This always only refers to
- * the estimated first hop transport bandwidth.
- *
- * @return The estimated first hop downstream (network to device) bandwidth.
- */
- public int getLinkDownstreamBandwidthKbps() {
- return mLinkDownBandwidthKbps;
- }
-
- private void combineLinkBandwidths(NetworkCapabilities nc) {
- this.mLinkUpBandwidthKbps =
- Math.max(this.mLinkUpBandwidthKbps, nc.mLinkUpBandwidthKbps);
- this.mLinkDownBandwidthKbps =
- Math.max(this.mLinkDownBandwidthKbps, nc.mLinkDownBandwidthKbps);
- }
- private boolean satisfiedByLinkBandwidths(NetworkCapabilities nc) {
- return !(this.mLinkUpBandwidthKbps > nc.mLinkUpBandwidthKbps
- || this.mLinkDownBandwidthKbps > nc.mLinkDownBandwidthKbps);
- }
- private boolean equalsLinkBandwidths(NetworkCapabilities nc) {
- return (this.mLinkUpBandwidthKbps == nc.mLinkUpBandwidthKbps
- && this.mLinkDownBandwidthKbps == nc.mLinkDownBandwidthKbps);
- }
- /** @hide */
- public static int minBandwidth(int a, int b) {
- if (a == LINK_BANDWIDTH_UNSPECIFIED) {
- return b;
- } else if (b == LINK_BANDWIDTH_UNSPECIFIED) {
- return a;
- } else {
- return Math.min(a, b);
- }
- }
- /** @hide */
- public static int maxBandwidth(int a, int b) {
- return Math.max(a, b);
- }
-
- private NetworkSpecifier mNetworkSpecifier = null;
- private TransportInfo mTransportInfo = null;
-
- /**
- * Sets the optional bearer specific network specifier.
- * This has no meaning if a single transport is also not specified, so calling
- * this without a single transport set will generate an exception, as will
- * subsequently adding or removing transports after this is set.
- * </p>
- *
- * @param networkSpecifier A concrete, parcelable framework class that extends
- * NetworkSpecifier.
- * @return This NetworkCapabilities instance, to facilitate chaining.
- * @hide
- */
- public @NonNull NetworkCapabilities setNetworkSpecifier(
- @NonNull NetworkSpecifier networkSpecifier) {
- if (networkSpecifier != null && Long.bitCount(mTransportTypes) != 1) {
- throw new IllegalStateException("Must have a single transport specified to use " +
- "setNetworkSpecifier");
- }
-
- mNetworkSpecifier = networkSpecifier;
-
- return this;
- }
-
- /**
- * Sets the optional transport specific information.
- *
- * @param transportInfo A concrete, parcelable framework class that extends
- * {@link TransportInfo}.
- * @return This NetworkCapabilities instance, to facilitate chaining.
- * @hide
- */
- public @NonNull NetworkCapabilities setTransportInfo(@NonNull TransportInfo transportInfo) {
- mTransportInfo = transportInfo;
- return this;
- }
-
- /**
- * Gets the optional bearer specific network specifier. May be {@code null} if not set.
- *
- * @return The optional {@link NetworkSpecifier} specifying the bearer specific network
- * specifier or {@code null}.
- */
- public @Nullable NetworkSpecifier getNetworkSpecifier() {
- return mNetworkSpecifier;
- }
-
- /**
- * Returns a transport-specific information container. The application may cast this
- * container to a concrete sub-class based on its knowledge of the network request. The
- * application should be able to deal with a {@code null} return value or an invalid case,
- * e.g. use {@code instanceof} operator to verify expected type.
- *
- * @return A concrete implementation of the {@link TransportInfo} class or null if not
- * available for the network.
- */
- @Nullable public TransportInfo getTransportInfo() {
- return mTransportInfo;
- }
-
- private void combineSpecifiers(NetworkCapabilities nc) {
- if (mNetworkSpecifier != null && !mNetworkSpecifier.equals(nc.mNetworkSpecifier)) {
- throw new IllegalStateException("Can't combine two networkSpecifiers");
- }
- setNetworkSpecifier(nc.mNetworkSpecifier);
- }
-
- private boolean satisfiedBySpecifier(NetworkCapabilities nc) {
- return mNetworkSpecifier == null || mNetworkSpecifier.canBeSatisfiedBy(nc.mNetworkSpecifier)
- || nc.mNetworkSpecifier instanceof MatchAllNetworkSpecifier;
- }
-
- private boolean equalsSpecifier(NetworkCapabilities nc) {
- return Objects.equals(mNetworkSpecifier, nc.mNetworkSpecifier);
- }
-
- private void combineTransportInfos(NetworkCapabilities nc) {
- if (mTransportInfo != null && !mTransportInfo.equals(nc.mTransportInfo)) {
- throw new IllegalStateException("Can't combine two TransportInfos");
- }
- setTransportInfo(nc.mTransportInfo);
- }
-
- private boolean equalsTransportInfo(NetworkCapabilities nc) {
- return Objects.equals(mTransportInfo, nc.mTransportInfo);
- }
-
- /**
- * Magic value that indicates no signal strength provided. A request specifying this value is
- * always satisfied.
- */
- public static final int SIGNAL_STRENGTH_UNSPECIFIED = Integer.MIN_VALUE;
-
- /**
- * Signal strength. This is a signed integer, and higher values indicate better signal.
- * The exact units are bearer-dependent. For example, Wi-Fi uses RSSI.
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
- private int mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
-
- /**
- * Sets the signal strength. This is a signed integer, with higher values indicating a stronger
- * signal. The exact units are bearer-dependent. For example, Wi-Fi uses the same RSSI units
- * reported by wifi code.
- * <p>
- * Note that when used to register a network callback, this specifies the minimum acceptable
- * signal strength. When received as the state of an existing network it specifies the current
- * value. A value of code SIGNAL_STRENGTH_UNSPECIFIED} means no value when received and has no
- * effect when requesting a callback.
- *
- * @param signalStrength the bearer-specific signal strength.
- * @hide
- */
- public @NonNull NetworkCapabilities setSignalStrength(int signalStrength) {
- mSignalStrength = signalStrength;
- return this;
- }
-
- /**
- * Returns {@code true} if this object specifies a signal strength.
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public boolean hasSignalStrength() {
- return mSignalStrength > SIGNAL_STRENGTH_UNSPECIFIED;
- }
-
- /**
- * Retrieves the signal strength.
- *
- * @return The bearer-specific signal strength.
- */
- public int getSignalStrength() {
- return mSignalStrength;
- }
-
- private void combineSignalStrength(NetworkCapabilities nc) {
- this.mSignalStrength = Math.max(this.mSignalStrength, nc.mSignalStrength);
- }
-
- private boolean satisfiedBySignalStrength(NetworkCapabilities nc) {
- return this.mSignalStrength <= nc.mSignalStrength;
- }
-
- private boolean equalsSignalStrength(NetworkCapabilities nc) {
- return this.mSignalStrength == nc.mSignalStrength;
- }
-
- /**
- * List of UIDs this network applies to. No restriction if null.
- * <p>
- * For networks, mUids represent the list of network this applies to, and null means this
- * network applies to all UIDs.
- * For requests, mUids is the list of UIDs this network MUST apply to to match ; ALL UIDs
- * must be included in a network so that they match. As an exception to the general rule,
- * a null mUids field for requests mean "no requirements" rather than what the general rule
- * would suggest ("must apply to all UIDs") : this is because this has shown to be what users
- * of this API expect in practice. A network that must match all UIDs can still be
- * expressed with a set ranging the entire set of possible UIDs.
- * <p>
- * mUids is typically (and at this time, only) used by VPN. This network is only available to
- * the UIDs in this list, and it is their default network. Apps in this list that wish to
- * bypass the VPN can do so iff the VPN app allows them to or if they are privileged. If this
- * member is null, then the network is not restricted by app UID. If it's an empty list, then
- * it means nobody can use it.
- * As a special exception, the app managing this network (as identified by its UID stored in
- * mOwnerUid) can always see this network. This is embodied by a special check in
- * satisfiedByUids. That still does not mean the network necessarily <strong>applies</strong>
- * to the app that manages it as determined by #appliesToUid.
- * <p>
- * Please note that in principle a single app can be associated with multiple UIDs because
- * each app will have a different UID when it's run as a different (macro-)user. A single
- * macro user can only have a single active VPN app at any given time however.
- * <p>
- * Also please be aware this class does not try to enforce any normalization on this. Callers
- * can only alter the UIDs by setting them wholesale : this class does not provide any utility
- * to add or remove individual UIDs or ranges. If callers have any normalization needs on
- * their own (like requiring sortedness or no overlap) they need to enforce it
- * themselves. Some of the internal methods also assume this is normalized as in no adjacent
- * or overlapping ranges are present.
- *
- * @hide
- */
- private ArraySet<UidRange> mUids = null;
-
- /**
- * Convenience method to set the UIDs this network applies to to a single UID.
- * @hide
- */
- public @NonNull NetworkCapabilities setSingleUid(int uid) {
- mUids = new ArraySet<>(1);
- mUids.add(new UidRange(uid, uid));
- return this;
- }
-
- /**
- * Set the list of UIDs this network applies to.
- * This makes a copy of the set so that callers can't modify it after the call.
- * @hide
- */
- public @NonNull NetworkCapabilities setUids(@Nullable Set<Range<Integer>> uids) {
- mUids = UidRange.fromIntRanges(uids);
- return this;
- }
-
- /**
- * Get the list of UIDs this network applies to.
- * This returns a copy of the set so that callers can't modify the original object.
- *
- * @return the list of UIDs this network applies to. If {@code null}, then the network applies
- * to all UIDs.
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @SuppressLint("NullableCollection")
- public @Nullable Set<Range<Integer>> getUids() {
- return UidRange.toIntRanges(mUids);
- }
-
- /**
- * Get the list of UIDs this network applies to.
- * This returns a copy of the set so that callers can't modify the original object.
- * @hide
- */
- public @Nullable Set<UidRange> getUidRanges() {
- if (mUids == null) return null;
-
- return new ArraySet<>(mUids);
- }
-
- /**
- * Test whether this network applies to this UID.
- * @hide
- */
- public boolean appliesToUid(int uid) {
- if (null == mUids) return true;
- for (UidRange range : mUids) {
- if (range.contains(uid)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Tests if the set of UIDs that this network applies to is the same as the passed network.
- * <p>
- * This test only checks whether equal range objects are in both sets. It will
- * return false if the ranges are not exactly the same, even if the covered UIDs
- * are for an equivalent result.
- * <p>
- * Note that this method is not very optimized, which is fine as long as it's not used very
- * often.
- * <p>
- * nc is assumed nonnull.
- *
- * @hide
- */
- @VisibleForTesting
- public boolean equalsUids(@NonNull NetworkCapabilities nc) {
- Set<UidRange> comparedUids = nc.mUids;
- if (null == comparedUids) return null == mUids;
- if (null == mUids) return false;
- // Make a copy so it can be mutated to check that all ranges in mUids
- // also are in uids.
- final Set<UidRange> uids = new ArraySet<>(mUids);
- for (UidRange range : comparedUids) {
- if (!uids.contains(range)) {
- return false;
- }
- uids.remove(range);
- }
- return uids.isEmpty();
- }
-
- /**
- * Test whether the passed NetworkCapabilities satisfies the UIDs this capabilities require.
- *
- * This method is called on the NetworkCapabilities embedded in a request with the
- * capabilities of an available network. It checks whether all the UIDs from this listen
- * (representing the UIDs that must have access to the network) are satisfied by the UIDs
- * in the passed nc (representing the UIDs that this network is available to).
- * <p>
- * As a special exception, the UID that created the passed network (as represented by its
- * mOwnerUid field) always satisfies a NetworkRequest requiring it (of LISTEN
- * or REQUEST types alike), even if the network does not apply to it. That is so a VPN app
- * can see its own network when it listens for it.
- * <p>
- * nc is assumed nonnull. Else, NPE.
- * @see #appliesToUid
- * @hide
- */
- public boolean satisfiedByUids(@NonNull NetworkCapabilities nc) {
- if (null == nc.mUids || null == mUids) return true; // The network satisfies everything.
- for (UidRange requiredRange : mUids) {
- if (requiredRange.contains(nc.mOwnerUid)) return true;
- if (!nc.appliesToUidRange(requiredRange)) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Returns whether this network applies to the passed ranges.
- * This assumes that to apply, the passed range has to be entirely contained
- * within one of the ranges this network applies to. If the ranges are not normalized,
- * this method may return false even though all required UIDs are covered because no
- * single range contained them all.
- * @hide
- */
- @VisibleForTesting
- public boolean appliesToUidRange(@Nullable UidRange requiredRange) {
- if (null == mUids) return true;
- for (UidRange uidRange : mUids) {
- if (uidRange.containsRange(requiredRange)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Combine the UIDs this network currently applies to with the UIDs the passed
- * NetworkCapabilities apply to.
- * nc is assumed nonnull.
- */
- private void combineUids(@NonNull NetworkCapabilities nc) {
- if (null == nc.mUids || null == mUids) {
- mUids = null;
- return;
- }
- mUids.addAll(nc.mUids);
- }
-
-
- /**
- * The SSID of the network, or null if not applicable or unknown.
- * <p>
- * This is filled in by wifi code.
- * @hide
- */
- private String mSSID;
-
- /**
- * Sets the SSID of this network.
- * @hide
- */
- public @NonNull NetworkCapabilities setSSID(@Nullable String ssid) {
- mSSID = ssid;
- return this;
- }
-
- /**
- * Gets the SSID of this network, or null if none or unknown.
- * @hide
- */
- @SystemApi
- public @Nullable String getSsid() {
- return mSSID;
- }
-
- /**
- * Tests if the SSID of this network is the same as the SSID of the passed network.
- * @hide
- */
- public boolean equalsSSID(@NonNull NetworkCapabilities nc) {
- return Objects.equals(mSSID, nc.mSSID);
- }
-
- /**
- * Check if the SSID requirements of this object are matched by the passed object.
- * @hide
- */
- public boolean satisfiedBySSID(@NonNull NetworkCapabilities nc) {
- return mSSID == null || mSSID.equals(nc.mSSID);
- }
-
- /**
- * Combine SSIDs of the capabilities.
- * <p>
- * This is only legal if either the SSID of this object is null, or both SSIDs are
- * equal.
- * @hide
- */
- private void combineSSIDs(@NonNull NetworkCapabilities nc) {
- if (mSSID != null && !mSSID.equals(nc.mSSID)) {
- throw new IllegalStateException("Can't combine two SSIDs");
- }
- setSSID(nc.mSSID);
- }
-
- /**
- * Combine a set of Capabilities to this one. Useful for coming up with the complete set.
- * <p>
- * Note that this method may break an invariant of having a particular capability in either
- * wanted or forbidden lists but never in both. Requests that have the same capability in
- * both lists will never be satisfied.
- * @hide
- */
- public void combineCapabilities(@NonNull NetworkCapabilities nc) {
- combineNetCapabilities(nc);
- combineTransportTypes(nc);
- combineLinkBandwidths(nc);
- combineSpecifiers(nc);
- combineTransportInfos(nc);
- combineSignalStrength(nc);
- combineUids(nc);
- combineSSIDs(nc);
- combineRequestor(nc);
- combineAdministratorUids(nc);
- combineSubscriptionIds(nc);
- }
-
- /**
- * Check if our requirements are satisfied by the given {@code NetworkCapabilities}.
- *
- * @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements.
- * @param onlyImmutable if {@code true}, do not consider mutable requirements such as link
- * bandwidth, signal strength, or validation / captive portal status.
- *
- * @hide
- */
- private boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc, boolean onlyImmutable) {
- return (nc != null
- && satisfiedByNetCapabilities(nc, onlyImmutable)
- && satisfiedByTransportTypes(nc)
- && (onlyImmutable || satisfiedByLinkBandwidths(nc))
- && satisfiedBySpecifier(nc)
- && (onlyImmutable || satisfiedBySignalStrength(nc))
- && (onlyImmutable || satisfiedByUids(nc))
- && (onlyImmutable || satisfiedBySSID(nc))
- && (onlyImmutable || satisfiedByRequestor(nc))
- && (onlyImmutable || satisfiedBySubscriptionIds(nc)));
- }
-
- /**
- * Check if our requirements are satisfied by the given {@code NetworkCapabilities}.
- *
- * @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements.
- *
- * @hide
- */
- @SystemApi
- public boolean satisfiedByNetworkCapabilities(@Nullable NetworkCapabilities nc) {
- return satisfiedByNetworkCapabilities(nc, false);
- }
-
- /**
- * Check if our immutable requirements are satisfied by the given {@code NetworkCapabilities}.
- *
- * @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements.
- *
- * @hide
- */
- public boolean satisfiedByImmutableNetworkCapabilities(@Nullable NetworkCapabilities nc) {
- return satisfiedByNetworkCapabilities(nc, true);
- }
-
- /**
- * Checks that our immutable capabilities are the same as those of the given
- * {@code NetworkCapabilities} and return a String describing any difference.
- * The returned String is empty if there is no difference.
- *
- * @hide
- */
- public String describeImmutableDifferences(@Nullable NetworkCapabilities that) {
- if (that == null) {
- return "other NetworkCapabilities was null";
- }
-
- StringJoiner joiner = new StringJoiner(", ");
-
- // Ignore NOT_METERED being added or removed as it is effectively dynamic. http://b/63326103
- // TODO: properly support NOT_METERED as a mutable and requestable capability.
- final long mask = ~MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_NOT_METERED);
- long oldImmutableCapabilities = this.mNetworkCapabilities & mask;
- long newImmutableCapabilities = that.mNetworkCapabilities & mask;
- if (oldImmutableCapabilities != newImmutableCapabilities) {
- String before = capabilityNamesOf(NetworkCapabilitiesUtils.unpackBits(
- oldImmutableCapabilities));
- String after = capabilityNamesOf(NetworkCapabilitiesUtils.unpackBits(
- newImmutableCapabilities));
- joiner.add(String.format("immutable capabilities changed: %s -> %s", before, after));
- }
-
- if (!equalsSpecifier(that)) {
- NetworkSpecifier before = this.getNetworkSpecifier();
- NetworkSpecifier after = that.getNetworkSpecifier();
- joiner.add(String.format("specifier changed: %s -> %s", before, after));
- }
-
- if (!equalsTransportTypes(that)) {
- String before = transportNamesOf(this.getTransportTypes());
- String after = transportNamesOf(that.getTransportTypes());
- joiner.add(String.format("transports changed: %s -> %s", before, after));
- }
-
- return joiner.toString();
- }
-
- /**
- * Checks that our requestable capabilities are the same as those of the given
- * {@code NetworkCapabilities}.
- *
- * @hide
- */
- public boolean equalRequestableCapabilities(@Nullable NetworkCapabilities nc) {
- if (nc == null) return false;
- return (equalsNetCapabilitiesRequestable(nc)
- && equalsTransportTypes(nc)
- && equalsSpecifier(nc));
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (obj == null || (obj instanceof NetworkCapabilities == false)) return false;
- NetworkCapabilities that = (NetworkCapabilities) obj;
- return equalsNetCapabilities(that)
- && equalsTransportTypes(that)
- && equalsLinkBandwidths(that)
- && equalsSignalStrength(that)
- && equalsSpecifier(that)
- && equalsTransportInfo(that)
- && equalsUids(that)
- && equalsSSID(that)
- && equalsOwnerUid(that)
- && equalsPrivateDnsBroken(that)
- && equalsRequestor(that)
- && equalsAdministratorUids(that)
- && equalsSubscriptionIds(that);
- }
-
- @Override
- public int hashCode() {
- return (int) (mNetworkCapabilities & 0xFFFFFFFF)
- + ((int) (mNetworkCapabilities >> 32) * 3)
- + ((int) (mForbiddenNetworkCapabilities & 0xFFFFFFFF) * 5)
- + ((int) (mForbiddenNetworkCapabilities >> 32) * 7)
- + ((int) (mTransportTypes & 0xFFFFFFFF) * 11)
- + ((int) (mTransportTypes >> 32) * 13)
- + mLinkUpBandwidthKbps * 17
- + mLinkDownBandwidthKbps * 19
- + Objects.hashCode(mNetworkSpecifier) * 23
- + mSignalStrength * 29
- + mOwnerUid * 31
- + Objects.hashCode(mUids) * 37
- + Objects.hashCode(mSSID) * 41
- + Objects.hashCode(mTransportInfo) * 43
- + Objects.hashCode(mPrivateDnsBroken) * 47
- + Objects.hashCode(mRequestorUid) * 53
- + Objects.hashCode(mRequestorPackageName) * 59
- + Arrays.hashCode(mAdministratorUids) * 61
- + Objects.hashCode(mSubIds) * 67;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- private <T extends Parcelable> void writeParcelableArraySet(Parcel in,
- @Nullable ArraySet<T> val, int flags) {
- final int size = (val != null) ? val.size() : -1;
- in.writeInt(size);
- for (int i = 0; i < size; i++) {
- in.writeParcelable(val.valueAt(i), flags);
- }
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeLong(mNetworkCapabilities);
- dest.writeLong(mForbiddenNetworkCapabilities);
- dest.writeLong(mTransportTypes);
- dest.writeInt(mLinkUpBandwidthKbps);
- dest.writeInt(mLinkDownBandwidthKbps);
- dest.writeParcelable((Parcelable) mNetworkSpecifier, flags);
- dest.writeParcelable((Parcelable) mTransportInfo, flags);
- dest.writeInt(mSignalStrength);
- writeParcelableArraySet(dest, mUids, flags);
- dest.writeString(mSSID);
- dest.writeBoolean(mPrivateDnsBroken);
- dest.writeIntArray(getAdministratorUids());
- dest.writeInt(mOwnerUid);
- dest.writeInt(mRequestorUid);
- dest.writeString(mRequestorPackageName);
- dest.writeIntArray(CollectionUtils.toIntArray(mSubIds));
- }
-
- public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
- new Creator<NetworkCapabilities>() {
- @Override
- public NetworkCapabilities createFromParcel(Parcel in) {
- NetworkCapabilities netCap = new NetworkCapabilities();
-
- netCap.mNetworkCapabilities = in.readLong();
- netCap.mForbiddenNetworkCapabilities = in.readLong();
- netCap.mTransportTypes = in.readLong();
- netCap.mLinkUpBandwidthKbps = in.readInt();
- netCap.mLinkDownBandwidthKbps = in.readInt();
- netCap.mNetworkSpecifier = in.readParcelable(null);
- netCap.mTransportInfo = in.readParcelable(null);
- netCap.mSignalStrength = in.readInt();
- netCap.mUids = readParcelableArraySet(in, null /* ClassLoader, null for default */);
- netCap.mSSID = in.readString();
- netCap.mPrivateDnsBroken = in.readBoolean();
- netCap.setAdministratorUids(in.createIntArray());
- netCap.mOwnerUid = in.readInt();
- netCap.mRequestorUid = in.readInt();
- netCap.mRequestorPackageName = in.readString();
- netCap.mSubIds = new ArraySet<>();
- final int[] subIdInts = Objects.requireNonNull(in.createIntArray());
- for (int i = 0; i < subIdInts.length; i++) {
- netCap.mSubIds.add(subIdInts[i]);
- }
- return netCap;
- }
- @Override
- public NetworkCapabilities[] newArray(int size) {
- return new NetworkCapabilities[size];
- }
-
- private @Nullable <T extends Parcelable> ArraySet<T> readParcelableArraySet(Parcel in,
- @Nullable ClassLoader loader) {
- final int size = in.readInt();
- if (size < 0) {
- return null;
- }
- final ArraySet<T> result = new ArraySet<>(size);
- for (int i = 0; i < size; i++) {
- final T value = in.readParcelable(loader);
- result.add(value);
- }
- return result;
- }
- };
-
- @Override
- public @NonNull String toString() {
- final StringBuilder sb = new StringBuilder("[");
- if (0 != mTransportTypes) {
- sb.append(" Transports: ");
- appendStringRepresentationOfBitMaskToStringBuilder(sb, mTransportTypes,
- NetworkCapabilities::transportNameOf, "|");
- }
- if (0 != mNetworkCapabilities) {
- sb.append(" Capabilities: ");
- appendStringRepresentationOfBitMaskToStringBuilder(sb, mNetworkCapabilities,
- NetworkCapabilities::capabilityNameOf, "&");
- }
- if (0 != mForbiddenNetworkCapabilities) {
- sb.append(" Forbidden: ");
- appendStringRepresentationOfBitMaskToStringBuilder(sb, mForbiddenNetworkCapabilities,
- NetworkCapabilities::capabilityNameOf, "&");
- }
- if (mLinkUpBandwidthKbps > 0) {
- sb.append(" LinkUpBandwidth>=").append(mLinkUpBandwidthKbps).append("Kbps");
- }
- if (mLinkDownBandwidthKbps > 0) {
- sb.append(" LinkDnBandwidth>=").append(mLinkDownBandwidthKbps).append("Kbps");
- }
- if (mNetworkSpecifier != null) {
- sb.append(" Specifier: <").append(mNetworkSpecifier).append(">");
- }
- if (mTransportInfo != null) {
- sb.append(" TransportInfo: <").append(mTransportInfo).append(">");
- }
- if (hasSignalStrength()) {
- sb.append(" SignalStrength: ").append(mSignalStrength);
- }
-
- if (null != mUids) {
- if ((1 == mUids.size()) && (mUids.valueAt(0).count() == 1)) {
- sb.append(" Uid: ").append(mUids.valueAt(0).start);
- } else {
- sb.append(" Uids: <").append(mUids).append(">");
- }
- }
- if (mOwnerUid != Process.INVALID_UID) {
- sb.append(" OwnerUid: ").append(mOwnerUid);
- }
-
- if (mAdministratorUids != null && mAdministratorUids.length != 0) {
- sb.append(" AdminUids: ").append(Arrays.toString(mAdministratorUids));
- }
-
- if (mRequestorUid != Process.INVALID_UID) {
- sb.append(" RequestorUid: ").append(mRequestorUid);
- }
-
- if (mRequestorPackageName != null) {
- sb.append(" RequestorPkg: ").append(mRequestorPackageName);
- }
-
- if (null != mSSID) {
- sb.append(" SSID: ").append(mSSID);
- }
-
- if (mPrivateDnsBroken) {
- sb.append(" PrivateDnsBroken");
- }
-
- if (!mSubIds.isEmpty()) {
- sb.append(" SubscriptionIds: ").append(mSubIds);
- }
-
- sb.append("]");
- return sb.toString();
- }
-
-
- private interface NameOf {
- String nameOf(int value);
- }
-
- /**
- * @hide
- */
- public static void appendStringRepresentationOfBitMaskToStringBuilder(@NonNull StringBuilder sb,
- long bitMask, @NonNull NameOf nameFetcher, @NonNull String separator) {
- int bitPos = 0;
- boolean firstElementAdded = false;
- while (bitMask != 0) {
- if ((bitMask & 1) != 0) {
- if (firstElementAdded) {
- sb.append(separator);
- } else {
- firstElementAdded = true;
- }
- sb.append(nameFetcher.nameOf(bitPos));
- }
- bitMask >>= 1;
- ++bitPos;
- }
- }
-
- /**
- * @hide
- */
- public static @NonNull String capabilityNamesOf(@Nullable @NetCapability int[] capabilities) {
- StringJoiner joiner = new StringJoiner("|");
- if (capabilities != null) {
- for (int c : capabilities) {
- joiner.add(capabilityNameOf(c));
- }
- }
- return joiner.toString();
- }
-
- /**
- * @hide
- */
- public static @NonNull String capabilityNameOf(@NetCapability int capability) {
- switch (capability) {
- case NET_CAPABILITY_MMS: return "MMS";
- case NET_CAPABILITY_SUPL: return "SUPL";
- case NET_CAPABILITY_DUN: return "DUN";
- case NET_CAPABILITY_FOTA: return "FOTA";
- case NET_CAPABILITY_IMS: return "IMS";
- case NET_CAPABILITY_CBS: return "CBS";
- case NET_CAPABILITY_WIFI_P2P: return "WIFI_P2P";
- case NET_CAPABILITY_IA: return "IA";
- case NET_CAPABILITY_RCS: return "RCS";
- case NET_CAPABILITY_XCAP: return "XCAP";
- case NET_CAPABILITY_EIMS: return "EIMS";
- case NET_CAPABILITY_NOT_METERED: return "NOT_METERED";
- case NET_CAPABILITY_INTERNET: return "INTERNET";
- case NET_CAPABILITY_NOT_RESTRICTED: return "NOT_RESTRICTED";
- case NET_CAPABILITY_TRUSTED: return "TRUSTED";
- case NET_CAPABILITY_NOT_VPN: return "NOT_VPN";
- case NET_CAPABILITY_VALIDATED: return "VALIDATED";
- case NET_CAPABILITY_CAPTIVE_PORTAL: return "CAPTIVE_PORTAL";
- case NET_CAPABILITY_NOT_ROAMING: return "NOT_ROAMING";
- case NET_CAPABILITY_FOREGROUND: return "FOREGROUND";
- case NET_CAPABILITY_NOT_CONGESTED: return "NOT_CONGESTED";
- case NET_CAPABILITY_NOT_SUSPENDED: return "NOT_SUSPENDED";
- case NET_CAPABILITY_OEM_PAID: return "OEM_PAID";
- case NET_CAPABILITY_MCX: return "MCX";
- case NET_CAPABILITY_PARTIAL_CONNECTIVITY: return "PARTIAL_CONNECTIVITY";
- case NET_CAPABILITY_TEMPORARILY_NOT_METERED: return "TEMPORARILY_NOT_METERED";
- case NET_CAPABILITY_OEM_PRIVATE: return "OEM_PRIVATE";
- case NET_CAPABILITY_VEHICLE_INTERNAL: return "VEHICLE_INTERNAL";
- case NET_CAPABILITY_NOT_VCN_MANAGED: return "NOT_VCN_MANAGED";
- case NET_CAPABILITY_ENTERPRISE: return "ENTERPRISE";
- case NET_CAPABILITY_VSIM: return "VSIM";
- case NET_CAPABILITY_BIP: return "BIP";
- case NET_CAPABILITY_HEAD_UNIT: return "HEAD_UNIT";
- default: return Integer.toString(capability);
- }
- }
-
- /**
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static @NonNull String transportNamesOf(@Nullable @Transport int[] types) {
- StringJoiner joiner = new StringJoiner("|");
- if (types != null) {
- for (int t : types) {
- joiner.add(transportNameOf(t));
- }
- }
- return joiner.toString();
- }
-
- /**
- * @hide
- */
- public static @NonNull String transportNameOf(@Transport int transport) {
- if (!isValidTransport(transport)) {
- return "UNKNOWN";
- }
- return TRANSPORT_NAMES[transport];
- }
-
- private static void checkValidTransportType(@Transport int transport) {
- if (!isValidTransport(transport)) {
- throw new IllegalArgumentException("Invalid TransportType " + transport);
- }
- }
-
- private static boolean isValidCapability(@NetworkCapabilities.NetCapability int capability) {
- return capability >= MIN_NET_CAPABILITY && capability <= MAX_NET_CAPABILITY;
- }
-
- private static void checkValidCapability(@NetworkCapabilities.NetCapability int capability) {
- if (!isValidCapability(capability)) {
- throw new IllegalArgumentException("NetworkCapability " + capability + "out of range");
- }
- }
-
- /**
- * Check if this {@code NetworkCapability} instance is metered.
- *
- * @return {@code true} if {@code NET_CAPABILITY_NOT_METERED} is not set on this instance.
- * @hide
- */
- public boolean isMetered() {
- return !hasCapability(NET_CAPABILITY_NOT_METERED);
- }
-
- /**
- * Check if private dns is broken.
- *
- * @return {@code true} if private DNS is broken on this network.
- * @hide
- */
- @SystemApi
- public boolean isPrivateDnsBroken() {
- return mPrivateDnsBroken;
- }
-
- /**
- * Set mPrivateDnsBroken to true when private dns is broken.
- *
- * @param broken the status of private DNS to be set.
- * @hide
- */
- public void setPrivateDnsBroken(boolean broken) {
- mPrivateDnsBroken = broken;
- }
-
- private boolean equalsPrivateDnsBroken(NetworkCapabilities nc) {
- return mPrivateDnsBroken == nc.mPrivateDnsBroken;
- }
-
- /**
- * Set the UID of the app making the request.
- *
- * For instances of NetworkCapabilities representing a request, sets the
- * UID of the app making the request. For a network created by the system,
- * sets the UID of the only app whose requests can match this network.
- * This can be set to {@link Process#INVALID_UID} if there is no such app,
- * or if this instance of NetworkCapabilities is about to be sent to a
- * party that should not learn about this.
- *
- * @param uid UID of the app.
- * @hide
- */
- public @NonNull NetworkCapabilities setRequestorUid(int uid) {
- mRequestorUid = uid;
- return this;
- }
-
- /**
- * Returns the UID of the app making the request.
- *
- * For a NetworkRequest being made by an app, contains the app's UID. For a network
- * created by the system, contains the UID of the only app whose requests can match
- * this network, or {@link Process#INVALID_UID} if none or if the
- * caller does not have permission to learn about this.
- *
- * @return the uid of the app making the request.
- * @hide
- */
- public int getRequestorUid() {
- return mRequestorUid;
- }
-
- /**
- * Set the package name of the app making the request.
- *
- * For instances of NetworkCapabilities representing a request, sets the
- * package name of the app making the request. For a network created by the system,
- * sets the package name of the only app whose requests can match this network.
- * This can be set to null if there is no such app, or if this instance of
- * NetworkCapabilities is about to be sent to a party that should not learn about this.
- *
- * @param packageName package name of the app.
- * @hide
- */
- public @NonNull NetworkCapabilities setRequestorPackageName(@NonNull String packageName) {
- mRequestorPackageName = packageName;
- return this;
- }
-
- /**
- * Returns the package name of the app making the request.
- *
- * For a NetworkRequest being made by an app, contains the app's package name. For a
- * network created by the system, contains the package name of the only app whose
- * requests can match this network, or null if none or if the caller does not have
- * permission to learn about this.
- *
- * @return the package name of the app making the request.
- * @hide
- */
- @Nullable
- public String getRequestorPackageName() {
- return mRequestorPackageName;
- }
-
- /**
- * Set the uid and package name of the app causing this network to exist.
- *
- * {@see #setRequestorUid} and {@link #setRequestorPackageName}
- *
- * @param uid UID of the app.
- * @param packageName package name of the app.
- * @hide
- */
- public @NonNull NetworkCapabilities setRequestorUidAndPackageName(
- int uid, @NonNull String packageName) {
- return setRequestorUid(uid).setRequestorPackageName(packageName);
- }
-
- /**
- * Test whether the passed NetworkCapabilities satisfies the requestor restrictions of this
- * capabilities.
- *
- * This method is called on the NetworkCapabilities embedded in a request with the
- * capabilities of an available network. If the available network, sets a specific
- * requestor (by uid and optionally package name), then this will only match a request from the
- * same app. If either of the capabilities have an unset uid or package name, then it matches
- * everything.
- * <p>
- * nc is assumed nonnull. Else, NPE.
- */
- private boolean satisfiedByRequestor(NetworkCapabilities nc) {
- // No uid set, matches everything.
- if (mRequestorUid == Process.INVALID_UID || nc.mRequestorUid == Process.INVALID_UID) {
- return true;
- }
- // uids don't match.
- if (mRequestorUid != nc.mRequestorUid) return false;
- // No package names set, matches everything
- if (null == nc.mRequestorPackageName || null == mRequestorPackageName) return true;
- // check for package name match.
- return TextUtils.equals(mRequestorPackageName, nc.mRequestorPackageName);
- }
-
- /**
- * Combine requestor info of the capabilities.
- * <p>
- * This is only legal if either the requestor info of this object is reset, or both info are
- * equal.
- * nc is assumed nonnull.
- */
- private void combineRequestor(@NonNull NetworkCapabilities nc) {
- if (mRequestorUid != Process.INVALID_UID && mRequestorUid != nc.mOwnerUid) {
- throw new IllegalStateException("Can't combine two uids");
- }
- if (mRequestorPackageName != null
- && !mRequestorPackageName.equals(nc.mRequestorPackageName)) {
- throw new IllegalStateException("Can't combine two package names");
- }
- setRequestorUid(nc.mRequestorUid);
- setRequestorPackageName(nc.mRequestorPackageName);
- }
-
- private boolean equalsRequestor(NetworkCapabilities nc) {
- return mRequestorUid == nc.mRequestorUid
- && TextUtils.equals(mRequestorPackageName, nc.mRequestorPackageName);
- }
-
- /**
- * Set of the subscription IDs that identifies the network or request, empty if none.
- */
- @NonNull
- private ArraySet<Integer> mSubIds = new ArraySet<>();
-
- /**
- * Sets the subscription ID set that associated to this network or request.
- *
- * @hide
- */
- @NonNull
- public NetworkCapabilities setSubscriptionIds(@NonNull Set<Integer> subIds) {
- mSubIds = new ArraySet(Objects.requireNonNull(subIds));
- return this;
- }
-
- /**
- * Gets the subscription ID set that associated to this network or request.
- *
- * <p>Instances of NetworkCapabilities will only have this field populated by the system if the
- * receiver holds the NETWORK_FACTORY permission. In all other cases, it will be the empty set.
- *
- * @return
- * @hide
- */
- @NonNull
- @SystemApi
- public Set<Integer> getSubscriptionIds() {
- return new ArraySet<>(mSubIds);
- }
-
- /**
- * Tests if the subscription ID set of this network is the same as that of the passed one.
- */
- private boolean equalsSubscriptionIds(@NonNull NetworkCapabilities nc) {
- return Objects.equals(mSubIds, nc.mSubIds);
- }
-
- /**
- * Check if the subscription ID set requirements of this object are matched by the passed one.
- * If specified in the request, the passed one need to have at least one subId and at least
- * one of them needs to be in the request set.
- */
- private boolean satisfiedBySubscriptionIds(@NonNull NetworkCapabilities nc) {
- if (mSubIds.isEmpty()) return true;
- if (nc.mSubIds.isEmpty()) return false;
- for (final Integer subId : nc.mSubIds) {
- if (mSubIds.contains(subId)) return true;
- }
- return false;
- }
-
- /**
- * Combine subscription ID set of the capabilities.
- *
- * <p>This is only legal if the subscription Ids are equal.
- *
- * <p>If both subscription IDs are not equal, they belong to different subscription
- * (or no subscription). In this case, it would not make sense to add them together.
- */
- private void combineSubscriptionIds(@NonNull NetworkCapabilities nc) {
- if (!Objects.equals(mSubIds, nc.mSubIds)) {
- throw new IllegalStateException("Can't combine two subscription ID sets");
- }
- }
-
- /**
- * Returns a bitmask of all the applicable redactions (based on the permissions held by the
- * receiving app) to be performed on this object.
- *
- * @return bitmask of redactions applicable on this instance.
- * @hide
- */
- public @RedactionType long getApplicableRedactions() {
- // Currently, there are no fields redacted in NetworkCapabilities itself, so we just
- // passthrough the redactions required by the embedded TransportInfo. If this changes
- // in the future, modify this method.
- if (mTransportInfo == null) {
- return NetworkCapabilities.REDACT_NONE;
- }
- return mTransportInfo.getApplicableRedactions();
- }
-
- private NetworkCapabilities removeDefaultCapabilites() {
- mNetworkCapabilities &= ~DEFAULT_CAPABILITIES;
- return this;
- }
-
- /**
- * Builder class for NetworkCapabilities.
- *
- * This class is mainly for for {@link NetworkAgent} instances to use. Many fields in
- * the built class require holding a signature permission to use - mostly
- * {@link android.Manifest.permission.NETWORK_FACTORY}, but refer to the specific
- * description of each setter. As this class lives entirely in app space it does not
- * enforce these restrictions itself but the system server clears out the relevant
- * fields when receiving a NetworkCapabilities object from a caller without the
- * appropriate permission.
- *
- * Apps don't use this builder directly. Instead, they use {@link NetworkRequest} via
- * its builder object.
- *
- * @hide
- */
- @SystemApi
- public static final class Builder {
- private final NetworkCapabilities mCaps;
-
- /**
- * Creates a new Builder to construct NetworkCapabilities objects.
- */
- public Builder() {
- mCaps = new NetworkCapabilities();
- }
-
- /**
- * Creates a new Builder of NetworkCapabilities from an existing instance.
- */
- public Builder(@NonNull final NetworkCapabilities nc) {
- Objects.requireNonNull(nc);
- mCaps = new NetworkCapabilities(nc);
- }
-
- /**
- * Creates a new Builder without the default capabilities.
- */
- @NonNull
- public static Builder withoutDefaultCapabilities() {
- final NetworkCapabilities nc = new NetworkCapabilities();
- nc.removeDefaultCapabilites();
- return new Builder(nc);
- }
-
- /**
- * Adds the given transport type.
- *
- * Multiple transports may be added. Note that when searching for a network to satisfy a
- * request, satisfying any of the transports listed in the request will satisfy the request.
- * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a
- * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network
- * to be selected. This is logically different than
- * {@code NetworkCapabilities.NET_CAPABILITY_*}. Also note that multiple networks with the
- * same transport type may be active concurrently.
- *
- * @param transportType the transport type to be added or removed.
- * @return this builder
- */
- @NonNull
- public Builder addTransportType(@Transport int transportType) {
- checkValidTransportType(transportType);
- mCaps.addTransportType(transportType);
- return this;
- }
-
- /**
- * Removes the given transport type.
- *
- * {@see #addTransportType}.
- *
- * @param transportType the transport type to be added or removed.
- * @return this builder
- */
- @NonNull
- public Builder removeTransportType(@Transport int transportType) {
- checkValidTransportType(transportType);
- mCaps.removeTransportType(transportType);
- return this;
- }
-
- /**
- * Adds the given capability.
- *
- * @param capability the capability
- * @return this builder
- */
- @NonNull
- public Builder addCapability(@NetCapability final int capability) {
- mCaps.setCapability(capability, true);
- return this;
- }
-
- /**
- * Removes the given capability.
- *
- * @param capability the capability
- * @return this builder
- */
- @NonNull
- public Builder removeCapability(@NetCapability final int capability) {
- mCaps.setCapability(capability, false);
- return this;
- }
-
- /**
- * Sets the owner UID.
- *
- * The default value is {@link Process#INVALID_UID}. Pass this value to reset.
- *
- * Note: for security the system will clear out this field when received from a
- * non-privileged source.
- *
- * @param ownerUid the owner UID
- * @return this builder
- */
- @NonNull
- @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
- public Builder setOwnerUid(final int ownerUid) {
- mCaps.setOwnerUid(ownerUid);
- return this;
- }
-
- /**
- * Sets the list of UIDs that are administrators of this network.
- *
- * <p>UIDs included in administratorUids gain administrator privileges over this
- * Network. Examples of UIDs that should be included in administratorUids are:
- * <ul>
- * <li>Carrier apps with privileges for the relevant subscription
- * <li>Active VPN apps
- * <li>Other application groups with a particular Network-related role
- * </ul>
- *
- * <p>In general, user-supplied networks (such as WiFi networks) do not have
- * administrators.
- *
- * <p>An app is granted owner privileges over Networks that it supplies. The owner
- * UID MUST always be included in administratorUids.
- *
- * The default value is the empty array. Pass an empty array to reset.
- *
- * Note: for security the system will clear out this field when received from a
- * non-privileged source, such as an app using reflection to call this or
- * mutate the member in the built object.
- *
- * @param administratorUids the UIDs to be set as administrators of this Network.
- * @return this builder
- */
- @NonNull
- @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
- public Builder setAdministratorUids(@NonNull final int[] administratorUids) {
- Objects.requireNonNull(administratorUids);
- mCaps.setAdministratorUids(administratorUids);
- return this;
- }
-
- /**
- * Sets the upstream bandwidth of the link.
- *
- * Sets the upstream bandwidth for this network in Kbps. This always only refers to
- * the estimated first hop transport bandwidth.
- * <p>
- * Note that when used to request a network, this specifies the minimum acceptable.
- * When received as the state of an existing network this specifies the typical
- * first hop bandwidth expected. This is never measured, but rather is inferred
- * from technology type and other link parameters. It could be used to differentiate
- * between very slow 1xRTT cellular links and other faster networks or even between
- * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between
- * fast backhauls and slow backhauls.
- *
- * @param upKbps the estimated first hop upstream (device to network) bandwidth.
- * @return this builder
- */
- @NonNull
- public Builder setLinkUpstreamBandwidthKbps(final int upKbps) {
- mCaps.setLinkUpstreamBandwidthKbps(upKbps);
- return this;
- }
-
- /**
- * Sets the downstream bandwidth for this network in Kbps. This always only refers to
- * the estimated first hop transport bandwidth.
- * <p>
- * Note that when used to request a network, this specifies the minimum acceptable.
- * When received as the state of an existing network this specifies the typical
- * first hop bandwidth expected. This is never measured, but rather is inferred
- * from technology type and other link parameters. It could be used to differentiate
- * between very slow 1xRTT cellular links and other faster networks or even between
- * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between
- * fast backhauls and slow backhauls.
- *
- * @param downKbps the estimated first hop downstream (network to device) bandwidth.
- * @return this builder
- */
- @NonNull
- public Builder setLinkDownstreamBandwidthKbps(final int downKbps) {
- mCaps.setLinkDownstreamBandwidthKbps(downKbps);
- return this;
- }
-
- /**
- * Sets the optional bearer specific network specifier.
- * This has no meaning if a single transport is also not specified, so calling
- * this without a single transport set will generate an exception, as will
- * subsequently adding or removing transports after this is set.
- * </p>
- *
- * @param specifier a concrete, parcelable framework class that extends NetworkSpecifier,
- * or null to clear it.
- * @return this builder
- */
- @NonNull
- public Builder setNetworkSpecifier(@Nullable final NetworkSpecifier specifier) {
- mCaps.setNetworkSpecifier(specifier);
- return this;
- }
-
- /**
- * Sets the optional transport specific information.
- *
- * @param info A concrete, parcelable framework class that extends {@link TransportInfo},
- * or null to clear it.
- * @return this builder
- */
- @NonNull
- public Builder setTransportInfo(@Nullable final TransportInfo info) {
- mCaps.setTransportInfo(info);
- return this;
- }
-
- /**
- * Sets the signal strength. This is a signed integer, with higher values indicating a
- * stronger signal. The exact units are bearer-dependent. For example, Wi-Fi uses the
- * same RSSI units reported by wifi code.
- * <p>
- * Note that when used to register a network callback, this specifies the minimum
- * acceptable signal strength. When received as the state of an existing network it
- * specifies the current value. A value of code SIGNAL_STRENGTH_UNSPECIFIED} means
- * no value when received and has no effect when requesting a callback.
- *
- * Note: for security the system will throw if it receives a NetworkRequest where
- * the underlying NetworkCapabilities has this member set from a source that does
- * not hold the {@link android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP}
- * permission. Apps with this permission can use this indirectly through
- * {@link android.net.NetworkRequest}.
- *
- * @param signalStrength the bearer-specific signal strength.
- * @return this builder
- */
- @NonNull
- @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP)
- public Builder setSignalStrength(final int signalStrength) {
- mCaps.setSignalStrength(signalStrength);
- return this;
- }
-
- /**
- * Sets the SSID of this network.
- *
- * Note: for security the system will clear out this field when received from a
- * non-privileged source, like an app using reflection to set this.
- *
- * @param ssid the SSID, or null to clear it.
- * @return this builder
- */
- @NonNull
- @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
- public Builder setSsid(@Nullable final String ssid) {
- mCaps.setSSID(ssid);
- return this;
- }
-
- /**
- * Set the uid of the app causing this network to exist.
- *
- * Note: for security the system will clear out this field when received from a
- * non-privileged source.
- *
- * @param uid UID of the app.
- * @return this builder
- */
- @NonNull
- @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
- public Builder setRequestorUid(final int uid) {
- mCaps.setRequestorUid(uid);
- return this;
- }
-
- /**
- * Set the package name of the app causing this network to exist.
- *
- * Note: for security the system will clear out this field when received from a
- * non-privileged source.
- *
- * @param packageName package name of the app, or null to clear it.
- * @return this builder
- */
- @NonNull
- @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
- public Builder setRequestorPackageName(@Nullable final String packageName) {
- mCaps.setRequestorPackageName(packageName);
- return this;
- }
-
- /**
- * Set the subscription ID set.
- *
- * <p>SubIds are populated in NetworkCapability instances from the system only for callers
- * that hold the NETWORK_FACTORY permission. Similarly, the system will reject any
- * NetworkRequests filed with a non-empty set of subIds unless the caller holds the
- * NETWORK_FACTORY permission.
- *
- * @param subIds a set that represent the subscription IDs. Empty if clean up.
- * @return this builder.
- * @hide
- */
- @NonNull
- @SystemApi
- public Builder setSubscriptionIds(@NonNull final Set<Integer> subIds) {
- mCaps.setSubscriptionIds(subIds);
- return this;
- }
-
- /**
- * Set the list of UIDs this network applies to.
- *
- * @param uids the list of UIDs this network applies to, or {@code null} if this network
- * applies to all UIDs.
- * @return this builder
- * @hide
- */
- @NonNull
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public Builder setUids(@Nullable Set<Range<Integer>> uids) {
- mCaps.setUids(uids);
- return this;
- }
-
- /**
- * Builds the instance of the capabilities.
- *
- * @return the built instance of NetworkCapabilities.
- */
- @NonNull
- public NetworkCapabilities build() {
- if (mCaps.getOwnerUid() != Process.INVALID_UID) {
- if (!CollectionUtils.contains(mCaps.getAdministratorUids(), mCaps.getOwnerUid())) {
- throw new IllegalStateException("The owner UID must be included in "
- + " administrator UIDs.");
- }
- }
- return new NetworkCapabilities(mCaps);
- }
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkConfig.java b/packages/Connectivity/framework/src/android/net/NetworkConfig.java
deleted file mode 100644
index 32a2cda..0000000
--- a/packages/Connectivity/framework/src/android/net/NetworkConfig.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import java.util.Locale;
-
-/**
- * Describes the buildtime configuration of a network.
- * Holds settings read from resources.
- * @hide
- */
-public class NetworkConfig {
- /**
- * Human readable string
- */
- public String name;
-
- /**
- * Type from ConnectivityManager
- */
- public int type;
-
- /**
- * the radio number from radio attributes config
- */
- public int radio;
-
- /**
- * higher number == higher priority when turning off connections
- */
- public int priority;
-
- /**
- * indicates the boot time dependencyMet setting
- */
- public boolean dependencyMet;
-
- /**
- * indicates the default restoral timer in seconds
- * if the network is used as a special network feature
- * -1 indicates no restoration of default
- */
- public int restoreTime;
-
- /**
- * input string from config.xml resource. Uses the form:
- * [Connection name],[ConnectivityManager connection type],
- * [associated radio-type],[priority],[dependencyMet]
- */
- public NetworkConfig(String init) {
- String fragments[] = init.split(",");
- name = fragments[0].trim().toLowerCase(Locale.ROOT);
- type = Integer.parseInt(fragments[1]);
- radio = Integer.parseInt(fragments[2]);
- priority = Integer.parseInt(fragments[3]);
- restoreTime = Integer.parseInt(fragments[4]);
- dependencyMet = Boolean.parseBoolean(fragments[5]);
- }
-
- /**
- * Indicates if this network is supposed to be default-routable
- */
- public boolean isDefault() {
- return (type == radio);
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkInfo.java b/packages/Connectivity/framework/src/android/net/NetworkInfo.java
deleted file mode 100644
index bb23494..0000000
--- a/packages/Connectivity/framework/src/android/net/NetworkInfo.java
+++ /dev/null
@@ -1,625 +0,0 @@
-/*
- * 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.
- */
-
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.EnumMap;
-
-/**
- * Describes the status of a network interface.
- * <p>Use {@link ConnectivityManager#getActiveNetworkInfo()} to get an instance that represents
- * the current network connection.
- *
- * @deprecated Callers should instead use the {@link ConnectivityManager.NetworkCallback} API to
- * learn about connectivity changes, or switch to use
- * {@link ConnectivityManager#getNetworkCapabilities} or
- * {@link ConnectivityManager#getLinkProperties} to get information synchronously. Keep
- * in mind that while callbacks are guaranteed to be called for every event in order,
- * synchronous calls have no such constraints, and as such it is unadvisable to use the
- * synchronous methods inside the callbacks as they will often not offer a view of
- * networking that is consistent (that is: they may return a past or a future state with
- * respect to the event being processed by the callback). Instead, callers are advised
- * to only use the arguments of the callbacks, possibly memorizing the specific bits of
- * information they need to keep from one callback to another.
- */
-@Deprecated
-public class NetworkInfo implements Parcelable {
-
- /**
- * Coarse-grained network state. This is probably what most applications should
- * use, rather than {@link android.net.NetworkInfo.DetailedState DetailedState}.
- * The mapping between the two is as follows:
- * <br/><br/>
- * <table>
- * <tr><td><b>Detailed state</b></td><td><b>Coarse-grained state</b></td></tr>
- * <tr><td><code>IDLE</code></td><td><code>DISCONNECTED</code></td></tr>
- * <tr><td><code>SCANNING</code></td><td><code>DISCONNECTED</code></td></tr>
- * <tr><td><code>CONNECTING</code></td><td><code>CONNECTING</code></td></tr>
- * <tr><td><code>AUTHENTICATING</code></td><td><code>CONNECTING</code></td></tr>
- * <tr><td><code>OBTAINING_IPADDR</code></td><td><code>CONNECTING</code></td></tr>
- * <tr><td><code>VERIFYING_POOR_LINK</code></td><td><code>CONNECTING</code></td></tr>
- * <tr><td><code>CAPTIVE_PORTAL_CHECK</code></td><td><code>CONNECTING</code></td></tr>
- * <tr><td><code>CONNECTED</code></td><td><code>CONNECTED</code></td></tr>
- * <tr><td><code>SUSPENDED</code></td><td><code>SUSPENDED</code></td></tr>
- * <tr><td><code>DISCONNECTING</code></td><td><code>DISCONNECTING</code></td></tr>
- * <tr><td><code>DISCONNECTED</code></td><td><code>DISCONNECTED</code></td></tr>
- * <tr><td><code>FAILED</code></td><td><code>DISCONNECTED</code></td></tr>
- * <tr><td><code>BLOCKED</code></td><td><code>DISCONNECTED</code></td></tr>
- * </table>
- *
- * @deprecated See {@link NetworkInfo}.
- */
- @Deprecated
- public enum State {
- CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING, DISCONNECTED, UNKNOWN
- }
-
- /**
- * The fine-grained state of a network connection. This level of detail
- * is probably of interest to few applications. Most should use
- * {@link android.net.NetworkInfo.State State} instead.
- *
- * @deprecated See {@link NetworkInfo}.
- */
- @Deprecated
- public enum DetailedState {
- /** Ready to start data connection setup. */
- IDLE,
- /** Searching for an available access point. */
- SCANNING,
- /** Currently setting up data connection. */
- CONNECTING,
- /** Network link established, performing authentication. */
- AUTHENTICATING,
- /** Awaiting response from DHCP server in order to assign IP address information. */
- OBTAINING_IPADDR,
- /** IP traffic should be available. */
- CONNECTED,
- /** IP traffic is suspended */
- SUSPENDED,
- /** Currently tearing down data connection. */
- DISCONNECTING,
- /** IP traffic not available. */
- DISCONNECTED,
- /** Attempt to connect failed. */
- FAILED,
- /** Access to this network is blocked. */
- BLOCKED,
- /** Link has poor connectivity. */
- VERIFYING_POOR_LINK,
- /** Checking if network is a captive portal */
- CAPTIVE_PORTAL_CHECK
- }
-
- /**
- * This is the map described in the Javadoc comment above. The positions
- * of the elements of the array must correspond to the ordinal values
- * of <code>DetailedState</code>.
- */
- private static final EnumMap<DetailedState, State> stateMap =
- new EnumMap<DetailedState, State>(DetailedState.class);
-
- static {
- stateMap.put(DetailedState.IDLE, State.DISCONNECTED);
- stateMap.put(DetailedState.SCANNING, State.DISCONNECTED);
- stateMap.put(DetailedState.CONNECTING, State.CONNECTING);
- stateMap.put(DetailedState.AUTHENTICATING, State.CONNECTING);
- stateMap.put(DetailedState.OBTAINING_IPADDR, State.CONNECTING);
- stateMap.put(DetailedState.VERIFYING_POOR_LINK, State.CONNECTING);
- stateMap.put(DetailedState.CAPTIVE_PORTAL_CHECK, State.CONNECTING);
- stateMap.put(DetailedState.CONNECTED, State.CONNECTED);
- stateMap.put(DetailedState.SUSPENDED, State.SUSPENDED);
- stateMap.put(DetailedState.DISCONNECTING, State.DISCONNECTING);
- stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED);
- stateMap.put(DetailedState.FAILED, State.DISCONNECTED);
- stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED);
- }
-
- private int mNetworkType;
- private int mSubtype;
- private String mTypeName;
- private String mSubtypeName;
- @NonNull
- private State mState;
- @NonNull
- private DetailedState mDetailedState;
- private String mReason;
- private String mExtraInfo;
- private boolean mIsFailover;
- private boolean mIsAvailable;
- private boolean mIsRoaming;
-
- /**
- * Create a new instance of NetworkInfo.
- *
- * This may be useful for apps to write unit tests.
- *
- * @param type the legacy type of the network, as one of the ConnectivityManager.TYPE_*
- * constants.
- * @param subtype the subtype if applicable, as one of the TelephonyManager.NETWORK_TYPE_*
- * constants.
- * @param typeName a human-readable string for the network type, or an empty string or null.
- * @param subtypeName a human-readable string for the subtype, or an empty string or null.
- */
- public NetworkInfo(int type, int subtype,
- @Nullable String typeName, @Nullable String subtypeName) {
- if (!ConnectivityManager.isNetworkTypeValid(type)
- && type != ConnectivityManager.TYPE_NONE) {
- throw new IllegalArgumentException("Invalid network type: " + type);
- }
- mNetworkType = type;
- mSubtype = subtype;
- mTypeName = typeName;
- mSubtypeName = subtypeName;
- setDetailedState(DetailedState.IDLE, null, null);
- mState = State.UNKNOWN;
- }
-
- /** {@hide} */
- @UnsupportedAppUsage
- public NetworkInfo(NetworkInfo source) {
- if (source != null) {
- synchronized (source) {
- mNetworkType = source.mNetworkType;
- mSubtype = source.mSubtype;
- mTypeName = source.mTypeName;
- mSubtypeName = source.mSubtypeName;
- mState = source.mState;
- mDetailedState = source.mDetailedState;
- mReason = source.mReason;
- mExtraInfo = source.mExtraInfo;
- mIsFailover = source.mIsFailover;
- mIsAvailable = source.mIsAvailable;
- mIsRoaming = source.mIsRoaming;
- }
- }
- }
-
- /**
- * Reports the type of network to which the
- * info in this {@code NetworkInfo} pertains.
- * @return one of {@link ConnectivityManager#TYPE_MOBILE}, {@link
- * ConnectivityManager#TYPE_WIFI}, {@link ConnectivityManager#TYPE_WIMAX}, {@link
- * ConnectivityManager#TYPE_ETHERNET}, {@link ConnectivityManager#TYPE_BLUETOOTH}, or other
- * types defined by {@link ConnectivityManager}.
- * @deprecated Callers should switch to checking {@link NetworkCapabilities#hasTransport}
- * instead with one of the NetworkCapabilities#TRANSPORT_* constants :
- * {@link #getType} and {@link #getTypeName} cannot account for networks using
- * multiple transports. Note that generally apps should not care about transport;
- * {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} and
- * {@link NetworkCapabilities#getLinkDownstreamBandwidthKbps} are calls that
- * apps concerned with meteredness or bandwidth should be looking at, as they
- * offer this information with much better accuracy.
- */
- @Deprecated
- public int getType() {
- synchronized (this) {
- return mNetworkType;
- }
- }
-
- /**
- * @deprecated Use {@link NetworkCapabilities} instead
- * @hide
- */
- @Deprecated
- public void setType(int type) {
- synchronized (this) {
- mNetworkType = type;
- }
- }
-
- /**
- * Return a network-type-specific integer describing the subtype
- * of the network.
- * @return the network subtype
- * @deprecated Use {@link android.telephony.TelephonyManager#getDataNetworkType} instead.
- */
- @Deprecated
- public int getSubtype() {
- synchronized (this) {
- return mSubtype;
- }
- }
-
- /**
- * @hide
- */
- @UnsupportedAppUsage
- public void setSubtype(int subtype, String subtypeName) {
- synchronized (this) {
- mSubtype = subtype;
- mSubtypeName = subtypeName;
- }
- }
-
- /**
- * Return a human-readable name describe the type of the network,
- * for example "WIFI" or "MOBILE".
- * @return the name of the network type
- * @deprecated Callers should switch to checking {@link NetworkCapabilities#hasTransport}
- * instead with one of the NetworkCapabilities#TRANSPORT_* constants :
- * {@link #getType} and {@link #getTypeName} cannot account for networks using
- * multiple transports. Note that generally apps should not care about transport;
- * {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} and
- * {@link NetworkCapabilities#getLinkDownstreamBandwidthKbps} are calls that
- * apps concerned with meteredness or bandwidth should be looking at, as they
- * offer this information with much better accuracy.
- */
- @Deprecated
- public String getTypeName() {
- synchronized (this) {
- return mTypeName;
- }
- }
-
- /**
- * Return a human-readable name describing the subtype of the network.
- * @return the name of the network subtype
- * @deprecated Use {@link android.telephony.TelephonyManager#getDataNetworkType} instead.
- */
- @Deprecated
- public String getSubtypeName() {
- synchronized (this) {
- return mSubtypeName;
- }
- }
-
- /**
- * Indicates whether network connectivity exists or is in the process
- * of being established. This is good for applications that need to
- * do anything related to the network other than read or write data.
- * For the latter, call {@link #isConnected()} instead, which guarantees
- * that the network is fully usable.
- * @return {@code true} if network connectivity exists or is in the process
- * of being established, {@code false} otherwise.
- * @deprecated Apps should instead use the
- * {@link android.net.ConnectivityManager.NetworkCallback} API to
- * learn about connectivity changes.
- * {@link ConnectivityManager#registerDefaultNetworkCallback} and
- * {@link ConnectivityManager#registerNetworkCallback}. These will
- * give a more accurate picture of the connectivity state of
- * the device and let apps react more easily and quickly to changes.
- */
- @Deprecated
- public boolean isConnectedOrConnecting() {
- synchronized (this) {
- return mState == State.CONNECTED || mState == State.CONNECTING;
- }
- }
-
- /**
- * Indicates whether network connectivity exists and it is possible to establish
- * connections and pass data.
- * <p>Always call this before attempting to perform data transactions.
- * @return {@code true} if network connectivity exists, {@code false} otherwise.
- * @deprecated Apps should instead use the
- * {@link android.net.ConnectivityManager.NetworkCallback} API to
- * learn about connectivity changes. See
- * {@link ConnectivityManager#registerDefaultNetworkCallback} and
- * {@link ConnectivityManager#registerNetworkCallback}. These will
- * give a more accurate picture of the connectivity state of
- * the device and let apps react more easily and quickly to changes.
- */
- @Deprecated
- public boolean isConnected() {
- synchronized (this) {
- return mState == State.CONNECTED;
- }
- }
-
- /**
- * Indicates whether network connectivity is possible. A network is unavailable
- * when a persistent or semi-persistent condition prevents the possibility
- * of connecting to that network. Examples include
- * <ul>
- * <li>The device is out of the coverage area for any network of this type.</li>
- * <li>The device is on a network other than the home network (i.e., roaming), and
- * data roaming has been disabled.</li>
- * <li>The device's radio is turned off, e.g., because airplane mode is enabled.</li>
- * </ul>
- * Since Android L, this always returns {@code true}, because the system only
- * returns info for available networks.
- * @return {@code true} if the network is available, {@code false} otherwise
- * @deprecated Apps should instead use the
- * {@link android.net.ConnectivityManager.NetworkCallback} API to
- * learn about connectivity changes.
- * {@link ConnectivityManager#registerDefaultNetworkCallback} and
- * {@link ConnectivityManager#registerNetworkCallback}. These will
- * give a more accurate picture of the connectivity state of
- * the device and let apps react more easily and quickly to changes.
- */
- @Deprecated
- public boolean isAvailable() {
- synchronized (this) {
- return mIsAvailable;
- }
- }
-
- /**
- * Sets if the network is available, ie, if the connectivity is possible.
- * @param isAvailable the new availability value.
- * @deprecated Use {@link NetworkCapabilities} instead
- *
- * @hide
- */
- @Deprecated
- @UnsupportedAppUsage
- public void setIsAvailable(boolean isAvailable) {
- synchronized (this) {
- mIsAvailable = isAvailable;
- }
- }
-
- /**
- * Indicates whether the current attempt to connect to the network
- * resulted from the ConnectivityManager trying to fail over to this
- * network following a disconnect from another network.
- * @return {@code true} if this is a failover attempt, {@code false}
- * otherwise.
- * @deprecated This field is not populated in recent Android releases,
- * and does not make a lot of sense in a multi-network world.
- */
- @Deprecated
- public boolean isFailover() {
- synchronized (this) {
- return mIsFailover;
- }
- }
-
- /**
- * Set the failover boolean.
- * @param isFailover {@code true} to mark the current connection attempt
- * as a failover.
- * @deprecated This hasn't been set in any recent Android release.
- * @hide
- */
- @Deprecated
- @UnsupportedAppUsage
- public void setFailover(boolean isFailover) {
- synchronized (this) {
- mIsFailover = isFailover;
- }
- }
-
- /**
- * Indicates whether the device is currently roaming on this network. When
- * {@code true}, it suggests that use of data on this network may incur
- * extra costs.
- *
- * @return {@code true} if roaming is in effect, {@code false} otherwise.
- * @deprecated Callers should switch to checking
- * {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING}
- * instead, since that handles more complex situations, such as
- * VPNs.
- */
- @Deprecated
- public boolean isRoaming() {
- synchronized (this) {
- return mIsRoaming;
- }
- }
-
- /**
- * @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING} instead.
- * {@hide}
- */
- @VisibleForTesting
- @Deprecated
- @UnsupportedAppUsage
- public void setRoaming(boolean isRoaming) {
- synchronized (this) {
- mIsRoaming = isRoaming;
- }
- }
-
- /**
- * Reports the current coarse-grained state of the network.
- * @return the coarse-grained state
- * @deprecated Apps should instead use the
- * {@link android.net.ConnectivityManager.NetworkCallback} API to
- * learn about connectivity changes.
- * {@link ConnectivityManager#registerDefaultNetworkCallback} and
- * {@link ConnectivityManager#registerNetworkCallback}. These will
- * give a more accurate picture of the connectivity state of
- * the device and let apps react more easily and quickly to changes.
- */
- @Deprecated
- public State getState() {
- synchronized (this) {
- return mState;
- }
- }
-
- /**
- * Reports the current fine-grained state of the network.
- * @return the fine-grained state
- * @deprecated Apps should instead use the
- * {@link android.net.ConnectivityManager.NetworkCallback} API to
- * learn about connectivity changes. See
- * {@link ConnectivityManager#registerDefaultNetworkCallback} and
- * {@link ConnectivityManager#registerNetworkCallback}. These will
- * give a more accurate picture of the connectivity state of
- * the device and let apps react more easily and quickly to changes.
- */
- @Deprecated
- public @NonNull DetailedState getDetailedState() {
- synchronized (this) {
- return mDetailedState;
- }
- }
-
- /**
- * Sets the fine-grained state of the network.
- *
- * This is only useful for testing.
- *
- * @param detailedState the {@link DetailedState}.
- * @param reason a {@code String} indicating the reason for the state change,
- * if one was supplied. May be {@code null}.
- * @param extraInfo an optional {@code String} providing addditional network state
- * information passed up from the lower networking layers.
- * @deprecated Use {@link NetworkCapabilities} instead.
- */
- @Deprecated
- public void setDetailedState(@NonNull DetailedState detailedState, @Nullable String reason,
- @Nullable String extraInfo) {
- synchronized (this) {
- this.mDetailedState = detailedState;
- this.mState = stateMap.get(detailedState);
- this.mReason = reason;
- this.mExtraInfo = extraInfo;
- }
- }
-
- /**
- * Set the extraInfo field.
- * @param extraInfo an optional {@code String} providing addditional network state
- * information passed up from the lower networking layers.
- * @deprecated See {@link NetworkInfo#getExtraInfo}.
- * @hide
- */
- @Deprecated
- public void setExtraInfo(String extraInfo) {
- synchronized (this) {
- this.mExtraInfo = extraInfo;
- }
- }
-
- /**
- * Report the reason an attempt to establish connectivity failed,
- * if one is available.
- * @return the reason for failure, or null if not available
- * @deprecated This method does not have a consistent contract that could make it useful
- * to callers.
- */
- public String getReason() {
- synchronized (this) {
- return mReason;
- }
- }
-
- /**
- * Report the extra information about the network state, if any was
- * provided by the lower networking layers.
- * @return the extra information, or null if not available
- * @deprecated Use other services e.g. WifiManager to get additional information passed up from
- * the lower networking layers.
- */
- @Deprecated
- public String getExtraInfo() {
- synchronized (this) {
- return mExtraInfo;
- }
- }
-
- @Override
- public String toString() {
- synchronized (this) {
- final StringBuilder builder = new StringBuilder("[");
- builder.append("type: ").append(getTypeName()).append("[").append(getSubtypeName()).
- append("], state: ").append(mState).append("/").append(mDetailedState).
- append(", reason: ").append(mReason == null ? "(unspecified)" : mReason).
- append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo).
- append(", failover: ").append(mIsFailover).
- append(", available: ").append(mIsAvailable).
- append(", roaming: ").append(mIsRoaming).
- append("]");
- return builder.toString();
- }
- }
-
- /**
- * Returns a brief summary string suitable for debugging.
- * @hide
- */
- public String toShortString() {
- synchronized (this) {
- final StringBuilder builder = new StringBuilder();
- builder.append(getTypeName());
-
- final String subtype = getSubtypeName();
- if (!TextUtils.isEmpty(subtype)) {
- builder.append("[").append(subtype).append("]");
- }
-
- builder.append(" ");
- builder.append(mDetailedState);
- if (mIsRoaming) {
- builder.append(" ROAMING");
- }
- if (mExtraInfo != null) {
- builder.append(" extra: ").append(mExtraInfo);
- }
- return builder.toString();
- }
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- synchronized (this) {
- dest.writeInt(mNetworkType);
- dest.writeInt(mSubtype);
- dest.writeString(mTypeName);
- dest.writeString(mSubtypeName);
- dest.writeString(mState.name());
- dest.writeString(mDetailedState.name());
- dest.writeInt(mIsFailover ? 1 : 0);
- dest.writeInt(mIsAvailable ? 1 : 0);
- dest.writeInt(mIsRoaming ? 1 : 0);
- dest.writeString(mReason);
- dest.writeString(mExtraInfo);
- }
- }
-
- public static final @android.annotation.NonNull Creator<NetworkInfo> CREATOR = new Creator<NetworkInfo>() {
- @Override
- public NetworkInfo createFromParcel(Parcel in) {
- int netType = in.readInt();
- int subtype = in.readInt();
- String typeName = in.readString();
- String subtypeName = in.readString();
- NetworkInfo netInfo = new NetworkInfo(netType, subtype, typeName, subtypeName);
- netInfo.mState = State.valueOf(in.readString());
- netInfo.mDetailedState = DetailedState.valueOf(in.readString());
- netInfo.mIsFailover = in.readInt() != 0;
- netInfo.mIsAvailable = in.readInt() != 0;
- netInfo.mIsRoaming = in.readInt() != 0;
- netInfo.mReason = in.readString();
- netInfo.mExtraInfo = in.readString();
- return netInfo;
- }
-
- @Override
- public NetworkInfo[] newArray(int size) {
- return new NetworkInfo[size];
- }
- };
-}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkProvider.java b/packages/Connectivity/framework/src/android/net/NetworkProvider.java
deleted file mode 100644
index 0665af5..0000000
--- a/packages/Connectivity/framework/src/android/net/NetworkProvider.java
+++ /dev/null
@@ -1,332 +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.net;
-
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.util.ArrayList;
-import java.util.concurrent.Executor;
-
-/**
- * Base class for network providers such as telephony or Wi-Fi. NetworkProviders connect the device
- * to networks and makes them available to the core network stack by creating
- * {@link NetworkAgent}s. The networks can then provide connectivity to apps and can be interacted
- * with via networking APIs such as {@link ConnectivityManager}.
- *
- * Subclasses should implement {@link #onNetworkRequested} and {@link #onNetworkRequestWithdrawn}
- * to receive {@link NetworkRequest}s sent by the system and by apps. A network that is not the
- * best (highest-scoring) network for any request is generally not used by the system, and torn
- * down.
- *
- * @hide
- */
-@SystemApi
-public class NetworkProvider {
- /**
- * {@code providerId} value that indicates the absence of a provider. It is the providerId of
- * any NetworkProvider that is not currently registered, and of any NetworkRequest that is not
- * currently being satisfied by a network.
- */
- public static final int ID_NONE = -1;
-
- /**
- * The first providerId value that will be allocated.
- * @hide only used by ConnectivityService.
- */
- public static final int FIRST_PROVIDER_ID = 1;
-
- /** @hide only used by ConnectivityService */
- public static final int CMD_REQUEST_NETWORK = 1;
- /** @hide only used by ConnectivityService */
- public static final int CMD_CANCEL_REQUEST = 2;
-
- private final Messenger mMessenger;
- private final String mName;
- private final Context mContext;
-
- private int mProviderId = ID_NONE;
-
- /**
- * Constructs a new NetworkProvider.
- *
- * @param looper the Looper on which to run {@link #onNetworkRequested} and
- * {@link #onNetworkRequestWithdrawn}.
- * @param name the name of the listener, used only for debugging.
- *
- * @hide
- */
- @SystemApi
- public NetworkProvider(@NonNull Context context, @NonNull Looper looper, @NonNull String name) {
- // TODO (b/174636568) : this class should be able to cache an instance of
- // ConnectivityManager so it doesn't have to fetch it again every time.
- final Handler handler = new Handler(looper) {
- @Override
- public void handleMessage(Message m) {
- switch (m.what) {
- case CMD_REQUEST_NETWORK:
- onNetworkRequested((NetworkRequest) m.obj, m.arg1, m.arg2);
- break;
- case CMD_CANCEL_REQUEST:
- onNetworkRequestWithdrawn((NetworkRequest) m.obj);
- break;
- default:
- Log.e(mName, "Unhandled message: " + m.what);
- }
- }
- };
- mContext = context;
- mMessenger = new Messenger(handler);
- mName = name;
- }
-
- // TODO: consider adding a register() method so ConnectivityManager does not need to call this.
- /** @hide */
- public @Nullable Messenger getMessenger() {
- return mMessenger;
- }
-
- /** @hide */
- public @NonNull String getName() {
- return mName;
- }
-
- /**
- * Returns the ID of this provider. This is known only once the provider is registered via
- * {@link ConnectivityManager#registerNetworkProvider()}, otherwise the ID is {@link #ID_NONE}.
- * This ID must be used when registering any {@link NetworkAgent}s.
- */
- public int getProviderId() {
- return mProviderId;
- }
-
- /** @hide */
- public void setProviderId(int providerId) {
- mProviderId = providerId;
- }
-
- /**
- * Called when a NetworkRequest is received. The request may be a new request or an existing
- * request with a different score.
- *
- * @param request the NetworkRequest being received
- * @param score the score of the network currently satisfying the request, or 0 if none.
- * @param providerId the ID of the provider that created the network currently satisfying this
- * request, or {@link #ID_NONE} if none.
- *
- * @hide
- */
- @SystemApi
- public void onNetworkRequested(@NonNull NetworkRequest request,
- @IntRange(from = 0, to = 99) int score, int providerId) {}
-
- /**
- * Called when a NetworkRequest is withdrawn.
- * @hide
- */
- @SystemApi
- public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) {}
-
- /**
- * Asserts that no provider will ever be able to satisfy the specified request. The provider
- * must only call this method if it knows that it is the only provider on the system capable of
- * satisfying this request, and that the request cannot be satisfied. The application filing the
- * request will receive an {@link NetworkCallback#onUnavailable()} callback.
- *
- * @param request the request that permanently cannot be fulfilled
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
- public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) {
- ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(request);
- }
-
- /**
- * A callback for parties registering a NetworkOffer.
- *
- * This is used with {@link ConnectivityManager#offerNetwork}. When offering a network,
- * the system will use this callback to inform the caller that a network corresponding to
- * this offer is needed or unneeded.
- *
- * @hide
- */
- @SystemApi
- public interface NetworkOfferCallback {
- /**
- * Called by the system when a network for this offer is needed to satisfy some
- * networking request.
- */
- void onNetworkNeeded(@NonNull NetworkRequest request);
- /**
- * Called by the system when this offer is no longer valuable for this request.
- */
- void onNetworkUnneeded(@NonNull NetworkRequest request);
- }
-
- private class NetworkOfferCallbackProxy extends INetworkOfferCallback.Stub {
- @NonNull public final NetworkOfferCallback callback;
- @NonNull private final Executor mExecutor;
-
- NetworkOfferCallbackProxy(@NonNull final NetworkOfferCallback callback,
- @NonNull final Executor executor) {
- this.callback = callback;
- this.mExecutor = executor;
- }
-
- @Override
- public void onNetworkNeeded(final @NonNull NetworkRequest request) {
- mExecutor.execute(() -> callback.onNetworkNeeded(request));
- }
-
- @Override
- public void onNetworkUnneeded(final @NonNull NetworkRequest request) {
- mExecutor.execute(() -> callback.onNetworkUnneeded(request));
- }
- }
-
- @GuardedBy("mProxies")
- @NonNull private final ArrayList<NetworkOfferCallbackProxy> mProxies = new ArrayList<>();
-
- // Returns the proxy associated with this callback, or null if none.
- @Nullable
- private NetworkOfferCallbackProxy findProxyForCallback(@NonNull final NetworkOfferCallback cb) {
- synchronized (mProxies) {
- for (final NetworkOfferCallbackProxy p : mProxies) {
- if (p.callback == cb) return p;
- }
- }
- return null;
- }
-
- /**
- * Register or update an offer for network with the passed capabilities and score.
- *
- * A NetworkProvider's role is to provide networks. This method is how a provider tells the
- * connectivity stack what kind of network it may provide. The score and caps arguments act
- * as filters that the connectivity stack uses to tell when the offer is valuable. When an
- * offer might be preferred over existing networks, the provider will receive a call to
- * the associated callback's {@link NetworkOfferCallback#onNetworkNeeded} method. The provider
- * should then try to bring up this network. When an offer is no longer useful, the stack
- * will inform the provider by calling {@link NetworkOfferCallback#onNetworkUnneeded}. The
- * provider should stop trying to bring up such a network, or disconnect it if it already has
- * one.
- *
- * The stack determines what offers are valuable according to what networks are currently
- * available to the system, and what networking requests are made by applications. If an
- * offer looks like it could connect a better network than any existing network for any
- * particular request, that's when the stack decides the network is needed. If the current
- * networking requests are all satisfied by networks that this offer couldn't possibly be a
- * better match for, that's when the offer is no longer valuable. An offer starts out as
- * unneeded ; the provider should not try to bring up the network until
- * {@link NetworkOfferCallback#onNetworkNeeded} is called.
- *
- * Note that the offers are non-binding to the providers, in particular because providers
- * often don't know if they will be able to bring up such a network at any given time. For
- * example, no wireless network may be in range when the offer would be valuable. This is fine
- * and expected ; the provider should simply continue to try to bring up the network and do so
- * if/when it becomes possible. In the mean time, the stack will continue to satisfy requests
- * with the best network currently available, or if none, keep the apps informed that no
- * network can currently satisfy this request. When/if the provider can bring up the network,
- * the connectivity stack will match it against requests, and inform interested apps of the
- * availability of this network. This may, in turn, render the offer of some other provider
- * low-value if all requests it used to satisfy are now better served by this network.
- *
- * A network can become unneeded for a reason like the above : whether the provider managed
- * to bring up the offered network after it became needed or not, some other provider may
- * bring up a better network than this one, making this network unneeded. A network may also
- * become unneeded if the application making the request withdrew it (for example, after it
- * is done transferring data, or if the user canceled an operation).
- *
- * The capabilities and score act as filters as to what requests the provider will see.
- * They are not promises, but for best performance, the providers should strive to put
- * as much known information as possible in the offer. For the score, it should put as
- * strong a score as the networks will have, since this will filter what requests the
- * provider sees – it's not a promise, it only serves to avoid sending requests that
- * the provider can't ever hope to satisfy better than any current network. For capabilities,
- * it should put all NetworkAgent-managed capabilities a network may have, even if it doesn't
- * have them at first. This applies to INTERNET, for example ; if a provider thinks the
- * network it can bring up for this offer may offer Internet access it should include the
- * INTERNET bit. It's fine if the brought up network ends up not actually having INTERNET.
- *
- * TODO : in the future, to avoid possible infinite loops, there should be constraints on
- * what can be put in capabilities of networks brought up for an offer. If a provider might
- * bring up a network with or without INTERNET, then it should file two offers : this will
- * let it know precisely what networks are needed, so it can avoid bringing up networks that
- * won't actually satisfy requests and remove the risk for bring-up-bring-down loops.
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
- public void registerNetworkOffer(@NonNull final NetworkScore score,
- @NonNull final NetworkCapabilities caps, @NonNull final Executor executor,
- @NonNull final NetworkOfferCallback callback) {
- // Can't offer a network with a provider that is not yet registered or already unregistered.
- final int providerId = mProviderId;
- if (providerId == ID_NONE) return;
- NetworkOfferCallbackProxy proxy = null;
- synchronized (mProxies) {
- for (final NetworkOfferCallbackProxy existingProxy : mProxies) {
- if (existingProxy.callback == callback) {
- proxy = existingProxy;
- break;
- }
- }
- if (null == proxy) {
- proxy = new NetworkOfferCallbackProxy(callback, executor);
- mProxies.add(proxy);
- }
- }
- mContext.getSystemService(ConnectivityManager.class)
- .offerNetwork(providerId, score, caps, proxy);
- }
-
- /**
- * Withdraw a network offer previously made to the networking stack.
- *
- * If a provider can no longer provide a network they offered, it should call this method.
- * An example of usage could be if the hardware necessary to bring up the network was turned
- * off in UI by the user. Note that because offers are never binding, the provider might
- * alternatively decide not to withdraw this offer and simply refuse to bring up the network
- * even when it's needed. However, withdrawing the request is slightly more resource-efficient
- * because the networking stack won't have to compare this offer to exiting networks to see
- * if it could beat any of them, and may be advantageous to the provider's implementation that
- * can rely on no longer receiving callbacks for a network that they can't bring up anyways.
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
- public void unregisterNetworkOffer(final @NonNull NetworkOfferCallback callback) {
- final NetworkOfferCallbackProxy proxy = findProxyForCallback(callback);
- if (null == proxy) return;
- mProxies.remove(proxy);
- mContext.getSystemService(ConnectivityManager.class).unofferNetwork(proxy);
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkReleasedException.java b/packages/Connectivity/framework/src/android/net/NetworkReleasedException.java
deleted file mode 100644
index 0629b75..0000000
--- a/packages/Connectivity/framework/src/android/net/NetworkReleasedException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.SystemApi;
-
-/**
- * Indicates that the {@link Network} was released and is no longer available.
- *
- * @hide
- */
-@SystemApi
-public class NetworkReleasedException extends Exception {
- /** @hide */
- public NetworkReleasedException() {
- super("The network was released and is no longer available");
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
deleted file mode 100644
index afc76d6..0000000
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ /dev/null
@@ -1,753 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
-import static android.net.NetworkCapabilities.TRANSPORT_TEST;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.net.NetworkCapabilities.NetCapability;
-import android.net.NetworkCapabilities.Transport;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.Process;
-import android.text.TextUtils;
-import android.util.Range;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * Defines a request for a network, made through {@link NetworkRequest.Builder} and used
- * to request a network via {@link ConnectivityManager#requestNetwork} or listen for changes
- * via {@link ConnectivityManager#registerNetworkCallback}.
- */
-public class NetworkRequest implements Parcelable {
- /**
- * The first requestId value that will be allocated.
- * @hide only used by ConnectivityService.
- */
- public static final int FIRST_REQUEST_ID = 1;
-
- /**
- * The requestId value that represents the absence of a request.
- * @hide only used by ConnectivityService.
- */
- public static final int REQUEST_ID_NONE = -1;
-
- /**
- * The {@link NetworkCapabilities} that define this request.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public final @NonNull NetworkCapabilities networkCapabilities;
-
- /**
- * Identifies the request. NetworkRequests should only be constructed by
- * the Framework and given out to applications as tokens to be used to identify
- * the request.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public final int requestId;
-
- /**
- * Set for legacy requests and the default. Set to TYPE_NONE for none.
- * Causes CONNECTIVITY_ACTION broadcasts to be sent.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public final int legacyType;
-
- /**
- * A NetworkRequest as used by the system can be one of the following types:
- *
- * - LISTEN, for which the framework will issue callbacks about any
- * and all networks that match the specified NetworkCapabilities,
- *
- * - REQUEST, capable of causing a specific network to be created
- * first (e.g. a telephony DUN request), the framework will issue
- * callbacks about the single, highest scoring current network
- * (if any) that matches the specified NetworkCapabilities, or
- *
- * - TRACK_DEFAULT, which causes the framework to issue callbacks for
- * the single, highest scoring current network (if any) that will
- * be chosen for an app, but which cannot cause the framework to
- * either create or retain the existence of any specific network.
- *
- * - TRACK_SYSTEM_DEFAULT, which causes the framework to send callbacks
- * for the network (if any) that satisfies the default Internet
- * request.
- *
- * - TRACK_BEST, which causes the framework to send callbacks about
- * the single, highest scoring current network (if any) that matches
- * the specified NetworkCapabilities.
- *
- * - BACKGROUND_REQUEST, like REQUEST but does not cause any networks
- * to retain the NET_CAPABILITY_FOREGROUND capability. A network with
- * no foreground requests is in the background. A network that has
- * one or more background requests and loses its last foreground
- * request to a higher-scoring network will not go into the
- * background immediately, but will linger and go into the background
- * after the linger timeout.
- *
- * - The value NONE is used only by applications. When an application
- * creates a NetworkRequest, it does not have a type; the type is set
- * by the system depending on the method used to file the request
- * (requestNetwork, registerNetworkCallback, etc.).
- *
- * @hide
- */
- public static enum Type {
- NONE,
- LISTEN,
- TRACK_DEFAULT,
- REQUEST,
- BACKGROUND_REQUEST,
- TRACK_SYSTEM_DEFAULT,
- LISTEN_FOR_BEST,
- };
-
- /**
- * The type of the request. This is only used by the system and is always NONE elsewhere.
- *
- * @hide
- */
- public final Type type;
-
- /**
- * @hide
- */
- public NetworkRequest(NetworkCapabilities nc, int legacyType, int rId, Type type) {
- if (nc == null) {
- throw new NullPointerException();
- }
- requestId = rId;
- networkCapabilities = nc;
- this.legacyType = legacyType;
- this.type = type;
- }
-
- /**
- * @hide
- */
- public NetworkRequest(NetworkRequest that) {
- networkCapabilities = new NetworkCapabilities(that.networkCapabilities);
- requestId = that.requestId;
- this.legacyType = that.legacyType;
- this.type = that.type;
- }
-
- /**
- * Builder used to create {@link NetworkRequest} objects. Specify the Network features
- * needed in terms of {@link NetworkCapabilities} features
- */
- public static class Builder {
- /**
- * Capabilities that are currently compatible with VCN networks.
- */
- private static final List<Integer> VCN_SUPPORTED_CAPABILITIES = Arrays.asList(
- NET_CAPABILITY_CAPTIVE_PORTAL,
- NET_CAPABILITY_DUN,
- NET_CAPABILITY_FOREGROUND,
- NET_CAPABILITY_INTERNET,
- NET_CAPABILITY_NOT_CONGESTED,
- NET_CAPABILITY_NOT_METERED,
- NET_CAPABILITY_NOT_RESTRICTED,
- NET_CAPABILITY_NOT_ROAMING,
- NET_CAPABILITY_NOT_SUSPENDED,
- NET_CAPABILITY_NOT_VPN,
- NET_CAPABILITY_PARTIAL_CONNECTIVITY,
- NET_CAPABILITY_TEMPORARILY_NOT_METERED,
- NET_CAPABILITY_TRUSTED,
- NET_CAPABILITY_VALIDATED);
-
- private final NetworkCapabilities mNetworkCapabilities;
-
- // A boolean that represents whether the NOT_VCN_MANAGED capability should be deduced when
- // the NetworkRequest object is built.
- private boolean mShouldDeduceNotVcnManaged = true;
-
- /**
- * Default constructor for Builder.
- */
- public Builder() {
- // By default, restrict this request to networks available to this app.
- // Apps can rescind this restriction, but ConnectivityService will enforce
- // it for apps that do not have the NETWORK_SETTINGS permission.
- mNetworkCapabilities = new NetworkCapabilities();
- mNetworkCapabilities.setSingleUid(Process.myUid());
- }
-
- /**
- * Creates a new Builder of NetworkRequest from an existing instance.
- */
- public Builder(@NonNull final NetworkRequest request) {
- Objects.requireNonNull(request);
- mNetworkCapabilities = request.networkCapabilities;
- // If the caller constructed the builder from a request, it means the user
- // might explicitly want the capabilities from the request. Thus, the NOT_VCN_MANAGED
- // capabilities should not be touched later.
- mShouldDeduceNotVcnManaged = false;
- }
-
- /**
- * Build {@link NetworkRequest} give the current set of capabilities.
- */
- public NetworkRequest build() {
- // Make a copy of mNetworkCapabilities so we don't inadvertently remove NOT_RESTRICTED
- // when later an unrestricted capability could be added to mNetworkCapabilities, in
- // which case NOT_RESTRICTED should be returned to mNetworkCapabilities, which
- // maybeMarkCapabilitiesRestricted() doesn't add back.
- final NetworkCapabilities nc = new NetworkCapabilities(mNetworkCapabilities);
- nc.maybeMarkCapabilitiesRestricted();
- deduceNotVcnManagedCapability(nc);
- return new NetworkRequest(nc, ConnectivityManager.TYPE_NONE,
- ConnectivityManager.REQUEST_ID_UNSET, Type.NONE);
- }
-
- /**
- * Add the given capability requirement to this builder. These represent
- * the requested network's required capabilities. Note that when searching
- * for a network to satisfy a request, all capabilities requested must be
- * satisfied.
- *
- * @param capability The capability to add.
- * @return The builder to facilitate chaining
- * {@code builder.addCapability(...).addCapability();}.
- */
- public Builder addCapability(@NetworkCapabilities.NetCapability int capability) {
- mNetworkCapabilities.addCapability(capability);
- if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) {
- mShouldDeduceNotVcnManaged = false;
- }
- return this;
- }
-
- /**
- * Removes (if found) the given capability from this builder instance.
- *
- * @param capability The capability to remove.
- * @return The builder to facilitate chaining.
- */
- public Builder removeCapability(@NetworkCapabilities.NetCapability int capability) {
- mNetworkCapabilities.removeCapability(capability);
- if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) {
- mShouldDeduceNotVcnManaged = false;
- }
- return this;
- }
-
- /**
- * Set the {@code NetworkCapabilities} for this builder instance,
- * overriding any capabilities that had been previously set.
- *
- * @param nc The superseding {@code NetworkCapabilities} instance.
- * @return The builder to facilitate chaining.
- * @hide
- */
- public Builder setCapabilities(NetworkCapabilities nc) {
- mNetworkCapabilities.set(nc);
- return this;
- }
-
- /**
- * Sets this request to match only networks that apply to the specified UIDs.
- *
- * By default, the set of UIDs is the UID of the calling app, and this request will match
- * any network that applies to the app. Setting it to {@code null} will observe any
- * network on the system, even if it does not apply to this app. In this case, any
- * {@link NetworkSpecifier} set on this request will be redacted or removed to prevent the
- * application deducing restricted information such as location.
- *
- * @param uids The UIDs as a set of {@code Range<Integer>}, or null for everything.
- * @return The builder to facilitate chaining.
- * @hide
- */
- @NonNull
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @SuppressLint("MissingGetterMatchingBuilder")
- public Builder setUids(@Nullable Set<Range<Integer>> uids) {
- mNetworkCapabilities.setUids(uids);
- return this;
- }
-
- /**
- * Add a capability that must not exist in the requested network.
- * <p>
- * If the capability was previously added to the list of required capabilities (for
- * example, it was there by default or added using {@link #addCapability(int)} method), then
- * it will be removed from the list of required capabilities as well.
- *
- * @see #addCapability(int)
- *
- * @param capability The capability to add to forbidden capability list.
- * @return The builder to facilitate chaining.
- *
- * @hide
- */
- @NonNull
- @SuppressLint("MissingGetterMatchingBuilder")
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public Builder addForbiddenCapability(@NetworkCapabilities.NetCapability int capability) {
- mNetworkCapabilities.addForbiddenCapability(capability);
- return this;
- }
-
- /**
- * Removes (if found) the given forbidden capability from this builder instance.
- *
- * @param capability The forbidden capability to remove.
- * @return The builder to facilitate chaining.
- *
- * @hide
- */
- @NonNull
- @SuppressLint("BuilderSetStyle")
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public Builder removeForbiddenCapability(
- @NetworkCapabilities.NetCapability int capability) {
- mNetworkCapabilities.removeForbiddenCapability(capability);
- return this;
- }
-
- /**
- * Completely clears all the {@code NetworkCapabilities} from this builder instance,
- * removing even the capabilities that are set by default when the object is constructed.
- *
- * @return The builder to facilitate chaining.
- */
- @NonNull
- public Builder clearCapabilities() {
- mNetworkCapabilities.clearAll();
- // If the caller explicitly clear all capabilities, the NOT_VCN_MANAGED capabilities
- // should not be add back later.
- mShouldDeduceNotVcnManaged = false;
- return this;
- }
-
- /**
- * Adds the given transport requirement to this builder. These represent
- * the set of allowed transports for the request. Only networks using one
- * of these transports will satisfy the request. If no particular transports
- * are required, none should be specified here.
- *
- * @param transportType The transport type to add.
- * @return The builder to facilitate chaining.
- */
- public Builder addTransportType(@NetworkCapabilities.Transport int transportType) {
- mNetworkCapabilities.addTransportType(transportType);
- return this;
- }
-
- /**
- * Removes (if found) the given transport from this builder instance.
- *
- * @param transportType The transport type to remove.
- * @return The builder to facilitate chaining.
- */
- public Builder removeTransportType(@NetworkCapabilities.Transport int transportType) {
- mNetworkCapabilities.removeTransportType(transportType);
- return this;
- }
-
- /**
- * @hide
- */
- public Builder setLinkUpstreamBandwidthKbps(int upKbps) {
- mNetworkCapabilities.setLinkUpstreamBandwidthKbps(upKbps);
- return this;
- }
- /**
- * @hide
- */
- public Builder setLinkDownstreamBandwidthKbps(int downKbps) {
- mNetworkCapabilities.setLinkDownstreamBandwidthKbps(downKbps);
- return this;
- }
-
- /**
- * Sets the optional bearer specific network specifier.
- * This has no meaning if a single transport is also not specified, so calling
- * this without a single transport set will generate an exception, as will
- * subsequently adding or removing transports after this is set.
- * </p>
- * If the {@code networkSpecifier} is provided, it shall be interpreted as follows:
- * <ul>
- * <li>If the specifier can be parsed as an integer, it will be treated as a
- * {@link android.net TelephonyNetworkSpecifier}, and the provided integer will be
- * interpreted as a SubscriptionId.
- * <li>If the value is an ethernet interface name, it will be treated as such.
- * <li>For all other cases, the behavior is undefined.
- * </ul>
- *
- * @param networkSpecifier A {@code String} of either a SubscriptionId in cellular
- * network request or an ethernet interface name in ethernet
- * network request.
- *
- * @deprecated Use {@link #setNetworkSpecifier(NetworkSpecifier)} instead.
- */
- @Deprecated
- public Builder setNetworkSpecifier(String networkSpecifier) {
- try {
- int subId = Integer.parseInt(networkSpecifier);
- return setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
- .setSubscriptionId(subId).build());
- } catch (NumberFormatException nfe) {
- // An EthernetNetworkSpecifier or TestNetworkSpecifier does not accept null or empty
- // ("") strings. When network specifiers were strings a null string and an empty
- // string were considered equivalent. Hence no meaning is attached to a null or
- // empty ("") string.
- if (TextUtils.isEmpty(networkSpecifier)) {
- return setNetworkSpecifier((NetworkSpecifier) null);
- } else if (mNetworkCapabilities.hasTransport(TRANSPORT_TEST)) {
- return setNetworkSpecifier(new TestNetworkSpecifier(networkSpecifier));
- } else {
- return setNetworkSpecifier(new EthernetNetworkSpecifier(networkSpecifier));
- }
- }
- }
-
- /**
- * Sets the optional bearer specific network specifier.
- * This has no meaning if a single transport is also not specified, so calling
- * this without a single transport set will generate an exception, as will
- * subsequently adding or removing transports after this is set.
- * </p>
- *
- * @param networkSpecifier A concrete, parcelable framework class that extends
- * NetworkSpecifier.
- */
- public Builder setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
- if (networkSpecifier instanceof MatchAllNetworkSpecifier) {
- throw new IllegalArgumentException("A MatchAllNetworkSpecifier is not permitted");
- }
- mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
- // Do not touch NOT_VCN_MANAGED if the caller needs to access to a very specific
- // Network.
- mShouldDeduceNotVcnManaged = false;
- return this;
- }
-
- /**
- * Sets the signal strength. This is a signed integer, with higher values indicating a
- * stronger signal. The exact units are bearer-dependent. For example, Wi-Fi uses the same
- * RSSI units reported by WifiManager.
- * <p>
- * Note that when used to register a network callback, this specifies the minimum acceptable
- * signal strength. When received as the state of an existing network it specifies the
- * current value. A value of {@code SIGNAL_STRENGTH_UNSPECIFIED} means no value when
- * received and has no effect when requesting a callback.
- *
- * <p>This method requires the caller to hold the
- * {@link android.Manifest.permission#NETWORK_SIGNAL_STRENGTH_WAKEUP} permission
- *
- * @param signalStrength the bearer-specific signal strength.
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP)
- public @NonNull Builder setSignalStrength(int signalStrength) {
- mNetworkCapabilities.setSignalStrength(signalStrength);
- return this;
- }
-
- /**
- * Deduce the NET_CAPABILITY_NOT_VCN_MANAGED capability from other capabilities
- * and user intention, which includes:
- * 1. For the requests that don't have anything besides
- * {@link #VCN_SUPPORTED_CAPABILITIES}, add the NET_CAPABILITY_NOT_VCN_MANAGED to
- * allow the callers automatically utilize VCN networks if available.
- * 2. For the requests that explicitly add or remove NET_CAPABILITY_NOT_VCN_MANAGED,
- * or has clear intention of tracking specific network,
- * do not alter them to allow user fire request that suits their need.
- *
- * @hide
- */
- private void deduceNotVcnManagedCapability(final NetworkCapabilities nc) {
- if (!mShouldDeduceNotVcnManaged) return;
- for (final int cap : nc.getCapabilities()) {
- if (!VCN_SUPPORTED_CAPABILITIES.contains(cap)) return;
- }
- nc.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- }
-
- /**
- * Sets the optional subscription ID set.
- * <p>
- * This specify the subscription IDs requirement.
- * A network will satisfy this request only if it matches one of the subIds in this set.
- * An empty set matches all networks, including those without a subId.
- *
- * <p>Registering a NetworkRequest with a non-empty set of subIds requires the
- * NETWORK_FACTORY permission.
- *
- * @param subIds A {@code Set} that represents subscription IDs.
- * @hide
- */
- @NonNull
- @SystemApi
- public Builder setSubscriptionIds(@NonNull Set<Integer> subIds) {
- mNetworkCapabilities.setSubscriptionIds(subIds);
- return this;
- }
-
- /**
- * Specifies whether the built request should also match networks that do not apply to the
- * calling UID.
- *
- * By default, the built request will only match networks that apply to the calling UID.
- * If this method is called with {@code true}, the built request will match any network on
- * the system that matches the other parameters of the request. In this case, any
- * information in the built request that is subject to redaction for security or privacy
- * purposes, such as a {@link NetworkSpecifier}, will be redacted or removed to prevent the
- * application deducing sensitive information.
- *
- * @param include Whether to match networks that do not apply to the calling UID.
- * @return The builder to facilitate chaining.
- */
- @NonNull
- public Builder setIncludeOtherUidNetworks(boolean include) {
- if (include) {
- mNetworkCapabilities.setUids(null);
- } else {
- mNetworkCapabilities.setSingleUid(Process.myUid());
- }
- return this;
- }
- }
-
- // implement the Parcelable interface
- public int describeContents() {
- return 0;
- }
- public void writeToParcel(Parcel dest, int flags) {
- networkCapabilities.writeToParcel(dest, flags);
- dest.writeInt(legacyType);
- dest.writeInt(requestId);
- dest.writeString(type.name());
- }
-
- public static final @android.annotation.NonNull Creator<NetworkRequest> CREATOR =
- new Creator<NetworkRequest>() {
- public NetworkRequest createFromParcel(Parcel in) {
- NetworkCapabilities nc = NetworkCapabilities.CREATOR.createFromParcel(in);
- int legacyType = in.readInt();
- int requestId = in.readInt();
- Type type = Type.valueOf(in.readString()); // IllegalArgumentException if invalid.
- NetworkRequest result = new NetworkRequest(nc, legacyType, requestId, type);
- return result;
- }
- public NetworkRequest[] newArray(int size) {
- return new NetworkRequest[size];
- }
- };
-
- /**
- * Returns true iff. this NetworkRequest is of type LISTEN.
- *
- * @hide
- */
- public boolean isListen() {
- return type == Type.LISTEN;
- }
-
- /**
- * Returns true iff. this NetworkRequest is of type LISTEN_FOR_BEST.
- *
- * @hide
- */
- public boolean isListenForBest() {
- return type == Type.LISTEN_FOR_BEST;
- }
-
- /**
- * Returns true iff. the contained NetworkRequest is one that:
- *
- * - should be associated with at most one satisfying network
- * at a time;
- *
- * - should cause a network to be kept up, but not necessarily in
- * the foreground, if it is the best network which can satisfy the
- * NetworkRequest.
- *
- * For full detail of how isRequest() is used for pairing Networks with
- * NetworkRequests read rematchNetworkAndRequests().
- *
- * @hide
- */
- public boolean isRequest() {
- return type == Type.REQUEST || type == Type.BACKGROUND_REQUEST;
- }
-
- /**
- * Returns true iff. this NetworkRequest is of type BACKGROUND_REQUEST.
- *
- * @hide
- */
- public boolean isBackgroundRequest() {
- return type == Type.BACKGROUND_REQUEST;
- }
-
- /**
- * @see Builder#addCapability(int)
- */
- public boolean hasCapability(@NetCapability int capability) {
- return networkCapabilities.hasCapability(capability);
- }
-
- /**
- * @see Builder#addForbiddenCapability(int)
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public boolean hasForbiddenCapability(@NetCapability int capability) {
- return networkCapabilities.hasForbiddenCapability(capability);
- }
-
- /**
- * Returns true if and only if the capabilities requested in this NetworkRequest are satisfied
- * by the provided {@link NetworkCapabilities}.
- *
- * @param nc Capabilities that should satisfy this NetworkRequest. null capabilities do not
- * satisfy any request.
- */
- public boolean canBeSatisfiedBy(@Nullable NetworkCapabilities nc) {
- return networkCapabilities.satisfiedByNetworkCapabilities(nc);
- }
-
- /**
- * @see Builder#addTransportType(int)
- */
- public boolean hasTransport(@Transport int transportType) {
- return networkCapabilities.hasTransport(transportType);
- }
-
- /**
- * @see Builder#setNetworkSpecifier(NetworkSpecifier)
- */
- @Nullable
- public NetworkSpecifier getNetworkSpecifier() {
- return networkCapabilities.getNetworkSpecifier();
- }
-
- /**
- * @return the uid of the app making the request.
- *
- * Note: This could return {@link Process#INVALID_UID} if the {@link NetworkRequest} object was
- * not obtained from {@link ConnectivityManager}.
- * @hide
- */
- @SystemApi
- public int getRequestorUid() {
- return networkCapabilities.getRequestorUid();
- }
-
- /**
- * @return the package name of the app making the request.
- *
- * Note: This could return {@code null} if the {@link NetworkRequest} object was not obtained
- * from {@link ConnectivityManager}.
- * @hide
- */
- @SystemApi
- @Nullable
- public String getRequestorPackageName() {
- return networkCapabilities.getRequestorPackageName();
- }
-
- public String toString() {
- return "NetworkRequest [ " + type + " id=" + requestId +
- (legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") +
- ", " + networkCapabilities.toString() + " ]";
- }
-
- public boolean equals(@Nullable Object obj) {
- if (obj instanceof NetworkRequest == false) return false;
- NetworkRequest that = (NetworkRequest)obj;
- return (that.legacyType == this.legacyType &&
- that.requestId == this.requestId &&
- that.type == this.type &&
- Objects.equals(that.networkCapabilities, this.networkCapabilities));
- }
-
- public int hashCode() {
- return Objects.hash(requestId, legacyType, networkCapabilities, type);
- }
-
- /**
- * Gets all the capabilities set on this {@code NetworkRequest} instance.
- *
- * @return an array of capability values for this instance.
- */
- @NonNull
- public @NetCapability int[] getCapabilities() {
- // No need to make a defensive copy here as NC#getCapabilities() already returns
- // a new array.
- return networkCapabilities.getCapabilities();
- }
-
- /**
- * Gets all the forbidden capabilities set on this {@code NetworkRequest} instance.
- *
- * @return an array of forbidden capability values for this instance.
- *
- * @hide
- */
- @NonNull
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public @NetCapability int[] getForbiddenCapabilities() {
- // No need to make a defensive copy here as NC#getForbiddenCapabilities() already returns
- // a new array.
- return networkCapabilities.getForbiddenCapabilities();
- }
-
- /**
- * Gets all the transports set on this {@code NetworkRequest} instance.
- *
- * @return an array of transport type values for this instance.
- */
- @NonNull
- public @Transport int[] getTransportTypes() {
- // No need to make a defensive copy here as NC#getTransportTypes() already returns
- // a new array.
- return networkCapabilities.getTransportTypes();
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkScore.java b/packages/Connectivity/framework/src/android/net/NetworkScore.java
deleted file mode 100644
index 7be7deb..0000000
--- a/packages/Connectivity/framework/src/android/net/NetworkScore.java
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Object representing the quality of a network as perceived by the user.
- *
- * A NetworkScore object represents the characteristics of a network that affects how good the
- * network is considered for a particular use.
- * @hide
- */
-@SystemApi
-public final class NetworkScore implements Parcelable {
- // This will be removed soon. Do *NOT* depend on it for any new code that is not part of
- // a migration.
- private final int mLegacyInt;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- KEEP_CONNECTED_NONE,
- KEEP_CONNECTED_FOR_HANDOVER
- })
- public @interface KeepConnectedReason { }
-
- /**
- * Do not keep this network connected if there is no outstanding request for it.
- */
- public static final int KEEP_CONNECTED_NONE = 0;
- /**
- * Keep this network connected even if there is no outstanding request for it, because it
- * is being considered for handover.
- */
- public static final int KEEP_CONNECTED_FOR_HANDOVER = 1;
-
- // Agent-managed policies
- // This network should lose to a wifi that has ever been validated
- // NOTE : temporarily this policy is managed by ConnectivityService, because of legacy. The
- // legacy design has this bit global to the system and tacked on WiFi which means it will affect
- // networks from carriers who don't want it and non-carrier networks, which is bad for users.
- // The S design has this on mobile networks only, so this can be fixed eventually ; as CS
- // doesn't know what carriers need this bit, the initial S implementation will continue to
- // affect other carriers but will at least leave non-mobile networks alone. Eventually Telephony
- // should set this on networks from carriers that require it.
- /** @hide */
- public static final int POLICY_YIELD_TO_BAD_WIFI = 1;
- // This network is primary for this transport.
- /** @hide */
- public static final int POLICY_TRANSPORT_PRIMARY = 2;
- // This network is exiting : it will likely disconnect in a few seconds.
- /** @hide */
- public static final int POLICY_EXITING = 3;
-
- /** @hide */
- public static final int MIN_AGENT_MANAGED_POLICY = POLICY_YIELD_TO_BAD_WIFI;
- /** @hide */
- public static final int MAX_AGENT_MANAGED_POLICY = POLICY_EXITING;
-
- // Bitmask of all the policies applied to this score.
- private final long mPolicies;
-
- private final int mKeepConnectedReason;
-
- /** @hide */
- NetworkScore(final int legacyInt, final long policies,
- @KeepConnectedReason final int keepConnectedReason) {
- mLegacyInt = legacyInt;
- mPolicies = policies;
- mKeepConnectedReason = keepConnectedReason;
- }
-
- private NetworkScore(@NonNull final Parcel in) {
- mLegacyInt = in.readInt();
- mPolicies = in.readLong();
- mKeepConnectedReason = in.readInt();
- }
-
- /**
- * Get the legacy int score embedded in this NetworkScore.
- * @see Builder#setLegacyInt(int)
- */
- public int getLegacyInt() {
- return mLegacyInt;
- }
-
- /**
- * Returns the keep-connected reason, or KEEP_CONNECTED_NONE.
- */
- public int getKeepConnectedReason() {
- return mKeepConnectedReason;
- }
-
- /**
- * @return whether this score has a particular policy.
- *
- * @hide
- */
- @VisibleForTesting
- public boolean hasPolicy(final int policy) {
- return 0 != (mPolicies & (1L << policy));
- }
-
- /**
- * To the exclusive usage of FullScore
- * @hide
- */
- public long getPolicies() {
- return mPolicies;
- }
-
- /**
- * Whether this network should yield to a previously validated wifi gone bad.
- *
- * If this policy is set, other things being equal, the device will prefer a previously
- * validated WiFi even if this network is validated and the WiFi is not.
- * If this policy is not set, the device prefers the validated network.
- *
- * @hide
- */
- // TODO : Unhide this for telephony and have telephony call it on the relevant carriers.
- // In the mean time this is handled by Connectivity in a backward-compatible manner.
- public boolean shouldYieldToBadWifi() {
- return hasPolicy(POLICY_YIELD_TO_BAD_WIFI);
- }
-
- /**
- * Whether this network is primary for this transport.
- *
- * When multiple networks of the same transport are active, the device prefers the ones that
- * are primary. This is meant in particular for DS-DA devices with a user setting to choose the
- * default SIM card, or for WiFi STA+STA and make-before-break cases.
- *
- * @hide
- */
- @SystemApi
- public boolean isTransportPrimary() {
- return hasPolicy(POLICY_TRANSPORT_PRIMARY);
- }
-
- /**
- * Whether this network is exiting.
- *
- * If this policy is set, the device will expect this network to disconnect within seconds.
- * It will try to migrate to some other network if any is available, policy permitting, to
- * avoid service disruption.
- * This is useful in particular when a good cellular network is available and WiFi is getting
- * weak and risks disconnecting soon. The WiFi network should be marked as exiting so that
- * the device will prefer the reliable mobile network over this soon-to-be-lost WiFi.
- *
- * @hide
- */
- @SystemApi
- public boolean isExiting() {
- return hasPolicy(POLICY_EXITING);
- }
-
- @Override
- public String toString() {
- return "Score(" + mLegacyInt + " ; Policies : " + mPolicies + ")";
- }
-
- @Override
- public void writeToParcel(@NonNull final Parcel dest, final int flags) {
- dest.writeInt(mLegacyInt);
- dest.writeLong(mPolicies);
- dest.writeInt(mKeepConnectedReason);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @NonNull public static final Creator<NetworkScore> CREATOR = new Creator<>() {
- @Override
- @NonNull
- public NetworkScore createFromParcel(@NonNull final Parcel in) {
- return new NetworkScore(in);
- }
-
- @Override
- @NonNull
- public NetworkScore[] newArray(int size) {
- return new NetworkScore[size];
- }
- };
-
- /**
- * A builder for NetworkScore.
- */
- public static final class Builder {
- private static final long POLICY_NONE = 0L;
- private static final int INVALID_LEGACY_INT = Integer.MIN_VALUE;
- private int mLegacyInt = INVALID_LEGACY_INT;
- private int mKeepConnectedReason = KEEP_CONNECTED_NONE;
- private int mPolicies = 0;
-
- /**
- * Sets the legacy int for this score.
- *
- * This will be used for measurements and logs, but will no longer be used for ranking
- * networks against each other. Callers that existed before Android S should send what
- * they used to send as the int score.
- *
- * @param score the legacy int
- * @return this
- */
- @NonNull
- public Builder setLegacyInt(final int score) {
- mLegacyInt = score;
- return this;
- }
-
-
- /**
- * Set for a network that should never be preferred to a wifi that has ever been validated
- *
- * If this policy is set, other things being equal, the device will prefer a previously
- * validated WiFi even if this network is validated and the WiFi is not.
- * If this policy is not set, the device prefers the validated network.
- *
- * @return this builder
- * @hide
- */
- // TODO : Unhide this for telephony and have telephony call it on the relevant carriers.
- // In the mean time this is handled by Connectivity in a backward-compatible manner.
- @NonNull
- public Builder setShouldYieldToBadWifi(final boolean val) {
- if (val) {
- mPolicies |= (1L << POLICY_YIELD_TO_BAD_WIFI);
- } else {
- mPolicies &= ~(1L << POLICY_YIELD_TO_BAD_WIFI);
- }
- return this;
- }
-
- /**
- * Set for a network that is primary for this transport.
- *
- * When multiple networks of the same transport are active, the device prefers the ones that
- * are primary. This is meant in particular for DS-DA devices with a user setting to choose
- * the default SIM card, or for WiFi STA+STA and make-before-break cases.
- *
- * @return this builder
- * @hide
- */
- @SystemApi
- @NonNull
- public Builder setTransportPrimary(final boolean val) {
- if (val) {
- mPolicies |= (1L << POLICY_TRANSPORT_PRIMARY);
- } else {
- mPolicies &= ~(1L << POLICY_TRANSPORT_PRIMARY);
- }
- return this;
- }
-
- /**
- * Set for a network that will likely disconnect in a few seconds.
- *
- * If this policy is set, the device will expect this network to disconnect within seconds.
- * It will try to migrate to some other network if any is available, policy permitting, to
- * avoid service disruption.
- * This is useful in particular when a good cellular network is available and WiFi is
- * getting weak and risks disconnecting soon. The WiFi network should be marked as exiting
- * so that the device will prefer the reliable mobile network over this soon-to-be-lost
- * WiFi.
- *
- * @return this builder
- * @hide
- */
- @SystemApi
- @NonNull
- public Builder setExiting(final boolean val) {
- if (val) {
- mPolicies |= (1L << POLICY_EXITING);
- } else {
- mPolicies &= ~(1L << POLICY_EXITING);
- }
- return this;
- }
-
- /**
- * Set the keep-connected reason.
- *
- * This can be reset by calling it again with {@link KEEP_CONNECTED_NONE}.
- */
- @NonNull
- public Builder setKeepConnectedReason(@KeepConnectedReason final int reason) {
- mKeepConnectedReason = reason;
- return this;
- }
-
- /**
- * Builds this NetworkScore.
- * @return The built NetworkScore object.
- */
- @NonNull
- public NetworkScore build() {
- return new NetworkScore(mLegacyInt, mPolicies, mKeepConnectedReason);
- }
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkState.java b/packages/Connectivity/framework/src/android/net/NetworkState.java
deleted file mode 100644
index 9b69674..0000000
--- a/packages/Connectivity/framework/src/android/net/NetworkState.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
-
-/**
- * Snapshot of network state.
- *
- * @hide
- */
-public class NetworkState implements Parcelable {
- private static final boolean VALIDATE_ROAMING_STATE = false;
-
- // TODO: remove and make members @NonNull.
- public static final NetworkState EMPTY = new NetworkState();
-
- public final NetworkInfo networkInfo;
- public final LinkProperties linkProperties;
- public final NetworkCapabilities networkCapabilities;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public final Network network;
- public final String subscriberId;
- public final int legacyNetworkType;
-
- private NetworkState() {
- networkInfo = null;
- linkProperties = null;
- networkCapabilities = null;
- network = null;
- subscriberId = null;
- legacyNetworkType = 0;
- }
-
- public NetworkState(int legacyNetworkType, @NonNull LinkProperties linkProperties,
- @NonNull NetworkCapabilities networkCapabilities, @NonNull Network network,
- @Nullable String subscriberId) {
- this(legacyNetworkType, new NetworkInfo(legacyNetworkType, 0, null, null), linkProperties,
- networkCapabilities, network, subscriberId);
- }
-
- // Constructor that used internally in ConnectivityService mainline module.
- public NetworkState(@NonNull NetworkInfo networkInfo, @NonNull LinkProperties linkProperties,
- @NonNull NetworkCapabilities networkCapabilities, @NonNull Network network,
- @Nullable String subscriberId) {
- this(networkInfo.getType(), networkInfo, linkProperties,
- networkCapabilities, network, subscriberId);
- }
-
- public NetworkState(int legacyNetworkType, @NonNull NetworkInfo networkInfo,
- @NonNull LinkProperties linkProperties,
- @NonNull NetworkCapabilities networkCapabilities, @NonNull Network network,
- @Nullable String subscriberId) {
- this.networkInfo = networkInfo;
- this.linkProperties = linkProperties;
- this.networkCapabilities = networkCapabilities;
- this.network = network;
- this.subscriberId = subscriberId;
- this.legacyNetworkType = legacyNetworkType;
-
- // This object is an atomic view of a network, so the various components
- // should always agree on roaming state.
- if (VALIDATE_ROAMING_STATE && networkInfo != null && networkCapabilities != null) {
- if (networkInfo.isRoaming() == networkCapabilities
- .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)) {
- Log.wtf("NetworkState", "Roaming state disagreement between " + networkInfo
- + " and " + networkCapabilities);
- }
- }
- }
-
- @UnsupportedAppUsage
- public NetworkState(Parcel in) {
- networkInfo = in.readParcelable(null);
- linkProperties = in.readParcelable(null);
- networkCapabilities = in.readParcelable(null);
- network = in.readParcelable(null);
- subscriberId = in.readString();
- legacyNetworkType = in.readInt();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeParcelable(networkInfo, flags);
- out.writeParcelable(linkProperties, flags);
- out.writeParcelable(networkCapabilities, flags);
- out.writeParcelable(network, flags);
- out.writeString(subscriberId);
- out.writeInt(legacyNetworkType);
- }
-
- @UnsupportedAppUsage
- @NonNull
- public static final Creator<NetworkState> CREATOR = new Creator<NetworkState>() {
- @Override
- public NetworkState createFromParcel(Parcel in) {
- return new NetworkState(in);
- }
-
- @Override
- public NetworkState[] newArray(int size) {
- return new NetworkState[size];
- }
- };
-}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkUtils.java b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
deleted file mode 100644
index 2679b62..0000000
--- a/packages/Connectivity/framework/src/android/net/NetworkUtils.java
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * 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.
- */
-
-package android.net;
-
-import static android.net.ConnectivityManager.NETID_UNSET;
-
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
-import android.system.ErrnoException;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.net.module.util.Inet4AddressUtils;
-
-import java.io.FileDescriptor;
-import java.math.BigInteger;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.Locale;
-import java.util.TreeSet;
-
-/**
- * Native methods for managing network interfaces.
- *
- * {@hide}
- */
-public class NetworkUtils {
- static {
- System.loadLibrary("framework-connectivity-jni");
- }
-
- private static final String TAG = "NetworkUtils";
-
- /**
- * Attaches a socket filter that drops all of incoming packets.
- * @param fd the socket's {@link FileDescriptor}.
- */
- public static native void attachDropAllBPFFilter(FileDescriptor fd) throws SocketException;
-
- /**
- * Detaches a socket filter.
- * @param fd the socket's {@link FileDescriptor}.
- */
- public static native void detachBPFFilter(FileDescriptor fd) throws SocketException;
-
- private static native boolean bindProcessToNetworkHandle(long netHandle);
-
- /**
- * Binds the current process to the network designated by {@code netId}. All sockets created
- * in the future (and not explicitly bound via a bound {@link SocketFactory} (see
- * {@link Network#getSocketFactory}) will be bound to this network. Note that if this
- * {@code Network} ever disconnects all sockets created in this way will cease to work. This
- * is by design so an application doesn't accidentally use sockets it thinks are still bound to
- * a particular {@code Network}. Passing NETID_UNSET clears the binding.
- */
- public static boolean bindProcessToNetwork(int netId) {
- return bindProcessToNetworkHandle(new Network(netId).getNetworkHandle());
- }
-
- private static native long getBoundNetworkHandleForProcess();
-
- /**
- * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if
- * {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}.
- */
- public static int getBoundNetworkForProcess() {
- final long netHandle = getBoundNetworkHandleForProcess();
- return netHandle == 0L ? NETID_UNSET : Network.fromNetworkHandle(netHandle).getNetId();
- }
-
- /**
- * Binds host resolutions performed by this process to the network designated by {@code netId}.
- * {@link #bindProcessToNetwork} takes precedence over this setting. Passing NETID_UNSET clears
- * the binding.
- *
- * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
- */
- @Deprecated
- public native static boolean bindProcessToNetworkForHostResolution(int netId);
-
- private static native int bindSocketToNetworkHandle(FileDescriptor fd, long netHandle);
-
- /**
- * Explicitly binds {@code fd} to the network designated by {@code netId}. This
- * overrides any binding via {@link #bindProcessToNetwork}.
- * @return 0 on success or negative errno on failure.
- */
- public static int bindSocketToNetwork(FileDescriptor fd, int netId) {
- return bindSocketToNetworkHandle(fd, new Network(netId).getNetworkHandle());
- }
-
- /**
- * Determine if {@code uid} can access network designated by {@code netId}.
- * @return {@code true} if {@code uid} can access network, {@code false} otherwise.
- */
- public static boolean queryUserAccess(int uid, int netId) {
- // TODO (b/183485986): remove this method
- return false;
- }
-
- private static native FileDescriptor resNetworkSend(
- long netHandle, byte[] msg, int msglen, int flags) throws ErrnoException;
-
- /**
- * DNS resolver series jni method.
- * Issue the query {@code msg} on the network designated by {@code netId}.
- * {@code flags} is an additional config to control actual querying behavior.
- * @return a file descriptor to watch for read events
- */
- public static FileDescriptor resNetworkSend(
- int netId, byte[] msg, int msglen, int flags) throws ErrnoException {
- return resNetworkSend(new Network(netId).getNetworkHandle(), msg, msglen, flags);
- }
-
- private static native FileDescriptor resNetworkQuery(
- long netHandle, String dname, int nsClass, int nsType, int flags) throws ErrnoException;
-
- /**
- * DNS resolver series jni method.
- * Look up the {@code nsClass} {@code nsType} Resource Record (RR) associated
- * with Domain Name {@code dname} on the network designated by {@code netId}.
- * {@code flags} is an additional config to control actual querying behavior.
- * @return a file descriptor to watch for read events
- */
- public static FileDescriptor resNetworkQuery(
- int netId, String dname, int nsClass, int nsType, int flags) throws ErrnoException {
- return resNetworkQuery(new Network(netId).getNetworkHandle(), dname, nsClass, nsType,
- flags);
- }
-
- /**
- * DNS resolver series jni method.
- * Read a result for the query associated with the {@code fd}.
- * @return DnsResponse containing blob answer and rcode
- */
- public static native DnsResolver.DnsResponse resNetworkResult(FileDescriptor fd)
- throws ErrnoException;
-
- /**
- * DNS resolver series jni method.
- * Attempts to cancel the in-progress query associated with the {@code fd}.
- */
- public static native void resNetworkCancel(FileDescriptor fd);
-
- /**
- * DNS resolver series jni method.
- * Attempts to get network which resolver will use if no network is explicitly selected.
- */
- public static native Network getDnsNetwork() throws ErrnoException;
-
- /**
- * Get the tcp repair window associated with the {@code fd}.
- *
- * @param fd the tcp socket's {@link FileDescriptor}.
- * @return a {@link TcpRepairWindow} object indicates tcp window size.
- */
- public static native TcpRepairWindow getTcpRepairWindow(FileDescriptor fd)
- throws ErrnoException;
-
- /**
- * @see Inet4AddressUtils#intToInet4AddressHTL(int)
- * @deprecated Use either {@link Inet4AddressUtils#intToInet4AddressHTH(int)}
- * or {@link Inet4AddressUtils#intToInet4AddressHTL(int)}
- */
- @Deprecated
- @UnsupportedAppUsage
- public static InetAddress intToInetAddress(int hostAddress) {
- return Inet4AddressUtils.intToInet4AddressHTL(hostAddress);
- }
-
- /**
- * @see Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)
- * @deprecated Use either {@link Inet4AddressUtils#inet4AddressToIntHTH(Inet4Address)}
- * or {@link Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)}
- */
- @Deprecated
- public static int inetAddressToInt(Inet4Address inetAddr)
- throws IllegalArgumentException {
- return Inet4AddressUtils.inet4AddressToIntHTL(inetAddr);
- }
-
- /**
- * @see Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)
- * @deprecated Use either {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTH(int)}
- * or {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)}
- */
- @Deprecated
- @UnsupportedAppUsage
- public static int prefixLengthToNetmaskInt(int prefixLength)
- throws IllegalArgumentException {
- return Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL(prefixLength);
- }
-
- /**
- * Convert a IPv4 netmask integer to a prefix length
- * @param netmask as an integer (0xff000000 for a /8 subnet)
- * @return the network prefix length
- */
- public static int netmaskIntToPrefixLength(int netmask) {
- return Integer.bitCount(netmask);
- }
-
- /**
- * Convert an IPv4 netmask to a prefix length, checking that the netmask is contiguous.
- * @param netmask as a {@code Inet4Address}.
- * @return the network prefix length
- * @throws IllegalArgumentException the specified netmask was not contiguous.
- * @hide
- * @deprecated use {@link Inet4AddressUtils#netmaskToPrefixLength(Inet4Address)}
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @Deprecated
- public static int netmaskToPrefixLength(Inet4Address netmask) {
- // This is only here because some apps seem to be using it (@UnsupportedAppUsage).
- return Inet4AddressUtils.netmaskToPrefixLength(netmask);
- }
-
-
- /**
- * Create an InetAddress from a string where the string must be a standard
- * representation of a V4 or V6 address. Avoids doing a DNS lookup on failure
- * but it will throw an IllegalArgumentException in that case.
- * @param addrString
- * @return the InetAddress
- * @hide
- * @deprecated Use {@link InetAddresses#parseNumericAddress(String)}, if possible.
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
- @Deprecated
- public static InetAddress numericToInetAddress(String addrString)
- throws IllegalArgumentException {
- return InetAddresses.parseNumericAddress(addrString);
- }
-
- /**
- * Returns the implicit netmask of an IPv4 address, as was the custom before 1993.
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static int getImplicitNetmask(Inet4Address address) {
- // Only here because it seems to be used by apps
- return Inet4AddressUtils.getImplicitNetmask(address);
- }
-
- /**
- * Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64".
- * @hide
- */
- public static Pair<InetAddress, Integer> parseIpAndMask(String ipAndMaskString) {
- InetAddress address = null;
- int prefixLength = -1;
- try {
- String[] pieces = ipAndMaskString.split("/", 2);
- prefixLength = Integer.parseInt(pieces[1]);
- address = InetAddresses.parseNumericAddress(pieces[0]);
- } catch (NullPointerException e) { // Null string.
- } catch (ArrayIndexOutOfBoundsException e) { // No prefix length.
- } catch (NumberFormatException e) { // Non-numeric prefix.
- } catch (IllegalArgumentException e) { // Invalid IP address.
- }
-
- if (address == null || prefixLength == -1) {
- throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString);
- }
-
- return new Pair<InetAddress, Integer>(address, prefixLength);
- }
-
- /**
- * Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64".
- * @hide
- *
- * @deprecated This method is used only for IpPrefix and LinkAddress. Since Android S, use
- * {@link #parseIpAndMask(String)}, if possible.
- */
- @Deprecated
- public static Pair<InetAddress, Integer> legacyParseIpAndMask(String ipAndMaskString) {
- InetAddress address = null;
- int prefixLength = -1;
- try {
- String[] pieces = ipAndMaskString.split("/", 2);
- prefixLength = Integer.parseInt(pieces[1]);
- if (pieces[0] == null || pieces[0].isEmpty()) {
- final byte[] bytes = new byte[16];
- bytes[15] = 1;
- return new Pair<InetAddress, Integer>(Inet6Address.getByAddress(
- "ip6-localhost"/* host */, bytes, 0 /* scope_id */), prefixLength);
- }
-
- if (pieces[0].startsWith("[")
- && pieces[0].endsWith("]")
- && pieces[0].indexOf(':') != -1) {
- pieces[0] = pieces[0].substring(1, pieces[0].length() - 1);
- }
- address = InetAddresses.parseNumericAddress(pieces[0]);
- } catch (NullPointerException e) { // Null string.
- } catch (ArrayIndexOutOfBoundsException e) { // No prefix length.
- } catch (NumberFormatException e) { // Non-numeric prefix.
- } catch (IllegalArgumentException e) { // Invalid IP address.
- } catch (UnknownHostException e) { // IP address length is illegal
- }
-
- if (address == null || prefixLength == -1) {
- throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString);
- }
-
- return new Pair<InetAddress, Integer>(address, prefixLength);
- }
-
- /**
- * Convert a 32 char hex string into a Inet6Address.
- * throws a runtime exception if the string isn't 32 chars, isn't hex or can't be
- * made into an Inet6Address
- * @param addrHexString a 32 character hex string representing an IPv6 addr
- * @return addr an InetAddress representation for the string
- */
- public static InetAddress hexToInet6Address(String addrHexString)
- throws IllegalArgumentException {
- try {
- return numericToInetAddress(String.format(Locale.US, "%s:%s:%s:%s:%s:%s:%s:%s",
- addrHexString.substring(0,4), addrHexString.substring(4,8),
- addrHexString.substring(8,12), addrHexString.substring(12,16),
- addrHexString.substring(16,20), addrHexString.substring(20,24),
- addrHexString.substring(24,28), addrHexString.substring(28,32)));
- } catch (Exception e) {
- Log.e("NetworkUtils", "error in hexToInet6Address(" + addrHexString + "): " + e);
- throw new IllegalArgumentException(e);
- }
- }
-
- /**
- * Trim leading zeros from IPv4 address strings
- * Our base libraries will interpret that as octel..
- * Must leave non v4 addresses and host names alone.
- * For example, 192.168.000.010 -> 192.168.0.10
- * TODO - fix base libraries and remove this function
- * @param addr a string representing an ip addr
- * @return a string propertly trimmed
- */
- @UnsupportedAppUsage
- public static String trimV4AddrZeros(String addr) {
- return Inet4AddressUtils.trimAddressZeros(addr);
- }
-
- /**
- * Returns a prefix set without overlaps.
- *
- * This expects the src set to be sorted from shorter to longer. Results are undefined
- * failing this condition. The returned prefix set is sorted in the same order as the
- * passed set, with the same comparator.
- */
- private static TreeSet<IpPrefix> deduplicatePrefixSet(final TreeSet<IpPrefix> src) {
- final TreeSet<IpPrefix> dst = new TreeSet<>(src.comparator());
- // Prefixes match addresses that share their upper part up to their length, therefore
- // the only kind of possible overlap in two prefixes is strict inclusion of the longer
- // (more restrictive) in the shorter (including equivalence if they have the same
- // length).
- // Because prefixes in the src set are sorted from shorter to longer, deduplicating
- // is done by simply iterating in order, and not adding any longer prefix that is
- // already covered by a shorter one.
- newPrefixes:
- for (IpPrefix newPrefix : src) {
- for (IpPrefix existingPrefix : dst) {
- if (existingPrefix.containsPrefix(newPrefix)) {
- continue newPrefixes;
- }
- }
- dst.add(newPrefix);
- }
- return dst;
- }
-
- /**
- * Returns how many IPv4 addresses match any of the prefixes in the passed ordered set.
- *
- * Obviously this returns an integral value between 0 and 2**32.
- * The behavior is undefined if any of the prefixes is not an IPv4 prefix or if the
- * set is not ordered smallest prefix to longer prefix.
- *
- * @param prefixes the set of prefixes, ordered by length
- */
- public static long routedIPv4AddressCount(final TreeSet<IpPrefix> prefixes) {
- long routedIPCount = 0;
- for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) {
- if (!prefix.isIPv4()) {
- Log.wtf(TAG, "Non-IPv4 prefix in routedIPv4AddressCount");
- }
- int rank = 32 - prefix.getPrefixLength();
- routedIPCount += 1L << rank;
- }
- return routedIPCount;
- }
-
- /**
- * Returns how many IPv6 addresses match any of the prefixes in the passed ordered set.
- *
- * This returns a BigInteger between 0 and 2**128.
- * The behavior is undefined if any of the prefixes is not an IPv6 prefix or if the
- * set is not ordered smallest prefix to longer prefix.
- */
- public static BigInteger routedIPv6AddressCount(final TreeSet<IpPrefix> prefixes) {
- BigInteger routedIPCount = BigInteger.ZERO;
- for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) {
- if (!prefix.isIPv6()) {
- Log.wtf(TAG, "Non-IPv6 prefix in routedIPv6AddressCount");
- }
- int rank = 128 - prefix.getPrefixLength();
- routedIPCount = routedIPCount.add(BigInteger.ONE.shiftLeft(rank));
- }
- return routedIPCount;
- }
-
-}
diff --git a/packages/Connectivity/framework/src/android/net/OemNetworkPreferences.java b/packages/Connectivity/framework/src/android/net/OemNetworkPreferences.java
deleted file mode 100644
index 2bb006d..0000000
--- a/packages/Connectivity/framework/src/android/net/OemNetworkPreferences.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.Bundle;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * Network preferences to set the default active network on a per-application basis as per a given
- * {@link OemNetworkPreference}. An example of this would be to set an application's network
- * preference to {@link #OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK} which would have the default
- * network for that application set to an unmetered network first if available and if not, it then
- * set that application's default network to an OEM managed network if available.
- *
- * @hide
- */
-@SystemApi
-public final class OemNetworkPreferences implements Parcelable {
- // Valid production preferences must be > 0, negative values reserved for testing
- /**
- * This preference is only to be used for testing and nothing else.
- * Use only TRANSPORT_TEST transport networks.
- * @hide
- */
- public static final int OEM_NETWORK_PREFERENCE_TEST_ONLY = -2;
-
- /**
- * This preference is only to be used for testing and nothing else.
- * If an unmetered network is available, use it.
- * Otherwise, if a network with the TRANSPORT_TEST transport is available, use it.
- * Otherwise, use the general default network.
- * @hide
- */
- public static final int OEM_NETWORK_PREFERENCE_TEST = -1;
-
- /**
- * Default in case this value is not set. Using it will result in an error.
- */
- public static final int OEM_NETWORK_PREFERENCE_UNINITIALIZED = 0;
-
- /**
- * If an unmetered network is available, use it.
- * Otherwise, if a network with the OEM_PAID capability is available, use it.
- * Otherwise, use the general default network.
- */
- public static final int OEM_NETWORK_PREFERENCE_OEM_PAID = 1;
-
- /**
- * If an unmetered network is available, use it.
- * Otherwise, if a network with the OEM_PAID capability is available, use it.
- * Otherwise, the app doesn't get a default network.
- */
- public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK = 2;
-
- /**
- * Use only NET_CAPABILITY_OEM_PAID networks.
- */
- public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY = 3;
-
- /**
- * Use only NET_CAPABILITY_OEM_PRIVATE networks.
- */
- public static final int OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY = 4;
-
- /**
- * The max allowed value for an OEM network preference.
- * @hide
- */
- public static final int OEM_NETWORK_PREFERENCE_MAX = OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
-
- @NonNull
- private final Bundle mNetworkMappings;
-
- /**
- * Return whether this object is empty.
- * @hide
- */
- public boolean isEmpty() {
- return mNetworkMappings.keySet().size() == 0;
- }
-
- /**
- * Return the currently built application package name to {@link OemNetworkPreference} mappings.
- * @return the current network preferences map.
- */
- @NonNull
- public Map<String, Integer> getNetworkPreferences() {
- return convertToUnmodifiableMap(mNetworkMappings);
- }
-
- private OemNetworkPreferences(@NonNull final Bundle networkMappings) {
- Objects.requireNonNull(networkMappings);
- mNetworkMappings = (Bundle) networkMappings.clone();
- }
-
- @Override
- public String toString() {
- return "OemNetworkPreferences{" + "mNetworkMappings=" + getNetworkPreferences() + '}';
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- OemNetworkPreferences that = (OemNetworkPreferences) o;
-
- return mNetworkMappings.size() == that.mNetworkMappings.size()
- && mNetworkMappings.toString().equals(that.mNetworkMappings.toString());
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mNetworkMappings);
- }
-
- /**
- * Builder used to create {@link OemNetworkPreferences} objects. Specify the preferred Network
- * to package name mappings.
- */
- public static final class Builder {
- private final Bundle mNetworkMappings;
-
- public Builder() {
- mNetworkMappings = new Bundle();
- }
-
- /**
- * Constructor to populate the builder's values with an already built
- * {@link OemNetworkPreferences}.
- * @param preferences the {@link OemNetworkPreferences} to populate with.
- */
- public Builder(@NonNull final OemNetworkPreferences preferences) {
- Objects.requireNonNull(preferences);
- mNetworkMappings = (Bundle) preferences.mNetworkMappings.clone();
- }
-
- /**
- * Add a network preference for a given package. Previously stored values for the given
- * package will be overwritten.
- *
- * @param packageName full package name (e.g.: "com.google.apps.contacts") of the app
- * to use the given preference
- * @param preference the desired network preference to use
- * @return The builder to facilitate chaining.
- */
- @NonNull
- public Builder addNetworkPreference(@NonNull final String packageName,
- @OemNetworkPreference final int preference) {
- Objects.requireNonNull(packageName);
- mNetworkMappings.putInt(packageName, preference);
- return this;
- }
-
- /**
- * Remove a network preference for a given package.
- *
- * @param packageName full package name (e.g.: "com.google.apps.contacts") of the app to
- * remove a preference for.
- * @return The builder to facilitate chaining.
- */
- @NonNull
- public Builder clearNetworkPreference(@NonNull final String packageName) {
- Objects.requireNonNull(packageName);
- mNetworkMappings.remove(packageName);
- return this;
- }
-
- /**
- * Build {@link OemNetworkPreferences} return the current OEM network preferences.
- */
- @NonNull
- public OemNetworkPreferences build() {
- return new OemNetworkPreferences(mNetworkMappings);
- }
- }
-
- private static Map<String, Integer> convertToUnmodifiableMap(@NonNull final Bundle bundle) {
- final Map<String, Integer> networkPreferences = new HashMap<>();
- for (final String key : bundle.keySet()) {
- networkPreferences.put(key, bundle.getInt(key));
- }
- return Collections.unmodifiableMap(networkPreferences);
- }
-
- /** @hide */
- @IntDef(prefix = "OEM_NETWORK_PREFERENCE_", value = {
- OEM_NETWORK_PREFERENCE_TEST_ONLY,
- OEM_NETWORK_PREFERENCE_TEST,
- OEM_NETWORK_PREFERENCE_UNINITIALIZED,
- OEM_NETWORK_PREFERENCE_OEM_PAID,
- OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK,
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY,
- OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface OemNetworkPreference {}
-
- /**
- * Return the string value for OemNetworkPreference
- *
- * @param value int value of OemNetworkPreference
- * @return string version of OemNetworkPreference
- *
- * @hide
- */
- @NonNull
- public static String oemNetworkPreferenceToString(@OemNetworkPreference int value) {
- switch (value) {
- case OEM_NETWORK_PREFERENCE_TEST_ONLY:
- return "OEM_NETWORK_PREFERENCE_TEST_ONLY";
- case OEM_NETWORK_PREFERENCE_TEST:
- return "OEM_NETWORK_PREFERENCE_TEST";
- case OEM_NETWORK_PREFERENCE_UNINITIALIZED:
- return "OEM_NETWORK_PREFERENCE_UNINITIALIZED";
- case OEM_NETWORK_PREFERENCE_OEM_PAID:
- return "OEM_NETWORK_PREFERENCE_OEM_PAID";
- case OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK:
- return "OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK";
- case OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY:
- return "OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY";
- case OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY:
- return "OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY";
- default:
- return Integer.toHexString(value);
- }
- }
-
- @Override
- public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
- dest.writeBundle(mNetworkMappings);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @NonNull
- public static final Parcelable.Creator<OemNetworkPreferences> CREATOR =
- new Parcelable.Creator<OemNetworkPreferences>() {
- @Override
- public OemNetworkPreferences[] newArray(int size) {
- return new OemNetworkPreferences[size];
- }
-
- @Override
- public OemNetworkPreferences createFromParcel(@NonNull android.os.Parcel in) {
- return new OemNetworkPreferences(
- in.readBundle(getClass().getClassLoader()));
- }
- };
-}
diff --git a/packages/Connectivity/framework/src/android/net/ParseException.java b/packages/Connectivity/framework/src/android/net/ParseException.java
deleted file mode 100644
index 9d4727a..0000000
--- a/packages/Connectivity/framework/src/android/net/ParseException.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.NonNull;
-
-/**
- * Thrown when parsing failed.
- */
-// See non-public class {@link WebAddress}.
-public class ParseException extends RuntimeException {
- public String response;
-
- public ParseException(@NonNull String response) {
- super(response);
- this.response = response;
- }
-
- public ParseException(@NonNull String response, @NonNull Throwable cause) {
- super(response, cause);
- this.response = response;
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/ProxyInfo.java b/packages/Connectivity/framework/src/android/net/ProxyInfo.java
deleted file mode 100644
index 0deda37..0000000
--- a/packages/Connectivity/framework/src/android/net/ProxyInfo.java
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-import com.android.net.module.util.ProxyUtils;
-
-import java.net.InetSocketAddress;
-import java.net.URLConnection;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * Describes a proxy configuration.
- *
- * Proxy configurations are already integrated within the {@code java.net} and
- * Apache HTTP stack. So {@link URLConnection} and Apache's {@code HttpClient} will use
- * them automatically.
- *
- * Other HTTP stacks will need to obtain the proxy info by watching for the
- * {@link Proxy#PROXY_CHANGE_ACTION} broadcast and calling methods such as
- * {@link android.net.ConnectivityManager#getDefaultProxy}.
- */
-public class ProxyInfo implements Parcelable {
-
- private final String mHost;
- private final int mPort;
- private final String mExclusionList;
- private final String[] mParsedExclusionList;
- private final Uri mPacFileUrl;
-
- /**
- *@hide
- */
- public static final String LOCAL_EXCL_LIST = "";
- /**
- *@hide
- */
- public static final int LOCAL_PORT = -1;
- /**
- *@hide
- */
- public static final String LOCAL_HOST = "localhost";
-
- /**
- * Constructs a {@link ProxyInfo} object that points at a Direct proxy
- * on the specified host and port.
- */
- public static ProxyInfo buildDirectProxy(String host, int port) {
- return new ProxyInfo(host, port, null);
- }
-
- /**
- * Constructs a {@link ProxyInfo} object that points at a Direct proxy
- * on the specified host and port.
- *
- * The proxy will not be used to access any host in exclusion list, exclList.
- *
- * @param exclList Hosts to exclude using the proxy on connections for. These
- * hosts can use wildcards such as *.example.com.
- */
- public static ProxyInfo buildDirectProxy(String host, int port, List<String> exclList) {
- String[] array = exclList.toArray(new String[exclList.size()]);
- return new ProxyInfo(host, port, TextUtils.join(",", array), array);
- }
-
- /**
- * Construct a {@link ProxyInfo} that will download and run the PAC script
- * at the specified URL.
- */
- public static ProxyInfo buildPacProxy(Uri pacUri) {
- return new ProxyInfo(pacUri);
- }
-
- /**
- * Construct a {@link ProxyInfo} object that will download and run the PAC script at the
- * specified URL and port.
- */
- @NonNull
- public static ProxyInfo buildPacProxy(@NonNull Uri pacUrl, int port) {
- return new ProxyInfo(pacUrl, port);
- }
-
- /**
- * Create a ProxyProperties that points at a HTTP Proxy.
- * @hide
- */
- @UnsupportedAppUsage
- public ProxyInfo(String host, int port, String exclList) {
- mHost = host;
- mPort = port;
- mExclusionList = exclList;
- mParsedExclusionList = parseExclusionList(mExclusionList);
- mPacFileUrl = Uri.EMPTY;
- }
-
- /**
- * Create a ProxyProperties that points at a PAC URL.
- * @hide
- */
- public ProxyInfo(@NonNull Uri pacFileUrl) {
- mHost = LOCAL_HOST;
- mPort = LOCAL_PORT;
- mExclusionList = LOCAL_EXCL_LIST;
- mParsedExclusionList = parseExclusionList(mExclusionList);
- if (pacFileUrl == null) {
- throw new NullPointerException();
- }
- mPacFileUrl = pacFileUrl;
- }
-
- /**
- * Only used in PacProxyService after Local Proxy is bound.
- * @hide
- */
- public ProxyInfo(@NonNull Uri pacFileUrl, int localProxyPort) {
- mHost = LOCAL_HOST;
- mPort = localProxyPort;
- mExclusionList = LOCAL_EXCL_LIST;
- mParsedExclusionList = parseExclusionList(mExclusionList);
- if (pacFileUrl == null) {
- throw new NullPointerException();
- }
- mPacFileUrl = pacFileUrl;
- }
-
- private static String[] parseExclusionList(String exclusionList) {
- if (exclusionList == null) {
- return new String[0];
- } else {
- return exclusionList.toLowerCase(Locale.ROOT).split(",");
- }
- }
-
- private ProxyInfo(String host, int port, String exclList, String[] parsedExclList) {
- mHost = host;
- mPort = port;
- mExclusionList = exclList;
- mParsedExclusionList = parsedExclList;
- mPacFileUrl = Uri.EMPTY;
- }
-
- /**
- * A copy constructor to hold proxy properties.
- */
- public ProxyInfo(@Nullable ProxyInfo source) {
- if (source != null) {
- mHost = source.getHost();
- mPort = source.getPort();
- mPacFileUrl = source.mPacFileUrl;
- mExclusionList = source.getExclusionListAsString();
- mParsedExclusionList = source.mParsedExclusionList;
- } else {
- mHost = null;
- mPort = 0;
- mExclusionList = null;
- mParsedExclusionList = null;
- mPacFileUrl = Uri.EMPTY;
- }
- }
-
- /**
- * @hide
- */
- public InetSocketAddress getSocketAddress() {
- InetSocketAddress inetSocketAddress = null;
- try {
- inetSocketAddress = new InetSocketAddress(mHost, mPort);
- } catch (IllegalArgumentException e) { }
- return inetSocketAddress;
- }
-
- /**
- * Returns the URL of the current PAC script or null if there is
- * no PAC script.
- */
- public Uri getPacFileUrl() {
- return mPacFileUrl;
- }
-
- /**
- * When configured to use a Direct Proxy this returns the host
- * of the proxy.
- */
- public String getHost() {
- return mHost;
- }
-
- /**
- * When configured to use a Direct Proxy this returns the port
- * of the proxy
- */
- public int getPort() {
- return mPort;
- }
-
- /**
- * When configured to use a Direct Proxy this returns the list
- * of hosts for which the proxy is ignored.
- */
- public String[] getExclusionList() {
- return mParsedExclusionList;
- }
-
- /**
- * comma separated
- * @hide
- */
- @Nullable
- public String getExclusionListAsString() {
- return mExclusionList;
- }
-
- /**
- * Return true if the pattern of proxy is valid, otherwise return false.
- */
- public boolean isValid() {
- if (!Uri.EMPTY.equals(mPacFileUrl)) return true;
- return ProxyUtils.PROXY_VALID == ProxyUtils.validate(mHost == null ? "" : mHost,
- mPort == 0 ? "" : Integer.toString(mPort),
- mExclusionList == null ? "" : mExclusionList);
- }
-
- /**
- * @hide
- */
- public java.net.Proxy makeProxy() {
- java.net.Proxy proxy = java.net.Proxy.NO_PROXY;
- if (mHost != null) {
- try {
- InetSocketAddress inetSocketAddress = new InetSocketAddress(mHost, mPort);
- proxy = new java.net.Proxy(java.net.Proxy.Type.HTTP, inetSocketAddress);
- } catch (IllegalArgumentException e) {
- }
- }
- return proxy;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- if (!Uri.EMPTY.equals(mPacFileUrl)) {
- sb.append("PAC Script: ");
- sb.append(mPacFileUrl);
- }
- if (mHost != null) {
- sb.append("[");
- sb.append(mHost);
- sb.append("] ");
- sb.append(Integer.toString(mPort));
- if (mExclusionList != null) {
- sb.append(" xl=").append(mExclusionList);
- }
- } else {
- sb.append("[ProxyProperties.mHost == null]");
- }
- return sb.toString();
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (!(o instanceof ProxyInfo)) return false;
- ProxyInfo p = (ProxyInfo)o;
- // If PAC URL is present in either then they must be equal.
- // Other parameters will only be for fall back.
- if (!Uri.EMPTY.equals(mPacFileUrl)) {
- return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort;
- }
- if (!Uri.EMPTY.equals(p.mPacFileUrl)) {
- return false;
- }
- if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) {
- return false;
- }
- if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) {
- return false;
- }
- if (mHost != null && p.mHost == null) return false;
- if (mHost == null && p.mHost != null) return false;
- if (mPort != p.mPort) return false;
- return true;
- }
-
- /**
- * Implement the Parcelable interface
- * @hide
- */
- public int describeContents() {
- return 0;
- }
-
- @Override
- /*
- * generate hashcode based on significant fields
- */
- public int hashCode() {
- return ((null == mHost) ? 0 : mHost.hashCode())
- + ((null == mExclusionList) ? 0 : mExclusionList.hashCode())
- + mPort;
- }
-
- /**
- * Implement the Parcelable interface.
- * @hide
- */
- public void writeToParcel(Parcel dest, int flags) {
- if (!Uri.EMPTY.equals(mPacFileUrl)) {
- dest.writeByte((byte)1);
- mPacFileUrl.writeToParcel(dest, 0);
- dest.writeInt(mPort);
- return;
- } else {
- dest.writeByte((byte)0);
- }
- if (mHost != null) {
- dest.writeByte((byte)1);
- dest.writeString(mHost);
- dest.writeInt(mPort);
- } else {
- dest.writeByte((byte)0);
- }
- dest.writeString(mExclusionList);
- dest.writeStringArray(mParsedExclusionList);
- }
-
- public static final @android.annotation.NonNull Creator<ProxyInfo> CREATOR =
- new Creator<ProxyInfo>() {
- public ProxyInfo createFromParcel(Parcel in) {
- String host = null;
- int port = 0;
- if (in.readByte() != 0) {
- Uri url = Uri.CREATOR.createFromParcel(in);
- int localPort = in.readInt();
- return new ProxyInfo(url, localPort);
- }
- if (in.readByte() != 0) {
- host = in.readString();
- port = in.readInt();
- }
- String exclList = in.readString();
- String[] parsedExclList = in.createStringArray();
- ProxyInfo proxyProperties = new ProxyInfo(host, port, exclList, parsedExclList);
- return proxyProperties;
- }
-
- public ProxyInfo[] newArray(int size) {
- return new ProxyInfo[size];
- }
- };
-}
diff --git a/packages/Connectivity/framework/src/android/net/QosCallback.java b/packages/Connectivity/framework/src/android/net/QosCallback.java
deleted file mode 100644
index 22f06bc..0000000
--- a/packages/Connectivity/framework/src/android/net/QosCallback.java
+++ /dev/null
@@ -1,91 +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.net;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-
-import java.util.concurrent.Executor;
-
-/**
- * Receives Qos information given a {@link Network}. The callback is registered with
- * {@link ConnectivityManager#registerQosCallback}.
- *
- * <p>
- * <br/>
- * The callback will no longer receive calls if any of the following takes place:
- * <ol>
- * <li>{@link ConnectivityManager#unregisterQosCallback(QosCallback)} is called with the same
- * callback instance.</li>
- * <li>{@link QosCallback#onError(QosCallbackException)} is called.</li>
- * <li>A network specific issue occurs. eg. Congestion on a carrier network.</li>
- * <li>The network registered with the callback has no associated QoS providers</li>
- * </ul>
- * {@hide}
- */
-@SystemApi
-public abstract class QosCallback {
- /**
- * Invoked after an error occurs on a registered callback. Once called, the callback is
- * automatically unregistered and the callback will no longer receive calls.
- *
- * <p>The underlying exception can either be a runtime exception or a custom exception made for
- * {@link QosCallback}. see: {@link QosCallbackException}.
- *
- * @param exception wraps the underlying cause
- */
- public void onError(@NonNull final QosCallbackException exception) {
- }
-
- /**
- * Called when a Qos Session first becomes available to the callback or if its attributes have
- * changed.
- * <p>
- * Note: The callback may be called multiple times with the same attributes.
- *
- * @param session the available session
- * @param sessionAttributes the attributes of the session
- */
- public void onQosSessionAvailable(@NonNull final QosSession session,
- @NonNull final QosSessionAttributes sessionAttributes) {
- }
-
- /**
- * Called after a Qos Session is lost.
- * <p>
- * At least one call to
- * {@link QosCallback#onQosSessionAvailable(QosSession, QosSessionAttributes)}
- * with the same {@link QosSession} will precede a call to lost.
- *
- * @param session the lost session
- */
- public void onQosSessionLost(@NonNull final QosSession session) {
- }
-
- /**
- * Thrown when there is a problem registering {@link QosCallback} with
- * {@link ConnectivityManager#registerQosCallback(QosSocketInfo, QosCallback, Executor)}.
- */
- public static class QosCallbackRegistrationException extends RuntimeException {
- /**
- * @hide
- */
- public QosCallbackRegistrationException() {
- super();
- }
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java b/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java
deleted file mode 100644
index de0fc24..0000000
--- a/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java
+++ /dev/null
@@ -1,148 +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.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.telephony.data.EpsBearerQosSessionAttributes;
-import android.telephony.data.NrQosSessionAttributes;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.Objects;
-import java.util.concurrent.Executor;
-
-/**
- * Sends messages from {@link com.android.server.ConnectivityService} to the registered
- * {@link QosCallback}.
- * <p/>
- * This is a satellite class of {@link ConnectivityManager} and not meant
- * to be used in other contexts.
- *
- * @hide
- */
-class QosCallbackConnection extends android.net.IQosCallback.Stub {
-
- @NonNull private final ConnectivityManager mConnectivityManager;
- @Nullable private volatile QosCallback mCallback;
- @NonNull private final Executor mExecutor;
-
- @VisibleForTesting
- @Nullable
- public QosCallback getCallback() {
- return mCallback;
- }
-
- /**
- * The constructor for the connection
- *
- * @param connectivityManager the mgr that created this connection
- * @param callback the callback to send messages back to
- * @param executor The executor on which the callback will be invoked. The provided
- * {@link Executor} must run callback sequentially, otherwise the order of
- * callbacks cannot be guaranteed.
- */
- QosCallbackConnection(@NonNull final ConnectivityManager connectivityManager,
- @NonNull final QosCallback callback,
- @NonNull final Executor executor) {
- mConnectivityManager = Objects.requireNonNull(connectivityManager,
- "connectivityManager must be non-null");
- mCallback = Objects.requireNonNull(callback, "callback must be non-null");
- mExecutor = Objects.requireNonNull(executor, "executor must be non-null");
- }
-
- /**
- * Called when either the {@link EpsBearerQosSessionAttributes} has changed or on the first time
- * the attributes have become available.
- *
- * @param session the session that is now available
- * @param attributes the corresponding attributes of session
- */
- @Override
- public void onQosEpsBearerSessionAvailable(@NonNull final QosSession session,
- @NonNull final EpsBearerQosSessionAttributes attributes) {
-
- mExecutor.execute(() -> {
- final QosCallback callback = mCallback;
- if (callback != null) {
- callback.onQosSessionAvailable(session, attributes);
- }
- });
- }
-
- /**
- * Called when either the {@link NrQosSessionAttributes} has changed or on the first time
- * the attributes have become available.
- *
- * @param session the session that is now available
- * @param attributes the corresponding attributes of session
- */
- @Override
- public void onNrQosSessionAvailable(@NonNull final QosSession session,
- @NonNull final NrQosSessionAttributes attributes) {
-
- mExecutor.execute(() -> {
- final QosCallback callback = mCallback;
- if (callback != null) {
- callback.onQosSessionAvailable(session, attributes);
- }
- });
- }
-
- /**
- * Called when the session is lost.
- *
- * @param session the session that was lost
- */
- @Override
- public void onQosSessionLost(@NonNull final QosSession session) {
- mExecutor.execute(() -> {
- final QosCallback callback = mCallback;
- if (callback != null) {
- callback.onQosSessionLost(session);
- }
- });
- }
-
- /**
- * Called when there is an error on the registered callback.
- *
- * @param errorType the type of error
- */
- @Override
- public void onError(@QosCallbackException.ExceptionType final int errorType) {
- mExecutor.execute(() -> {
- final QosCallback callback = mCallback;
- if (callback != null) {
- // Messages no longer need to be received since there was an error.
- stopReceivingMessages();
- mConnectivityManager.unregisterQosCallback(callback);
- callback.onError(QosCallbackException.createException(errorType));
- }
- });
- }
-
- /**
- * The callback will stop receiving messages.
- * <p/>
- * There are no synchronization guarantees on exactly when the callback will stop receiving
- * messages.
- */
- void stopReceivingMessages() {
- mCallback = null;
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/QosCallbackException.java b/packages/Connectivity/framework/src/android/net/QosCallbackException.java
deleted file mode 100644
index 7fd9a527e..0000000
--- a/packages/Connectivity/framework/src/android/net/QosCallbackException.java
+++ /dev/null
@@ -1,110 +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.net;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * This is the exception type passed back through the onError method on {@link QosCallback}.
- * {@link QosCallbackException#getCause()} contains the actual error that caused this exception.
- *
- * The possible exception types as causes are:
- * 1. {@link NetworkReleasedException}
- * 2. {@link SocketNotBoundException}
- * 3. {@link UnsupportedOperationException}
- * 4. {@link SocketLocalAddressChangedException}
- *
- * @hide
- */
-@SystemApi
-public final class QosCallbackException extends Exception {
-
- /** @hide */
- @IntDef(prefix = {"EX_TYPE_"}, value = {
- EX_TYPE_FILTER_NONE,
- EX_TYPE_FILTER_NETWORK_RELEASED,
- EX_TYPE_FILTER_SOCKET_NOT_BOUND,
- EX_TYPE_FILTER_NOT_SUPPORTED,
- EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ExceptionType {}
-
- private static final String TAG = "QosCallbackException";
-
- // Types of exceptions supported //
- /** {@hide} */
- public static final int EX_TYPE_FILTER_NONE = 0;
-
- /** {@hide} */
- public static final int EX_TYPE_FILTER_NETWORK_RELEASED = 1;
-
- /** {@hide} */
- public static final int EX_TYPE_FILTER_SOCKET_NOT_BOUND = 2;
-
- /** {@hide} */
- public static final int EX_TYPE_FILTER_NOT_SUPPORTED = 3;
-
- /** {@hide} */
- public static final int EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED = 4;
-
- /**
- * Creates exception based off of a type and message. Not all types of exceptions accept a
- * custom message.
- *
- * {@hide}
- */
- @NonNull
- static QosCallbackException createException(@ExceptionType final int type) {
- switch (type) {
- case EX_TYPE_FILTER_NETWORK_RELEASED:
- return new QosCallbackException(new NetworkReleasedException());
- case EX_TYPE_FILTER_SOCKET_NOT_BOUND:
- return new QosCallbackException(new SocketNotBoundException());
- case EX_TYPE_FILTER_NOT_SUPPORTED:
- return new QosCallbackException(new UnsupportedOperationException(
- "This device does not support the specified filter"));
- case EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED:
- return new QosCallbackException(
- new SocketLocalAddressChangedException());
- default:
- Log.wtf(TAG, "create: No case setup for exception type: '" + type + "'");
- return new QosCallbackException(
- new RuntimeException("Unknown exception code: " + type));
- }
- }
-
- /**
- * @hide
- */
- public QosCallbackException(@NonNull final String message) {
- super(message);
- }
-
- /**
- * @hide
- */
- public QosCallbackException(@NonNull final Throwable cause) {
- super(cause);
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/QosFilter.java b/packages/Connectivity/framework/src/android/net/QosFilter.java
deleted file mode 100644
index 957c867..0000000
--- a/packages/Connectivity/framework/src/android/net/QosFilter.java
+++ /dev/null
@@ -1,86 +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.net;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-
-import java.net.InetAddress;
-
-/**
- * Provides the related filtering logic to the {@link NetworkAgent} to match {@link QosSession}s
- * to their related {@link QosCallback}.
- *
- * Used by the {@link com.android.server.ConnectivityService} to validate a {@link QosCallback}
- * is still able to receive a {@link QosSession}.
- *
- * @hide
- */
-@SystemApi
-public abstract class QosFilter {
-
- /**
- * The constructor is kept hidden from outside this package to ensure that all derived types
- * are known and properly handled when being passed to and from {@link NetworkAgent}.
- *
- * @hide
- */
- QosFilter() {
- }
-
- /**
- * The network used with this filter.
- *
- * @return the registered {@link Network}
- */
- @NonNull
- public abstract Network getNetwork();
-
- /**
- * Validates that conditions have not changed such that no further {@link QosSession}s should
- * be passed back to the {@link QosCallback} associated to this filter.
- *
- * @return the error code when present, otherwise the filter is valid
- *
- * @hide
- */
- @QosCallbackException.ExceptionType
- public abstract int validate();
-
- /**
- * Determines whether or not the parameters is a match for the filter.
- *
- * @param address the local address
- * @param startPort the start of the port range
- * @param endPort the end of the port range
- * @return whether the parameters match the local address of the filter
- */
- public abstract boolean matchesLocalAddress(@NonNull InetAddress address,
- int startPort, int endPort);
-
- /**
- * Determines whether or not the parameters is a match for the filter.
- *
- * @param address the remote address
- * @param startPort the start of the port range
- * @param endPort the end of the port range
- * @return whether the parameters match the remote address of the filter
- */
- public abstract boolean matchesRemoteAddress(@NonNull InetAddress address,
- int startPort, int endPort);
-}
-
diff --git a/packages/Connectivity/framework/src/android/net/QosFilterParcelable.java b/packages/Connectivity/framework/src/android/net/QosFilterParcelable.java
deleted file mode 100644
index da3b2cf..0000000
--- a/packages/Connectivity/framework/src/android/net/QosFilterParcelable.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
-
-import java.util.Objects;
-
-/**
- * Aware of how to parcel different types of {@link QosFilter}s. Any new type of qos filter must
- * have a specialized case written here.
- * <p/>
- * Specifically leveraged when transferring {@link QosFilter} from
- * {@link com.android.server.ConnectivityService} to {@link NetworkAgent} when the filter is first
- * registered.
- * <p/>
- * This is not meant to be used in other contexts.
- *
- * @hide
- */
-public final class QosFilterParcelable implements Parcelable {
-
- private static final String LOG_TAG = QosFilterParcelable.class.getSimpleName();
-
- // Indicates that the filter was not successfully written to the parcel.
- private static final int NO_FILTER_PRESENT = 0;
-
- // The parcel is of type qos socket filter.
- private static final int QOS_SOCKET_FILTER = 1;
-
- private final QosFilter mQosFilter;
-
- /**
- * The underlying qos filter.
- * <p/>
- * Null only in the case parceling failed.
- */
- @Nullable
- public QosFilter getQosFilter() {
- return mQosFilter;
- }
-
- public QosFilterParcelable(@NonNull final QosFilter qosFilter) {
- Objects.requireNonNull(qosFilter, "qosFilter must be non-null");
-
- // NOTE: Normally a type check would belong here, but doing so breaks unit tests that rely
- // on mocking qos filter.
- mQosFilter = qosFilter;
- }
-
- private QosFilterParcelable(final Parcel in) {
- final int filterParcelType = in.readInt();
-
- switch (filterParcelType) {
- case QOS_SOCKET_FILTER: {
- mQosFilter = new QosSocketFilter(QosSocketInfo.CREATOR.createFromParcel(in));
- break;
- }
-
- case NO_FILTER_PRESENT:
- default: {
- mQosFilter = null;
- }
- }
- }
-
- public static final Creator<QosFilterParcelable> CREATOR = new Creator<QosFilterParcelable>() {
- @Override
- public QosFilterParcelable createFromParcel(final Parcel in) {
- return new QosFilterParcelable(in);
- }
-
- @Override
- public QosFilterParcelable[] newArray(final int size) {
- return new QosFilterParcelable[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(final Parcel dest, final int flags) {
- if (mQosFilter instanceof QosSocketFilter) {
- dest.writeInt(QOS_SOCKET_FILTER);
- final QosSocketFilter qosSocketFilter = (QosSocketFilter) mQosFilter;
- qosSocketFilter.getQosSocketInfo().writeToParcel(dest, 0);
- return;
- }
- dest.writeInt(NO_FILTER_PRESENT);
- Log.e(LOG_TAG, "Parceling failed, unknown type of filter present: " + mQosFilter);
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/QosSession.java b/packages/Connectivity/framework/src/android/net/QosSession.java
deleted file mode 100644
index 93f2ff2..0000000
--- a/packages/Connectivity/framework/src/android/net/QosSession.java
+++ /dev/null
@@ -1,142 +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.net;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Provides identifying information of a QoS session. Sent to an application through
- * {@link QosCallback}.
- *
- * @hide
- */
-@SystemApi
-public final class QosSession implements Parcelable {
-
- /**
- * The {@link QosSession} is a LTE EPS Session.
- */
- public static final int TYPE_EPS_BEARER = 1;
-
- /**
- * The {@link QosSession} is a NR Session.
- */
- public static final int TYPE_NR_BEARER = 2;
-
- private final int mSessionId;
-
- private final int mSessionType;
-
- /**
- * Gets the unique id of the session that is used to differentiate sessions across different
- * types.
- * <p/>
- * Note: Different qos sessions can be provided by different actors.
- *
- * @return the unique id
- */
- public long getUniqueId() {
- return (long) mSessionType << 32 | mSessionId;
- }
-
- /**
- * Gets the session id that is unique within that type.
- * <p/>
- * Note: The session id is set by the actor providing the qos. It can be either manufactured by
- * the actor, but also may have a particular meaning within that type. For example, using the
- * bearer id as the session id for {@link android.telephony.data.EpsBearerQosSessionAttributes}
- * is a straight forward way to keep the sessions unique from one another within that type.
- *
- * @return the id of the session
- */
- public int getSessionId() {
- return mSessionId;
- }
-
- /**
- * Gets the type of session.
- */
- @QosSessionType
- public int getSessionType() {
- return mSessionType;
- }
-
- /**
- * Creates a {@link QosSession}.
- *
- * @param sessionId uniquely identifies the session across all sessions of the same type
- * @param sessionType the type of session
- */
- public QosSession(final int sessionId, @QosSessionType final int sessionType) {
- //Ensures the session id is unique across types of sessions
- mSessionId = sessionId;
- mSessionType = sessionType;
- }
-
-
- @Override
- public String toString() {
- return "QosSession{"
- + "mSessionId=" + mSessionId
- + ", mSessionType=" + mSessionType
- + '}';
- }
-
- /**
- * Annotations for types of qos sessions.
- */
- @IntDef(value = {
- TYPE_EPS_BEARER,
- TYPE_NR_BEARER,
- })
- @interface QosSessionType {}
-
- private QosSession(final Parcel in) {
- mSessionId = in.readInt();
- mSessionType = in.readInt();
- }
-
- @NonNull
- public static final Creator<QosSession> CREATOR = new Creator<QosSession>() {
- @NonNull
- @Override
- public QosSession createFromParcel(@NonNull final Parcel in) {
- return new QosSession(in);
- }
-
- @NonNull
- @Override
- public QosSession[] newArray(final int size) {
- return new QosSession[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull final Parcel dest, final int flags) {
- dest.writeInt(mSessionId);
- dest.writeInt(mSessionType);
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/QosSessionAttributes.java b/packages/Connectivity/framework/src/android/net/QosSessionAttributes.java
deleted file mode 100644
index 7a88594..0000000
--- a/packages/Connectivity/framework/src/android/net/QosSessionAttributes.java
+++ /dev/null
@@ -1,30 +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.net;
-
-import android.annotation.SystemApi;
-
-/**
- * Implemented by classes that encapsulate Qos related attributes that describe a Qos Session.
- *
- * Use the instanceof keyword to determine the underlying type.
- *
- * @hide
- */
-@SystemApi
-public interface QosSessionAttributes {
-}
diff --git a/packages/Connectivity/framework/src/android/net/QosSocketFilter.java b/packages/Connectivity/framework/src/android/net/QosSocketFilter.java
deleted file mode 100644
index 69da7f4..0000000
--- a/packages/Connectivity/framework/src/android/net/QosSocketFilter.java
+++ /dev/null
@@ -1,179 +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.net;
-
-import static android.net.QosCallbackException.EX_TYPE_FILTER_NONE;
-import static android.net.QosCallbackException.EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.ParcelFileDescriptor;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.FileDescriptor;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.util.Objects;
-
-/**
- * Filters a {@link QosSession} according to the binding on the provided {@link Socket}.
- *
- * @hide
- */
-public class QosSocketFilter extends QosFilter {
-
- private static final String TAG = QosSocketFilter.class.getSimpleName();
-
- @NonNull
- private final QosSocketInfo mQosSocketInfo;
-
- /**
- * Creates a {@link QosSocketFilter} based off of {@link QosSocketInfo}.
- *
- * @param qosSocketInfo the information required to filter and validate
- */
- public QosSocketFilter(@NonNull final QosSocketInfo qosSocketInfo) {
- Objects.requireNonNull(qosSocketInfo, "qosSocketInfo must be non-null");
- mQosSocketInfo = qosSocketInfo;
- }
-
- /**
- * Gets the parcelable qos socket info that was used to create the filter.
- */
- @NonNull
- public QosSocketInfo getQosSocketInfo() {
- return mQosSocketInfo;
- }
-
- /**
- * Performs two validations:
- * 1. If the socket is not bound, then return
- * {@link QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_BOUND}. This is detected
- * by checking the local address on the filter which becomes null when the socket is no
- * longer bound.
- * 2. In the scenario that the socket is now bound to a different local address, which can
- * happen in the case of UDP, then
- * {@link QosCallbackException.EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED} is returned.
- * @return validation error code
- */
- @Override
- public int validate() {
- final InetSocketAddress sa = getAddressFromFileDescriptor();
- if (sa == null) {
- return QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_BOUND;
- }
-
- if (!sa.equals(mQosSocketInfo.getLocalSocketAddress())) {
- return EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED;
- }
-
- return EX_TYPE_FILTER_NONE;
- }
-
- /**
- * The local address of the socket's binding.
- *
- * Note: If the socket is no longer bound, null is returned.
- *
- * @return the local address
- */
- @Nullable
- private InetSocketAddress getAddressFromFileDescriptor() {
- final ParcelFileDescriptor parcelFileDescriptor = mQosSocketInfo.getParcelFileDescriptor();
- if (parcelFileDescriptor == null) return null;
-
- final FileDescriptor fd = parcelFileDescriptor.getFileDescriptor();
- if (fd == null) return null;
-
- final SocketAddress address;
- try {
- address = Os.getsockname(fd);
- } catch (final ErrnoException e) {
- Log.e(TAG, "getAddressFromFileDescriptor: getLocalAddress exception", e);
- return null;
- }
- if (address instanceof InetSocketAddress) {
- return (InetSocketAddress) address;
- }
- return null;
- }
-
- /**
- * The network used with this filter.
- *
- * @return the registered {@link Network}
- */
- @NonNull
- @Override
- public Network getNetwork() {
- return mQosSocketInfo.getNetwork();
- }
-
- /**
- * @inheritDoc
- */
- @Override
- public boolean matchesLocalAddress(@NonNull final InetAddress address, final int startPort,
- final int endPort) {
- if (mQosSocketInfo.getLocalSocketAddress() == null) {
- return false;
- }
- return matchesAddress(mQosSocketInfo.getLocalSocketAddress(), address, startPort,
- endPort);
- }
-
- /**
- * @inheritDoc
- */
- @Override
- public boolean matchesRemoteAddress(@NonNull final InetAddress address, final int startPort,
- final int endPort) {
- if (mQosSocketInfo.getRemoteSocketAddress() == null) {
- return false;
- }
- return matchesAddress(mQosSocketInfo.getRemoteSocketAddress(), address, startPort,
- endPort);
- }
-
- /**
- * Called from {@link QosSocketFilter#matchesLocalAddress(InetAddress, int, int)}
- * and {@link QosSocketFilter#matchesRemoteAddress(InetAddress, int, int)} with the
- * filterSocketAddress coming from {@link QosSocketInfo#getLocalSocketAddress()}.
- * <p>
- * This method exists for testing purposes since {@link QosSocketInfo} couldn't be mocked
- * due to being final.
- *
- * @param filterSocketAddress the socket address of the filter
- * @param address the address to compare the filterSocketAddressWith
- * @param startPort the start of the port range to check
- * @param endPort the end of the port range to check
- */
- @VisibleForTesting
- public static boolean matchesAddress(@NonNull final InetSocketAddress filterSocketAddress,
- @NonNull final InetAddress address,
- final int startPort, final int endPort) {
- return startPort <= filterSocketAddress.getPort()
- && endPort >= filterSocketAddress.getPort()
- && filterSocketAddress.getAddress().equals(address);
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/QosSocketInfo.java b/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
deleted file mode 100644
index a45d507..0000000
--- a/packages/Connectivity/framework/src/android/net/QosSocketInfo.java
+++ /dev/null
@@ -1,190 +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.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.UnknownHostException;
-import java.util.Objects;
-
-/**
- * Used in conjunction with
- * {@link ConnectivityManager#registerQosCallback}
- * in order to receive Qos Sessions related to the local address and port of a bound {@link Socket}
- * and/or remote address and port of a connected {@link Socket}.
- *
- * @hide
- */
-@SystemApi
-public final class QosSocketInfo implements Parcelable {
-
- @NonNull
- private final Network mNetwork;
-
- @NonNull
- private final ParcelFileDescriptor mParcelFileDescriptor;
-
- @NonNull
- private final InetSocketAddress mLocalSocketAddress;
-
- @Nullable
- private final InetSocketAddress mRemoteSocketAddress;
-
- /**
- * The {@link Network} the socket is on.
- *
- * @return the registered {@link Network}
- */
- @NonNull
- public Network getNetwork() {
- return mNetwork;
- }
-
- /**
- * The parcel file descriptor wrapped around the socket's file descriptor.
- *
- * @return the parcel file descriptor of the socket
- */
- @NonNull
- ParcelFileDescriptor getParcelFileDescriptor() {
- return mParcelFileDescriptor;
- }
-
- /**
- * The local address of the socket passed into {@link QosSocketInfo(Network, Socket)}.
- * The value does not reflect any changes that occur to the socket after it is first set
- * in the constructor.
- *
- * @return the local address of the socket
- */
- @NonNull
- public InetSocketAddress getLocalSocketAddress() {
- return mLocalSocketAddress;
- }
-
- /**
- * The remote address of the socket passed into {@link QosSocketInfo(Network, Socket)}.
- * The value does not reflect any changes that occur to the socket after it is first set
- * in the constructor.
- *
- * @return the remote address of the socket if socket is connected, null otherwise
- */
- @Nullable
- public InetSocketAddress getRemoteSocketAddress() {
- return mRemoteSocketAddress;
- }
-
- /**
- * Creates a {@link QosSocketInfo} given a {@link Network} and bound {@link Socket}. The
- * {@link Socket} must remain bound in order to receive {@link QosSession}s.
- *
- * @param network the network
- * @param socket the bound {@link Socket}
- */
- public QosSocketInfo(@NonNull final Network network, @NonNull final Socket socket)
- throws IOException {
- Objects.requireNonNull(socket, "socket cannot be null");
-
- mNetwork = Objects.requireNonNull(network, "network cannot be null");
- mParcelFileDescriptor = ParcelFileDescriptor.fromSocket(socket);
- mLocalSocketAddress =
- new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort());
-
- if (socket.isConnected()) {
- mRemoteSocketAddress = (InetSocketAddress) socket.getRemoteSocketAddress();
- } else {
- mRemoteSocketAddress = null;
- }
- }
-
- /* Parcelable methods */
- private QosSocketInfo(final Parcel in) {
- mNetwork = Objects.requireNonNull(Network.CREATOR.createFromParcel(in));
- mParcelFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(in);
-
- final int localAddressLength = in.readInt();
- mLocalSocketAddress = readSocketAddress(in, localAddressLength);
-
- final int remoteAddressLength = in.readInt();
- mRemoteSocketAddress = remoteAddressLength == 0 ? null
- : readSocketAddress(in, remoteAddressLength);
- }
-
- private @NonNull InetSocketAddress readSocketAddress(final Parcel in, final int addressLength) {
- final byte[] address = new byte[addressLength];
- in.readByteArray(address);
- final int port = in.readInt();
-
- try {
- return new InetSocketAddress(InetAddress.getByAddress(address), port);
- } catch (final UnknownHostException e) {
- /* This can never happen. UnknownHostException will never be thrown
- since the address provided is numeric and non-null. */
- throw new RuntimeException("UnknownHostException on numeric address", e);
- }
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull final Parcel dest, final int flags) {
- mNetwork.writeToParcel(dest, 0);
- mParcelFileDescriptor.writeToParcel(dest, 0);
-
- final byte[] localAddress = mLocalSocketAddress.getAddress().getAddress();
- dest.writeInt(localAddress.length);
- dest.writeByteArray(localAddress);
- dest.writeInt(mLocalSocketAddress.getPort());
-
- if (mRemoteSocketAddress == null) {
- dest.writeInt(0);
- } else {
- final byte[] remoteAddress = mRemoteSocketAddress.getAddress().getAddress();
- dest.writeInt(remoteAddress.length);
- dest.writeByteArray(remoteAddress);
- dest.writeInt(mRemoteSocketAddress.getPort());
- }
- }
-
- @NonNull
- public static final Parcelable.Creator<QosSocketInfo> CREATOR =
- new Parcelable.Creator<QosSocketInfo>() {
- @NonNull
- @Override
- public QosSocketInfo createFromParcel(final Parcel in) {
- return new QosSocketInfo(in);
- }
-
- @NonNull
- @Override
- public QosSocketInfo[] newArray(final int size) {
- return new QosSocketInfo[size];
- }
- };
-}
diff --git a/packages/Connectivity/framework/src/android/net/RouteInfo.java b/packages/Connectivity/framework/src/android/net/RouteInfo.java
deleted file mode 100644
index fad3144..0000000
--- a/packages/Connectivity/framework/src/android/net/RouteInfo.java
+++ /dev/null
@@ -1,659 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.net.module.util.NetUtils;
-import com.android.net.module.util.NetworkStackConstants;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Collection;
-import java.util.Objects;
-
-/**
- * Represents a network route.
- * <p>
- * This is used both to describe static network configuration and live network
- * configuration information.
- *
- * A route contains three pieces of information:
- * <ul>
- * <li>a destination {@link IpPrefix} specifying the network destinations covered by this route.
- * If this is {@code null} it indicates a default route of the address family (IPv4 or IPv6)
- * implied by the gateway IP address.
- * <li>a gateway {@link InetAddress} indicating the next hop to use. If this is {@code null} it
- * indicates a directly-connected route.
- * <li>an interface (which may be unspecified).
- * </ul>
- * Either the destination or the gateway may be {@code null}, but not both. If the
- * destination and gateway are both specified, they must be of the same address family
- * (IPv4 or IPv6).
- */
-public final class RouteInfo implements Parcelable {
- /** @hide */
- @IntDef(value = {
- RTN_UNICAST,
- RTN_UNREACHABLE,
- RTN_THROW,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface RouteType {}
-
- /**
- * The IP destination address for this route.
- */
- @NonNull
- private final IpPrefix mDestination;
-
- /**
- * The gateway address for this route.
- */
- @UnsupportedAppUsage
- @Nullable
- private final InetAddress mGateway;
-
- /**
- * The interface for this route.
- */
- @Nullable
- private final String mInterface;
-
-
- /** Unicast route. @hide */
- @SystemApi
- public static final int RTN_UNICAST = 1;
-
- /** Unreachable route. @hide */
- @SystemApi
- public static final int RTN_UNREACHABLE = 7;
-
- /** Throw route. @hide */
- @SystemApi
- public static final int RTN_THROW = 9;
-
- /**
- * The type of this route; one of the RTN_xxx constants above.
- */
- private final int mType;
-
- /**
- * The maximum transmission unit size for this route.
- */
- private final int mMtu;
-
- // Derived data members.
- // TODO: remove these.
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private final boolean mIsHost;
- private final boolean mHasGateway;
-
- /**
- * Constructs a RouteInfo object.
- *
- * If destination is null, then gateway must be specified and the
- * constructed route is either the IPv4 default route <code>0.0.0.0</code>
- * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
- * route <code>::/0</code> if gateway is an instance of
- * {@link Inet6Address}.
- * <p>
- * destination and gateway may not both be null.
- *
- * @param destination the destination prefix
- * @param gateway the IP address to route packets through
- * @param iface the interface name to send packets on
- * @param type the type of this route
- *
- * @hide
- */
- @SystemApi
- public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
- @Nullable String iface, @RouteType int type) {
- this(destination, gateway, iface, type, 0);
- }
-
- /**
- * Constructs a RouteInfo object.
- *
- * If destination is null, then gateway must be specified and the
- * constructed route is either the IPv4 default route <code>0.0.0.0</code>
- * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
- * route <code>::/0</code> if gateway is an instance of
- * {@link Inet6Address}.
- * <p>
- * destination and gateway may not both be null.
- *
- * @param destination the destination prefix
- * @param gateway the IP address to route packets through
- * @param iface the interface name to send packets on
- * @param type the type of this route
- * @param mtu the maximum transmission unit size for this route
- *
- * @hide
- */
- @SystemApi
- public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
- @Nullable String iface, @RouteType int type, int mtu) {
- switch (type) {
- case RTN_UNICAST:
- case RTN_UNREACHABLE:
- case RTN_THROW:
- // TODO: It would be nice to ensure that route types that don't have nexthops or
- // interfaces, such as unreachable or throw, can't be created if an interface or
- // a gateway is specified. This is a bit too complicated to do at the moment
- // because:
- //
- // - LinkProperties sets the interface on routes added to it, and modifies the
- // interfaces of all the routes when its interface name changes.
- // - Even when the gateway is null, we store a non-null gateway here.
- //
- // For now, we just rely on the code that sets routes to do things properly.
- break;
- default:
- throw new IllegalArgumentException("Unknown route type " + type);
- }
-
- if (destination == null) {
- if (gateway != null) {
- if (gateway instanceof Inet4Address) {
- destination = new IpPrefix(NetworkStackConstants.IPV4_ADDR_ANY, 0);
- } else {
- destination = new IpPrefix(NetworkStackConstants.IPV6_ADDR_ANY, 0);
- }
- } else {
- // no destination, no gateway. invalid.
- throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," +
- destination);
- }
- }
- // TODO: set mGateway to null if there is no gateway. This is more correct, saves space, and
- // matches the documented behaviour. Before we can do this we need to fix all callers (e.g.,
- // ConnectivityService) to stop doing things like r.getGateway().equals(), ... .
- if (gateway == null) {
- if (destination.getAddress() instanceof Inet4Address) {
- gateway = NetworkStackConstants.IPV4_ADDR_ANY;
- } else {
- gateway = NetworkStackConstants.IPV6_ADDR_ANY;
- }
- }
- mHasGateway = (!gateway.isAnyLocalAddress());
-
- if ((destination.getAddress() instanceof Inet4Address
- && !(gateway instanceof Inet4Address))
- || (destination.getAddress() instanceof Inet6Address
- && !(gateway instanceof Inet6Address))) {
- throw new IllegalArgumentException("address family mismatch in RouteInfo constructor");
- }
- mDestination = destination; // IpPrefix objects are immutable.
- mGateway = gateway; // InetAddress objects are immutable.
- mInterface = iface; // Strings are immutable.
- mType = type;
- mIsHost = isHost();
- mMtu = mtu;
- }
-
- /**
- * Constructs a {@code RouteInfo} object.
- *
- * If destination is null, then gateway must be specified and the
- * constructed route is either the IPv4 default route <code>0.0.0.0</code>
- * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
- * route <code>::/0</code> if gateway is an instance of {@link Inet6Address}.
- * <p>
- * Destination and gateway may not both be null.
- *
- * @param destination the destination address and prefix in an {@link IpPrefix}
- * @param gateway the {@link InetAddress} to route packets through
- * @param iface the interface name to send packets on
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
- @Nullable String iface) {
- this(destination, gateway, iface, RTN_UNICAST);
- }
-
- /**
- * @hide
- */
- @UnsupportedAppUsage
- public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway,
- @Nullable String iface) {
- this(destination == null ? null :
- new IpPrefix(destination.getAddress(), destination.getPrefixLength()),
- gateway, iface);
- }
-
- /**
- * Constructs a {@code RouteInfo} object.
- *
- * If destination is null, then gateway must be specified and the
- * constructed route is either the IPv4 default route <code>0.0.0.0</code>
- * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
- * route <code>::/0</code> if gateway is an instance of {@link Inet6Address}.
- * <p>
- * Destination and gateway may not both be null.
- *
- * @param destination the destination address and prefix in an {@link IpPrefix}
- * @param gateway the {@link InetAddress} to route packets through
- *
- * @hide
- */
- public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway) {
- this(destination, gateway, null);
- }
-
- /**
- * @hide
- *
- * TODO: Remove this.
- */
- @UnsupportedAppUsage
- public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway) {
- this(destination, gateway, null);
- }
-
- /**
- * Constructs a default {@code RouteInfo} object.
- *
- * @param gateway the {@link InetAddress} to route packets through
- *
- * @hide
- */
- @UnsupportedAppUsage
- public RouteInfo(@NonNull InetAddress gateway) {
- this((IpPrefix) null, gateway, null);
- }
-
- /**
- * Constructs a {@code RouteInfo} object representing a direct connected subnet.
- *
- * @param destination the {@link IpPrefix} describing the address and prefix
- * length of the subnet.
- *
- * @hide
- */
- public RouteInfo(@NonNull IpPrefix destination) {
- this(destination, null, null);
- }
-
- /**
- * @hide
- */
- public RouteInfo(@NonNull LinkAddress destination) {
- this(destination, null, null);
- }
-
- /**
- * @hide
- */
- public RouteInfo(@NonNull IpPrefix destination, @RouteType int type) {
- this(destination, null, null, type);
- }
-
- /**
- * @hide
- */
- public static RouteInfo makeHostRoute(@NonNull InetAddress host, @Nullable String iface) {
- return makeHostRoute(host, null, iface);
- }
-
- /**
- * @hide
- */
- public static RouteInfo makeHostRoute(@Nullable InetAddress host, @Nullable InetAddress gateway,
- @Nullable String iface) {
- if (host == null) return null;
-
- if (host instanceof Inet4Address) {
- return new RouteInfo(new IpPrefix(host, 32), gateway, iface);
- } else {
- return new RouteInfo(new IpPrefix(host, 128), gateway, iface);
- }
- }
-
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private boolean isHost() {
- return (mDestination.getAddress() instanceof Inet4Address &&
- mDestination.getPrefixLength() == 32) ||
- (mDestination.getAddress() instanceof Inet6Address &&
- mDestination.getPrefixLength() == 128);
- }
-
- /**
- * Retrieves the destination address and prefix length in the form of an {@link IpPrefix}.
- *
- * @return {@link IpPrefix} specifying the destination. This is never {@code null}.
- */
- @NonNull
- public IpPrefix getDestination() {
- return mDestination;
- }
-
- /**
- * TODO: Convert callers to use IpPrefix and then remove.
- * @hide
- */
- @NonNull
- public LinkAddress getDestinationLinkAddress() {
- return new LinkAddress(mDestination.getAddress(), mDestination.getPrefixLength());
- }
-
- /**
- * Retrieves the gateway or next hop {@link InetAddress} for this route.
- *
- * @return {@link InetAddress} specifying the gateway or next hop. This may be
- * {@code null} for a directly-connected route."
- */
- @Nullable
- public InetAddress getGateway() {
- return mGateway;
- }
-
- /**
- * Retrieves the interface used for this route if specified, else {@code null}.
- *
- * @return The name of the interface used for this route.
- */
- @Nullable
- public String getInterface() {
- return mInterface;
- }
-
- /**
- * Retrieves the type of this route.
- *
- * @return The type of this route; one of the {@code RTN_xxx} constants defined in this class.
- *
- * @hide
- */
- @SystemApi
- @RouteType
- public int getType() {
- return mType;
- }
-
- /**
- * Retrieves the MTU size for this route.
- *
- * @return The MTU size, or 0 if it has not been set.
- * @hide
- */
- @SystemApi
- public int getMtu() {
- return mMtu;
- }
-
- /**
- * Indicates if this route is a default route (ie, has no destination specified).
- *
- * @return {@code true} if the destination has a prefix length of 0.
- */
- public boolean isDefaultRoute() {
- return mType == RTN_UNICAST && mDestination.getPrefixLength() == 0;
- }
-
- /**
- * Indicates if this route is an unreachable default route.
- *
- * @return {@code true} if it's an unreachable route with prefix length of 0.
- * @hide
- */
- private boolean isUnreachableDefaultRoute() {
- return mType == RTN_UNREACHABLE && mDestination.getPrefixLength() == 0;
- }
-
- /**
- * Indicates if this route is an IPv4 default route.
- * @hide
- */
- public boolean isIPv4Default() {
- return isDefaultRoute() && mDestination.getAddress() instanceof Inet4Address;
- }
-
- /**
- * Indicates if this route is an IPv4 unreachable default route.
- * @hide
- */
- public boolean isIPv4UnreachableDefault() {
- return isUnreachableDefaultRoute() && mDestination.getAddress() instanceof Inet4Address;
- }
-
- /**
- * Indicates if this route is an IPv6 default route.
- * @hide
- */
- public boolean isIPv6Default() {
- return isDefaultRoute() && mDestination.getAddress() instanceof Inet6Address;
- }
-
- /**
- * Indicates if this route is an IPv6 unreachable default route.
- * @hide
- */
- public boolean isIPv6UnreachableDefault() {
- return isUnreachableDefaultRoute() && mDestination.getAddress() instanceof Inet6Address;
- }
-
- /**
- * Indicates if this route is a host route (ie, matches only a single host address).
- *
- * @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6,
- * respectively.
- * @hide
- */
- public boolean isHostRoute() {
- return mIsHost;
- }
-
- /**
- * Indicates if this route has a next hop ({@code true}) or is directly-connected
- * ({@code false}).
- *
- * @return {@code true} if a gateway is specified
- */
- public boolean hasGateway() {
- return mHasGateway;
- }
-
- /**
- * Determines whether the destination and prefix of this route includes the specified
- * address.
- *
- * @param destination A {@link InetAddress} to test to see if it would match this route.
- * @return {@code true} if the destination and prefix length cover the given address.
- */
- public boolean matches(InetAddress destination) {
- return mDestination.contains(destination);
- }
-
- /**
- * Find the route from a Collection of routes that best matches a given address.
- * May return null if no routes are applicable.
- * @param routes a Collection of RouteInfos to chose from
- * @param dest the InetAddress your trying to get to
- * @return the RouteInfo from the Collection that best fits the given address
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @Nullable
- public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
- return NetUtils.selectBestRoute(routes, dest);
- }
-
- /**
- * Returns a human-readable description of this object.
- */
- public String toString() {
- String val = "";
- if (mDestination != null) val = mDestination.toString();
- if (mType == RTN_UNREACHABLE) {
- val += " unreachable";
- } else if (mType == RTN_THROW) {
- val += " throw";
- } else {
- val += " ->";
- if (mGateway != null) val += " " + mGateway.getHostAddress();
- if (mInterface != null) val += " " + mInterface;
- if (mType != RTN_UNICAST) {
- val += " unknown type " + mType;
- }
- }
- val += " mtu " + mMtu;
- return val;
- }
-
- /**
- * Compares this RouteInfo object against the specified object and indicates if they are equal.
- * @return {@code true} if the objects are equal, {@code false} otherwise.
- */
- public boolean equals(@Nullable Object obj) {
- if (this == obj) return true;
-
- if (!(obj instanceof RouteInfo)) return false;
-
- RouteInfo target = (RouteInfo) obj;
-
- return Objects.equals(mDestination, target.getDestination()) &&
- Objects.equals(mGateway, target.getGateway()) &&
- Objects.equals(mInterface, target.getInterface()) &&
- mType == target.getType() && mMtu == target.getMtu();
- }
-
- /**
- * A helper class that contains the destination, the gateway and the interface in a
- * {@code RouteInfo}, used by {@link ConnectivityService#updateRoutes} or
- * {@link LinkProperties#addRoute} to calculate the list to be updated.
- * {@code RouteInfo} objects with different interfaces are treated as different routes because
- * *usually* on Android different interfaces use different routing tables, and moving a route
- * to a new routing table never constitutes an update, but is always a remove and an add.
- *
- * @hide
- */
- public static class RouteKey {
- @NonNull private final IpPrefix mDestination;
- @Nullable private final InetAddress mGateway;
- @Nullable private final String mInterface;
-
- RouteKey(@NonNull IpPrefix destination, @Nullable InetAddress gateway,
- @Nullable String iface) {
- mDestination = destination;
- mGateway = gateway;
- mInterface = iface;
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (!(o instanceof RouteKey)) {
- return false;
- }
- RouteKey p = (RouteKey) o;
- // No need to do anything special for scoped addresses. Inet6Address#equals does not
- // consider the scope ID, but the netd route IPCs (e.g., INetd#networkAddRouteParcel)
- // and the kernel ignore scoped addresses both in the prefix and in the nexthop and only
- // look at RTA_OIF.
- return Objects.equals(p.mDestination, mDestination)
- && Objects.equals(p.mGateway, mGateway)
- && Objects.equals(p.mInterface, mInterface);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mDestination, mGateway, mInterface);
- }
- }
-
- /**
- * Get {@code RouteKey} of this {@code RouteInfo}.
- * @return a {@code RouteKey} object.
- *
- * @hide
- */
- @NonNull
- public RouteKey getRouteKey() {
- return new RouteKey(mDestination, mGateway, mInterface);
- }
-
- /**
- * Returns a hashcode for this <code>RouteInfo</code> object.
- */
- public int hashCode() {
- return (mDestination.hashCode() * 41)
- + (mGateway == null ? 0 :mGateway.hashCode() * 47)
- + (mInterface == null ? 0 :mInterface.hashCode() * 67)
- + (mType * 71) + (mMtu * 89);
- }
-
- /**
- * Implement the Parcelable interface
- */
- public int describeContents() {
- return 0;
- }
-
- /**
- * Implement the Parcelable interface
- */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeParcelable(mDestination, flags);
- byte[] gatewayBytes = (mGateway == null) ? null : mGateway.getAddress();
- dest.writeByteArray(gatewayBytes);
- dest.writeString(mInterface);
- dest.writeInt(mType);
- dest.writeInt(mMtu);
- }
-
- /**
- * Implement the Parcelable interface.
- */
- public static final @android.annotation.NonNull Creator<RouteInfo> CREATOR =
- new Creator<RouteInfo>() {
- public RouteInfo createFromParcel(Parcel in) {
- IpPrefix dest = in.readParcelable(null);
-
- InetAddress gateway = null;
- byte[] addr = in.createByteArray();
- try {
- gateway = InetAddress.getByAddress(addr);
- } catch (UnknownHostException e) {}
-
- String iface = in.readString();
- int type = in.readInt();
- int mtu = in.readInt();
-
- return new RouteInfo(dest, gateway, iface, type, mtu);
- }
-
- public RouteInfo[] newArray(int size) {
- return new RouteInfo[size];
- }
- };
-}
diff --git a/packages/Connectivity/framework/src/android/net/SocketKeepalive.java b/packages/Connectivity/framework/src/android/net/SocketKeepalive.java
deleted file mode 100644
index f6cae72..0000000
--- a/packages/Connectivity/framework/src/android/net/SocketKeepalive.java
+++ /dev/null
@@ -1,347 +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 android.net;
-
-import android.annotation.IntDef;
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Binder;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.concurrent.Executor;
-
-/**
- * Allows applications to request that the system periodically send specific packets on their
- * behalf, using hardware offload to save battery power.
- *
- * To request that the system send keepalives, call one of the methods that return a
- * {@link SocketKeepalive} object, such as {@link ConnectivityManager#createSocketKeepalive},
- * passing in a non-null callback. If the {@link SocketKeepalive} is successfully
- * started, the callback's {@code onStarted} method will be called. If an error occurs,
- * {@code onError} will be called, specifying one of the {@code ERROR_*} constants in this
- * class.
- *
- * To stop an existing keepalive, call {@link SocketKeepalive#stop}. The system will call
- * {@link SocketKeepalive.Callback#onStopped} if the operation was successful or
- * {@link SocketKeepalive.Callback#onError} if an error occurred.
- *
- * For cellular, the device MUST support at least 1 keepalive slot.
- *
- * For WiFi, the device SHOULD support keepalive offload. If it does not, it MUST reply with
- * {@link SocketKeepalive.Callback#onError} with {@code ERROR_UNSUPPORTED} to any keepalive offload
- * request. If it does, it MUST support at least 3 concurrent keepalive slots.
- */
-public abstract class SocketKeepalive implements AutoCloseable {
- static final String TAG = "SocketKeepalive";
-
- /**
- * Success. It indicates there is no error.
- * @hide
- */
- @SystemApi
- public static final int SUCCESS = 0;
-
- /**
- * No keepalive. This should only be internally as it indicates There is no keepalive.
- * It should not propagate to applications.
- * @hide
- */
- public static final int NO_KEEPALIVE = -1;
-
- /**
- * Data received.
- * @hide
- */
- public static final int DATA_RECEIVED = -2;
-
- /**
- * The binder died.
- * @hide
- */
- public static final int BINDER_DIED = -10;
-
- /**
- * The invalid network. It indicates the specified {@code Network} is not connected.
- */
- public static final int ERROR_INVALID_NETWORK = -20;
-
- /**
- * The invalid IP addresses. Indicates the specified IP addresses are invalid.
- * For example, the specified source IP address is not configured on the
- * specified {@code Network}.
- */
- public static final int ERROR_INVALID_IP_ADDRESS = -21;
-
- /**
- * The port is invalid.
- */
- public static final int ERROR_INVALID_PORT = -22;
-
- /**
- * The length is invalid (e.g. too long).
- */
- public static final int ERROR_INVALID_LENGTH = -23;
-
- /**
- * The interval is invalid (e.g. too short).
- */
- public static final int ERROR_INVALID_INTERVAL = -24;
-
- /**
- * The socket is invalid.
- */
- public static final int ERROR_INVALID_SOCKET = -25;
-
- /**
- * The socket is not idle.
- */
- public static final int ERROR_SOCKET_NOT_IDLE = -26;
-
- /**
- * The stop reason is uninitialized. This should only be internally used as initial state
- * of stop reason, instead of propagating to application.
- * @hide
- */
- public static final int ERROR_STOP_REASON_UNINITIALIZED = -27;
-
- /**
- * The request is unsupported.
- */
- public static final int ERROR_UNSUPPORTED = -30;
-
- /**
- * There was a hardware error.
- */
- public static final int ERROR_HARDWARE_ERROR = -31;
-
- /**
- * Resources are insufficient (e.g. all hardware slots are in use).
- */
- public static final int ERROR_INSUFFICIENT_RESOURCES = -32;
-
- /**
- * There was no such slot. This should only be internally as it indicates
- * a programming error in the system server. It should not propagate to
- * applications.
- * @hide
- */
- @SystemApi
- public static final int ERROR_NO_SUCH_SLOT = -33;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "ERROR_" }, value = {
- ERROR_INVALID_NETWORK,
- ERROR_INVALID_IP_ADDRESS,
- ERROR_INVALID_PORT,
- ERROR_INVALID_LENGTH,
- ERROR_INVALID_INTERVAL,
- ERROR_INVALID_SOCKET,
- ERROR_SOCKET_NOT_IDLE,
- ERROR_NO_SUCH_SLOT
- })
- public @interface ErrorCode {}
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- SUCCESS,
- ERROR_INVALID_LENGTH,
- ERROR_UNSUPPORTED,
- ERROR_INSUFFICIENT_RESOURCES,
- })
- public @interface KeepaliveEvent {}
-
- /**
- * The minimum interval in seconds between keepalive packet transmissions.
- *
- * @hide
- **/
- public static final int MIN_INTERVAL_SEC = 10;
-
- /**
- * The maximum interval in seconds between keepalive packet transmissions.
- *
- * @hide
- **/
- public static final int MAX_INTERVAL_SEC = 3600;
-
- /**
- * An exception that embarks an error code.
- * @hide
- */
- public static class ErrorCodeException extends Exception {
- public final int error;
- public ErrorCodeException(final int error, final Throwable e) {
- super(e);
- this.error = error;
- }
- public ErrorCodeException(final int error) {
- this.error = error;
- }
- }
-
- /**
- * This socket is invalid.
- * See the error code for details, and the optional cause.
- * @hide
- */
- public static class InvalidSocketException extends ErrorCodeException {
- public InvalidSocketException(final int error, final Throwable e) {
- super(error, e);
- }
- public InvalidSocketException(final int error) {
- super(error);
- }
- }
-
- @NonNull final IConnectivityManager mService;
- @NonNull final Network mNetwork;
- @NonNull final ParcelFileDescriptor mPfd;
- @NonNull final Executor mExecutor;
- @NonNull final ISocketKeepaliveCallback mCallback;
- // TODO: remove slot since mCallback could be used to identify which keepalive to stop.
- @Nullable Integer mSlot;
-
- SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network,
- @NonNull ParcelFileDescriptor pfd,
- @NonNull Executor executor, @NonNull Callback callback) {
- mService = service;
- mNetwork = network;
- mPfd = pfd;
- mExecutor = executor;
- mCallback = new ISocketKeepaliveCallback.Stub() {
- @Override
- public void onStarted(int slot) {
- final long token = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> {
- mSlot = slot;
- callback.onStarted();
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void onStopped() {
- final long token = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> {
- mSlot = null;
- callback.onStopped();
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void onError(int error) {
- final long token = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> {
- mSlot = null;
- callback.onError(error);
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void onDataReceived() {
- final long token = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> {
- mSlot = null;
- callback.onDataReceived();
- });
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- };
- }
-
- /**
- * Request that keepalive be started with the given {@code intervalSec}. See
- * {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an exception
- * when invoking start or stop of the {@link SocketKeepalive}, a {@link RemoteException} will be
- * thrown into the {@code executor}. This is typically not important to catch because the remote
- * party is the system, so if it is not in shape to communicate through binder the system is
- * probably going down anyway. If the caller cares regardless, it can use a custom
- * {@link Executor} to catch the {@link RemoteException}.
- *
- * @param intervalSec The target interval in seconds between keepalive packet transmissions.
- * The interval should be between 10 seconds and 3600 seconds, otherwise
- * {@link #ERROR_INVALID_INTERVAL} will be returned.
- */
- public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
- int intervalSec) {
- startImpl(intervalSec);
- }
-
- abstract void startImpl(int intervalSec);
-
- /**
- * Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped}
- * before using the object. See {@link SocketKeepalive}.
- */
- public final void stop() {
- stopImpl();
- }
-
- abstract void stopImpl();
-
- /**
- * Deactivate this {@link SocketKeepalive} and free allocated resources. The instance won't be
- * usable again if {@code close()} is called.
- */
- @Override
- public final void close() {
- stop();
- try {
- mPfd.close();
- } catch (IOException e) {
- // Nothing much can be done.
- }
- }
-
- /**
- * The callback which app can use to learn the status changes of {@link SocketKeepalive}. See
- * {@link SocketKeepalive}.
- */
- public static class Callback {
- /** The requested keepalive was successfully started. */
- public void onStarted() {}
- /** The keepalive was successfully stopped. */
- public void onStopped() {}
- /** An error occurred. */
- public void onError(@ErrorCode int error) {}
- /** The keepalive on a TCP socket was stopped because the socket received data. This is
- * never called for UDP sockets. */
- public void onDataReceived() {}
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/SocketLocalAddressChangedException.java b/packages/Connectivity/framework/src/android/net/SocketLocalAddressChangedException.java
deleted file mode 100644
index 9daad83..0000000
--- a/packages/Connectivity/framework/src/android/net/SocketLocalAddressChangedException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.SystemApi;
-
-/**
- * Thrown when the local address of the socket has changed.
- *
- * @hide
- */
-@SystemApi
-public class SocketLocalAddressChangedException extends Exception {
- /** @hide */
- public SocketLocalAddressChangedException() {
- super("The local address of the socket changed");
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/SocketNotBoundException.java b/packages/Connectivity/framework/src/android/net/SocketNotBoundException.java
deleted file mode 100644
index b1d7026..0000000
--- a/packages/Connectivity/framework/src/android/net/SocketNotBoundException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.SystemApi;
-
-/**
- * Thrown when a previously bound socket becomes unbound.
- *
- * @hide
- */
-@SystemApi
-public class SocketNotBoundException extends Exception {
- /** @hide */
- public SocketNotBoundException() {
- super("The socket is unbound");
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java b/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java
deleted file mode 100644
index 7904f7a..0000000
--- a/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.net.module.util.InetAddressUtils;
-
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Class that describes static IP configuration.
- *
- * <p>This class is different from {@link LinkProperties} because it represents
- * configuration intent. The general contract is that if we can represent
- * a configuration here, then we should be able to configure it on a network.
- * The intent is that it closely match the UI we have for configuring networks.
- *
- * <p>In contrast, {@link LinkProperties} represents current state. It is much more
- * expressive. For example, it supports multiple IP addresses, multiple routes,
- * stacked interfaces, and so on. Because LinkProperties is so expressive,
- * using it to represent configuration intent as well as current state causes
- * problems. For example, we could unknowingly save a configuration that we are
- * not in fact capable of applying, or we could save a configuration that the
- * UI cannot display, which has the potential for malicious code to hide
- * hostile or unexpected configuration from the user.
- *
- * @hide
- */
-@SystemApi
-public final class StaticIpConfiguration implements Parcelable {
- /** @hide */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @Nullable
- public LinkAddress ipAddress;
- /** @hide */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @Nullable
- public InetAddress gateway;
- /** @hide */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @NonNull
- public final ArrayList<InetAddress> dnsServers;
- /** @hide */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @Nullable
- public String domains;
-
- public StaticIpConfiguration() {
- dnsServers = new ArrayList<>();
- }
-
- public StaticIpConfiguration(@Nullable StaticIpConfiguration source) {
- this();
- if (source != null) {
- // All of these except dnsServers are immutable, so no need to make copies.
- ipAddress = source.ipAddress;
- gateway = source.gateway;
- dnsServers.addAll(source.dnsServers);
- domains = source.domains;
- }
- }
-
- public void clear() {
- ipAddress = null;
- gateway = null;
- dnsServers.clear();
- domains = null;
- }
-
- /**
- * Get the static IP address included in the configuration.
- */
- public @Nullable LinkAddress getIpAddress() {
- return ipAddress;
- }
-
- /**
- * Get the gateway included in the configuration.
- */
- public @Nullable InetAddress getGateway() {
- return gateway;
- }
-
- /**
- * Get the DNS servers included in the configuration.
- */
- public @NonNull List<InetAddress> getDnsServers() {
- return dnsServers;
- }
-
- /**
- * Get a {@link String} containing the comma separated domains to search when resolving host
- * names on this link, in priority order.
- */
- public @Nullable String getDomains() {
- return domains;
- }
-
- /**
- * Helper class to build a new instance of {@link StaticIpConfiguration}.
- */
- public static final class Builder {
- private LinkAddress mIpAddress;
- private InetAddress mGateway;
- private Iterable<InetAddress> mDnsServers;
- private String mDomains;
-
- /**
- * Set the IP address to be included in the configuration; null by default.
- * @return The {@link Builder} for chaining.
- */
- public @NonNull Builder setIpAddress(@Nullable LinkAddress ipAddress) {
- mIpAddress = ipAddress;
- return this;
- }
-
- /**
- * Set the address of the gateway to be included in the configuration; null by default.
- * @return The {@link Builder} for chaining.
- */
- public @NonNull Builder setGateway(@Nullable InetAddress gateway) {
- mGateway = gateway;
- return this;
- }
-
- /**
- * Set the addresses of the DNS servers included in the configuration; empty by default.
- * @return The {@link Builder} for chaining.
- */
- public @NonNull Builder setDnsServers(@NonNull Iterable<InetAddress> dnsServers) {
- Objects.requireNonNull(dnsServers);
- mDnsServers = dnsServers;
- return this;
- }
-
- /**
- * Sets the DNS domain search path to be used on the link; null by default.
- * @param newDomains A {@link String} containing the comma separated domains to search when
- * resolving host names on this link, in priority order.
- * @return The {@link Builder} for chaining.
- */
- public @NonNull Builder setDomains(@Nullable String newDomains) {
- mDomains = newDomains;
- return this;
- }
-
- /**
- * Create a {@link StaticIpConfiguration} from the parameters in this {@link Builder}.
- * @return The newly created StaticIpConfiguration.
- */
- public @NonNull StaticIpConfiguration build() {
- final StaticIpConfiguration config = new StaticIpConfiguration();
- config.ipAddress = mIpAddress;
- config.gateway = mGateway;
- if (mDnsServers != null) {
- for (InetAddress server : mDnsServers) {
- config.dnsServers.add(server);
- }
- }
- config.domains = mDomains;
- return config;
- }
- }
-
- /**
- * Add a DNS server to this configuration.
- */
- public void addDnsServer(@NonNull InetAddress server) {
- dnsServers.add(server);
- }
-
- /**
- * Returns the network routes specified by this object. Will typically include a
- * directly-connected route for the IP address's local subnet and a default route.
- * @param iface Interface to include in the routes.
- */
- public @NonNull List<RouteInfo> getRoutes(@Nullable String iface) {
- List<RouteInfo> routes = new ArrayList<RouteInfo>(3);
- if (ipAddress != null) {
- RouteInfo connectedRoute = new RouteInfo(ipAddress, null, iface);
- routes.add(connectedRoute);
- // If the default gateway is not covered by the directly-connected route, also add a
- // host route to the gateway as well. This configuration is arguably invalid, but it
- // used to work in K and earlier, and other OSes appear to accept it.
- if (gateway != null && !connectedRoute.matches(gateway)) {
- routes.add(RouteInfo.makeHostRoute(gateway, iface));
- }
- }
- if (gateway != null) {
- routes.add(new RouteInfo((IpPrefix) null, gateway, iface));
- }
- return routes;
- }
-
- /**
- * Returns a LinkProperties object expressing the data in this object. Note that the information
- * contained in the LinkProperties will not be a complete picture of the link's configuration,
- * because any configuration information that is obtained dynamically by the network (e.g.,
- * IPv6 configuration) will not be included.
- * @hide
- */
- public @NonNull LinkProperties toLinkProperties(String iface) {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(iface);
- if (ipAddress != null) {
- lp.addLinkAddress(ipAddress);
- }
- for (RouteInfo route : getRoutes(iface)) {
- lp.addRoute(route);
- }
- for (InetAddress dns : dnsServers) {
- lp.addDnsServer(dns);
- }
- lp.setDomains(domains);
- return lp;
- }
-
- @NonNull
- @Override
- public String toString() {
- StringBuffer str = new StringBuffer();
-
- str.append("IP address ");
- if (ipAddress != null ) str.append(ipAddress).append(" ");
-
- str.append("Gateway ");
- if (gateway != null) str.append(gateway.getHostAddress()).append(" ");
-
- str.append(" DNS servers: [");
- for (InetAddress dnsServer : dnsServers) {
- str.append(" ").append(dnsServer.getHostAddress());
- }
-
- str.append(" ] Domains ");
- if (domains != null) str.append(domains);
- return str.toString();
- }
-
- @Override
- public int hashCode() {
- int result = 13;
- result = 47 * result + (ipAddress == null ? 0 : ipAddress.hashCode());
- result = 47 * result + (gateway == null ? 0 : gateway.hashCode());
- result = 47 * result + (domains == null ? 0 : domains.hashCode());
- result = 47 * result + dnsServers.hashCode();
- return result;
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) return true;
-
- if (!(obj instanceof StaticIpConfiguration)) return false;
-
- StaticIpConfiguration other = (StaticIpConfiguration) obj;
-
- return other != null &&
- Objects.equals(ipAddress, other.ipAddress) &&
- Objects.equals(gateway, other.gateway) &&
- dnsServers.equals(other.dnsServers) &&
- Objects.equals(domains, other.domains);
- }
-
- /** Implement the Parcelable interface */
- public static final @android.annotation.NonNull Creator<StaticIpConfiguration> CREATOR =
- new Creator<StaticIpConfiguration>() {
- public StaticIpConfiguration createFromParcel(Parcel in) {
- return readFromParcel(in);
- }
-
- public StaticIpConfiguration[] newArray(int size) {
- return new StaticIpConfiguration[size];
- }
- };
-
- /** Implement the Parcelable interface */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** Implement the Parcelable interface */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeParcelable(ipAddress, flags);
- InetAddressUtils.parcelInetAddress(dest, gateway, flags);
- dest.writeInt(dnsServers.size());
- for (InetAddress dnsServer : dnsServers) {
- InetAddressUtils.parcelInetAddress(dest, dnsServer, flags);
- }
- dest.writeString(domains);
- }
-
- /** @hide */
- public static StaticIpConfiguration readFromParcel(Parcel in) {
- final StaticIpConfiguration s = new StaticIpConfiguration();
- s.ipAddress = in.readParcelable(null);
- s.gateway = InetAddressUtils.unparcelInetAddress(in);
- s.dnsServers.clear();
- int size = in.readInt();
- for (int i = 0; i < size; i++) {
- s.dnsServers.add(InetAddressUtils.unparcelInetAddress(in));
- }
- s.domains = in.readString();
- return s;
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/TcpKeepalivePacketData.java b/packages/Connectivity/framework/src/android/net/TcpKeepalivePacketData.java
deleted file mode 100644
index c2c4f32..0000000
--- a/packages/Connectivity/framework/src/android/net/TcpKeepalivePacketData.java
+++ /dev/null
@@ -1,230 +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.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.net.InetAddress;
-import java.util.Objects;
-
-/**
- * Represents the actual tcp keep alive packets which will be used for hardware offload.
- * @hide
- */
-@SystemApi
-public final class TcpKeepalivePacketData extends KeepalivePacketData implements Parcelable {
- private static final String TAG = "TcpKeepalivePacketData";
-
- /**
- * TCP sequence number.
- * @hide
- */
- public final int tcpSeq;
-
- /**
- * TCP ACK number.
- * @hide
- */
- public final int tcpAck;
-
- /**
- * TCP RCV window.
- * @hide
- */
- public final int tcpWindow;
-
- /** TCP RCV window scale.
- * @hide
- */
- public final int tcpWindowScale;
-
- /**
- * IP TOS.
- * @hide
- */
- public final int ipTos;
-
- /**
- * IP TTL.
- * @hide
- */
- public final int ipTtl;
-
- public TcpKeepalivePacketData(@NonNull final InetAddress srcAddress, int srcPort,
- @NonNull final InetAddress dstAddress, int dstPort, @NonNull final byte[] data,
- int tcpSeq, int tcpAck, int tcpWindow, int tcpWindowScale, int ipTos, int ipTtl)
- throws InvalidPacketException {
- super(srcAddress, srcPort, dstAddress, dstPort, data);
- this.tcpSeq = tcpSeq;
- this.tcpAck = tcpAck;
- this.tcpWindow = tcpWindow;
- this.tcpWindowScale = tcpWindowScale;
- this.ipTos = ipTos;
- this.ipTtl = ipTtl;
- }
-
- /**
- * Get the TCP sequence number.
- *
- * See https://tools.ietf.org/html/rfc793#page-15.
- */
- public int getTcpSeq() {
- return tcpSeq;
- }
-
- /**
- * Get the TCP ACK number.
- *
- * See https://tools.ietf.org/html/rfc793#page-15.
- */
- public int getTcpAck() {
- return tcpAck;
- }
-
- /**
- * Get the TCP RCV window.
- *
- * See https://tools.ietf.org/html/rfc793#page-15.
- */
- public int getTcpWindow() {
- return tcpWindow;
- }
-
- /**
- * Get the TCP RCV window scale.
- *
- * See https://tools.ietf.org/html/rfc793#page-15.
- */
- public int getTcpWindowScale() {
- return tcpWindowScale;
- }
-
- /**
- * Get the IP type of service.
- */
- public int getIpTos() {
- return ipTos;
- }
-
- /**
- * Get the IP TTL.
- */
- public int getIpTtl() {
- return ipTtl;
- }
-
- @Override
- public boolean equals(@Nullable final Object o) {
- if (!(o instanceof TcpKeepalivePacketData)) return false;
- final TcpKeepalivePacketData other = (TcpKeepalivePacketData) o;
- final InetAddress srcAddress = getSrcAddress();
- final InetAddress dstAddress = getDstAddress();
- return srcAddress.equals(other.getSrcAddress())
- && dstAddress.equals(other.getDstAddress())
- && getSrcPort() == other.getSrcPort()
- && getDstPort() == other.getDstPort()
- && this.tcpAck == other.tcpAck
- && this.tcpSeq == other.tcpSeq
- && this.tcpWindow == other.tcpWindow
- && this.tcpWindowScale == other.tcpWindowScale
- && this.ipTos == other.ipTos
- && this.ipTtl == other.ipTtl;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort(),
- tcpAck, tcpSeq, tcpWindow, tcpWindowScale, ipTos, ipTtl);
- }
-
- /**
- * Parcelable Implementation.
- * Note that this object implements parcelable (and needs to keep doing this as it inherits
- * from a class that does), but should usually be parceled as a stable parcelable using
- * the toStableParcelable() and fromStableParcelable() methods.
- */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** Write to parcel. */
- @Override
- public void writeToParcel(@NonNull Parcel out, int flags) {
- out.writeString(getSrcAddress().getHostAddress());
- out.writeString(getDstAddress().getHostAddress());
- out.writeInt(getSrcPort());
- out.writeInt(getDstPort());
- out.writeByteArray(getPacket());
- out.writeInt(tcpSeq);
- out.writeInt(tcpAck);
- out.writeInt(tcpWindow);
- out.writeInt(tcpWindowScale);
- out.writeInt(ipTos);
- out.writeInt(ipTtl);
- }
-
- private static TcpKeepalivePacketData readFromParcel(Parcel in) throws InvalidPacketException {
- InetAddress srcAddress = InetAddresses.parseNumericAddress(in.readString());
- InetAddress dstAddress = InetAddresses.parseNumericAddress(in.readString());
- int srcPort = in.readInt();
- int dstPort = in.readInt();
- byte[] packet = in.createByteArray();
- int tcpSeq = in.readInt();
- int tcpAck = in.readInt();
- int tcpWnd = in.readInt();
- int tcpWndScale = in.readInt();
- int ipTos = in.readInt();
- int ipTtl = in.readInt();
- return new TcpKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, packet, tcpSeq,
- tcpAck, tcpWnd, tcpWndScale, ipTos, ipTtl);
- }
-
- /** Parcelable Creator. */
- public static final @NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
- new Parcelable.Creator<TcpKeepalivePacketData>() {
- public TcpKeepalivePacketData createFromParcel(Parcel in) {
- try {
- return readFromParcel(in);
- } catch (InvalidPacketException e) {
- throw new IllegalArgumentException(
- "Invalid TCP keepalive data: " + e.getError());
- }
- }
-
- public TcpKeepalivePacketData[] newArray(int size) {
- return new TcpKeepalivePacketData[size];
- }
- };
-
- @Override
- public String toString() {
- return "saddr: " + getSrcAddress()
- + " daddr: " + getDstAddress()
- + " sport: " + getSrcPort()
- + " dport: " + getDstPort()
- + " seq: " + tcpSeq
- + " ack: " + tcpAck
- + " window: " + tcpWindow
- + " windowScale: " + tcpWindowScale
- + " tos: " + ipTos
- + " ttl: " + ipTtl;
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/TcpRepairWindow.java b/packages/Connectivity/framework/src/android/net/TcpRepairWindow.java
deleted file mode 100644
index 86034f0..0000000
--- a/packages/Connectivity/framework/src/android/net/TcpRepairWindow.java
+++ /dev/null
@@ -1,45 +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 android.net;
-
-/**
- * Corresponds to C's {@code struct tcp_repair_window} from
- * include/uapi/linux/tcp.h
- *
- * @hide
- */
-public final class TcpRepairWindow {
- public final int sndWl1;
- public final int sndWnd;
- public final int maxWindow;
- public final int rcvWnd;
- public final int rcvWup;
- public final int rcvWndScale;
-
- /**
- * Constructs an instance with the given field values.
- */
- public TcpRepairWindow(final int sndWl1, final int sndWnd, final int maxWindow,
- final int rcvWnd, final int rcvWup, final int rcvWndScale) {
- this.sndWl1 = sndWl1;
- this.sndWnd = sndWnd;
- this.maxWindow = maxWindow;
- this.rcvWnd = rcvWnd;
- this.rcvWup = rcvWup;
- this.rcvWndScale = rcvWndScale;
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/TcpSocketKeepalive.java b/packages/Connectivity/framework/src/android/net/TcpSocketKeepalive.java
deleted file mode 100644
index d89814d..0000000
--- a/packages/Connectivity/framework/src/android/net/TcpSocketKeepalive.java
+++ /dev/null
@@ -1,77 +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 android.net;
-
-import android.annotation.NonNull;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.concurrent.Executor;
-
-/** @hide */
-final class TcpSocketKeepalive extends SocketKeepalive {
-
- TcpSocketKeepalive(@NonNull IConnectivityManager service,
- @NonNull Network network,
- @NonNull ParcelFileDescriptor pfd,
- @NonNull Executor executor,
- @NonNull Callback callback) {
- super(service, network, pfd, executor, callback);
- }
-
- /**
- * Starts keepalives. {@code mSocket} must be a connected TCP socket.
- *
- * - The application must not write to or read from the socket after calling this method, until
- * onDataReceived, onStopped, or onError are called. If it does, the keepalive will fail
- * with {@link #ERROR_SOCKET_NOT_IDLE}, or {@code #ERROR_INVALID_SOCKET} if the socket
- * experienced an error (as in poll(2) returned POLLERR or POLLHUP); if this happens, the data
- * received from the socket may be invalid, and the socket can't be recovered.
- * - If the socket has data in the send or receive buffer, then this call will fail with
- * {@link #ERROR_SOCKET_NOT_IDLE} and can be retried after the data has been processed.
- * An app could ensure this by using an application-layer protocol to receive acknowledgement
- * that indicates all data has been delivered to server, e.g. HTTP 200 OK.
- * Then the app could go into keepalive mode after reading all remaining data within the
- * acknowledgement.
- */
- @Override
- void startImpl(int intervalSec) {
- mExecutor.execute(() -> {
- try {
- mService.startTcpKeepalive(mNetwork, mPfd, intervalSec, mCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "Error starting packet keepalive: ", e);
- throw e.rethrowFromSystemServer();
- }
- });
- }
-
- @Override
- void stopImpl() {
- mExecutor.execute(() -> {
- try {
- if (mSlot != null) {
- mService.stopKeepalive(mNetwork, mSlot);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Error stopping packet keepalive: ", e);
- throw e.rethrowFromSystemServer();
- }
- });
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/TestNetworkInterface.java b/packages/Connectivity/framework/src/android/net/TestNetworkInterface.java
deleted file mode 100644
index 4449ff8..0000000
--- a/packages/Connectivity/framework/src/android/net/TestNetworkInterface.java
+++ /dev/null
@@ -1,78 +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 android.net;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
-
-/**
- * This class is used to return the interface name and fd of the test interface
- *
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public final class TestNetworkInterface implements Parcelable {
- @NonNull
- private final ParcelFileDescriptor mFileDescriptor;
- @NonNull
- private final String mInterfaceName;
-
- @Override
- public int describeContents() {
- return (mFileDescriptor != null) ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel out, int flags) {
- out.writeParcelable(mFileDescriptor, PARCELABLE_WRITE_RETURN_VALUE);
- out.writeString(mInterfaceName);
- }
-
- public TestNetworkInterface(@NonNull ParcelFileDescriptor pfd, @NonNull String intf) {
- mFileDescriptor = pfd;
- mInterfaceName = intf;
- }
-
- private TestNetworkInterface(@NonNull Parcel in) {
- mFileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
- mInterfaceName = in.readString();
- }
-
- @NonNull
- public ParcelFileDescriptor getFileDescriptor() {
- return mFileDescriptor;
- }
-
- @NonNull
- public String getInterfaceName() {
- return mInterfaceName;
- }
-
- @NonNull
- public static final Parcelable.Creator<TestNetworkInterface> CREATOR =
- new Parcelable.Creator<TestNetworkInterface>() {
- public TestNetworkInterface createFromParcel(Parcel in) {
- return new TestNetworkInterface(in);
- }
-
- public TestNetworkInterface[] newArray(int size) {
- return new TestNetworkInterface[size];
- }
- };
-}
diff --git a/packages/Connectivity/framework/src/android/net/TestNetworkManager.java b/packages/Connectivity/framework/src/android/net/TestNetworkManager.java
deleted file mode 100644
index 9ddd2f5..0000000
--- a/packages/Connectivity/framework/src/android/net/TestNetworkManager.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Objects;
-
-/**
- * Class that allows creation and management of per-app, test-only networks
- *
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public class TestNetworkManager {
- /**
- * Prefix for tun interfaces created by this class.
- * @hide
- */
- public static final String TEST_TUN_PREFIX = "testtun";
-
- /**
- * Prefix for tap interfaces created by this class.
- */
- public static final String TEST_TAP_PREFIX = "testtap";
-
- @NonNull private static final String TAG = TestNetworkManager.class.getSimpleName();
-
- @NonNull private final ITestNetworkManager mService;
-
- /** @hide */
- public TestNetworkManager(@NonNull ITestNetworkManager service) {
- mService = Objects.requireNonNull(service, "missing ITestNetworkManager");
- }
-
- /**
- * Teardown the capability-limited, testing-only network for a given interface
- *
- * @param network The test network that should be torn down
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public void teardownTestNetwork(@NonNull Network network) {
- try {
- mService.teardownTestNetwork(network.netId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- private void setupTestNetwork(
- @NonNull String iface,
- @Nullable LinkProperties lp,
- boolean isMetered,
- @NonNull int[] administratorUids,
- @NonNull IBinder binder) {
- try {
- mService.setupTestNetwork(iface, lp, isMetered, administratorUids, binder);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Sets up a capability-limited, testing-only network for a given interface
- *
- * @param lp The LinkProperties for the TestNetworkService to use for this test network. Note
- * that the interface name and link addresses will be overwritten, and the passed-in values
- * discarded.
- * @param isMetered Whether or not the network should be considered metered.
- * @param binder A binder object guarding the lifecycle of this test network.
- * @hide
- */
- public void setupTestNetwork(
- @NonNull LinkProperties lp, boolean isMetered, @NonNull IBinder binder) {
- Objects.requireNonNull(lp, "Invalid LinkProperties");
- setupTestNetwork(lp.getInterfaceName(), lp, isMetered, new int[0], binder);
- }
-
- /**
- * Sets up a capability-limited, testing-only network for a given interface
- *
- * @param iface the name of the interface to be used for the Network LinkProperties.
- * @param binder A binder object guarding the lifecycle of this test network.
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public void setupTestNetwork(@NonNull String iface, @NonNull IBinder binder) {
- setupTestNetwork(iface, null, true, new int[0], binder);
- }
-
- /**
- * Sets up a capability-limited, testing-only network for a given interface with the given
- * administrator UIDs.
- *
- * @param iface the name of the interface to be used for the Network LinkProperties.
- * @param administratorUids The administrator UIDs to be used for the test-only network
- * @param binder A binder object guarding the lifecycle of this test network.
- * @hide
- */
- public void setupTestNetwork(
- @NonNull String iface, @NonNull int[] administratorUids, @NonNull IBinder binder) {
- setupTestNetwork(iface, null, true, administratorUids, binder);
- }
-
- /**
- * Create a tun interface for testing purposes
- *
- * @param linkAddrs an array of LinkAddresses to assign to the TUN interface
- * @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the
- * TUN interface.
- * @deprecated Use {@link #createTunInterface(Collection)} instead.
- * @hide
- */
- @Deprecated
- @NonNull
- public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
- return createTunInterface(Arrays.asList(linkAddrs));
- }
-
- /**
- * Create a tun interface for testing purposes
- *
- * @param linkAddrs an array of LinkAddresses to assign to the TUN interface
- * @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the
- * TUN interface.
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @NonNull
- public TestNetworkInterface createTunInterface(@NonNull Collection<LinkAddress> linkAddrs) {
- try {
- final LinkAddress[] arr = new LinkAddress[linkAddrs.size()];
- return mService.createTunInterface(linkAddrs.toArray(arr));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Create a tap interface for testing purposes
- *
- * @return A ParcelFileDescriptor of the underlying TAP interface. Close this to tear down the
- * TAP interface.
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @NonNull
- public TestNetworkInterface createTapInterface() {
- try {
- return mService.createTapInterface();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
-}
diff --git a/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java b/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java
deleted file mode 100644
index 117457d..0000000
--- a/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package 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;
-
-import java.util.Objects;
-
-/**
- * A {@link NetworkSpecifier} used to identify test interfaces.
- *
- * @see TestNetworkManager
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public final class TestNetworkSpecifier extends NetworkSpecifier implements Parcelable {
-
- /**
- * Name of the network interface.
- */
- @NonNull
- private final String mInterfaceName;
-
- public TestNetworkSpecifier(@NonNull String interfaceName) {
- if (TextUtils.isEmpty(interfaceName)) {
- throw new IllegalArgumentException("Empty interfaceName");
- }
- mInterfaceName = interfaceName;
- }
-
- // This may be null in the future to support specifiers based on data other than the interface
- // name.
- @Nullable
- public String getInterfaceName() {
- return mInterfaceName;
- }
-
- @Override
- public boolean canBeSatisfiedBy(@Nullable NetworkSpecifier other) {
- return equals(other);
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof TestNetworkSpecifier)) return false;
- return TextUtils.equals(mInterfaceName, ((TestNetworkSpecifier) o).mInterfaceName);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(mInterfaceName);
- }
-
- @Override
- public String toString() {
- return "TestNetworkSpecifier (" + mInterfaceName + ")";
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeString(mInterfaceName);
- }
-
- public static final @NonNull Creator<TestNetworkSpecifier> CREATOR =
- new Creator<TestNetworkSpecifier>() {
- public TestNetworkSpecifier createFromParcel(Parcel in) {
- return new TestNetworkSpecifier(in.readString());
- }
- public TestNetworkSpecifier[] newArray(int size) {
- return new TestNetworkSpecifier[size];
- }
- };
-}
diff --git a/packages/Connectivity/framework/src/android/net/TransportInfo.java b/packages/Connectivity/framework/src/android/net/TransportInfo.java
deleted file mode 100644
index fa889ea..0000000
--- a/packages/Connectivity/framework/src/android/net/TransportInfo.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-
-/**
- * A container for transport-specific capabilities which is returned by
- * {@link NetworkCapabilities#getTransportInfo()}. Specific networks
- * may provide concrete implementations of this interface.
- * @see android.net.wifi.aware.WifiAwareNetworkInfo
- * @see android.net.wifi.WifiInfo
- */
-public interface TransportInfo {
-
- /**
- * Create a copy of a {@link TransportInfo} with some fields redacted based on the permissions
- * held by the receiving app.
- *
- * <p>
- * Usage by connectivity stack:
- * <ul>
- * <li> Connectivity stack will invoke {@link #getApplicableRedactions()} to find the list
- * of redactions that are required by this {@link TransportInfo} instance.</li>
- * <li> Connectivity stack then loops through each bit in the bitmask returned and checks if the
- * receiving app holds the corresponding permission.
- * <ul>
- * <li> If the app holds the corresponding permission, the bit is cleared from the
- * |redactions| bitmask. </li>
- * <li> If the app does not hold the corresponding permission, the bit is retained in the
- * |redactions| bitmask. </li>
- * </ul>
- * <li> Connectivity stack then invokes {@link #makeCopy(long)} with the necessary |redactions|
- * to create a copy to send to the corresponding app. </li>
- * </ul>
- * </p>
- *
- * @param redactions bitmask of redactions that needs to be performed on this instance.
- * @return Copy of this instance with the necessary redactions.
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- @NonNull
- default TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) {
- return this;
- }
-
- /**
- * Returns a bitmask of all the applicable redactions (based on the permissions held by the
- * receiving app) to be performed on this TransportInfo.
- *
- * @return bitmask of redactions applicable on this instance.
- * @see #makeCopy(long)
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- default @NetworkCapabilities.RedactionType long getApplicableRedactions() {
- return NetworkCapabilities.REDACT_NONE;
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/UidRange.aidl b/packages/Connectivity/framework/src/android/net/UidRange.aidl
deleted file mode 100644
index f70fc8e..0000000
--- a/packages/Connectivity/framework/src/android/net/UidRange.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-/**
- * An inclusive range of UIDs.
- *
- * {@hide}
- */
-parcelable UidRange;
\ No newline at end of file
diff --git a/packages/Connectivity/framework/src/android/net/UidRange.java b/packages/Connectivity/framework/src/android/net/UidRange.java
deleted file mode 100644
index bd33292..0000000
--- a/packages/Connectivity/framework/src/android/net/UidRange.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.UserHandle;
-import android.util.ArraySet;
-import android.util.Range;
-
-import java.util.Collection;
-import java.util.Set;
-
-/**
- * An inclusive range of UIDs.
- *
- * @hide
- */
-public final class UidRange implements Parcelable {
- public final int start;
- public final int stop;
-
- public UidRange(int startUid, int stopUid) {
- if (startUid < 0) throw new IllegalArgumentException("Invalid start UID.");
- if (stopUid < 0) throw new IllegalArgumentException("Invalid stop UID.");
- if (startUid > stopUid) throw new IllegalArgumentException("Invalid UID range.");
- start = startUid;
- stop = stopUid;
- }
-
- /** Creates a UidRange for the specified user. */
- public static UidRange createForUser(UserHandle user) {
- final UserHandle nextUser = UserHandle.of(user.getIdentifier() + 1);
- final int start = user.getUid(0 /* appId */);
- final int end = nextUser.getUid(0 /* appId */) - 1;
- return new UidRange(start, end);
- }
-
- /** Returns the smallest user Id which is contained in this UidRange */
- public int getStartUser() {
- return UserHandle.getUserHandleForUid(start).getIdentifier();
- }
-
- /** Returns the largest user Id which is contained in this UidRange */
- public int getEndUser() {
- return UserHandle.getUserHandleForUid(stop).getIdentifier();
- }
-
- /** Returns whether the UidRange contains the specified UID. */
- public boolean contains(int uid) {
- return start <= uid && uid <= stop;
- }
-
- /**
- * Returns the count of UIDs in this range.
- */
- public int count() {
- return 1 + stop - start;
- }
-
- /**
- * @return {@code true} if this range contains every UID contained by the {@code other} range.
- */
- public boolean containsRange(UidRange other) {
- return start <= other.start && other.stop <= stop;
- }
-
- @Override
- public int hashCode() {
- int result = 17;
- result = 31 * result + start;
- result = 31 * result + stop;
- return result;
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (this == o) {
- return true;
- }
- if (o instanceof UidRange) {
- UidRange other = (UidRange) o;
- return start == other.start && stop == other.stop;
- }
- return false;
- }
-
- @Override
- public String toString() {
- return start + "-" + stop;
- }
-
- // Implement the Parcelable interface
- // TODO: Consider making this class no longer parcelable, since all users are likely in the
- // system server.
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(start);
- dest.writeInt(stop);
- }
-
- public static final @android.annotation.NonNull Creator<UidRange> CREATOR =
- new Creator<UidRange>() {
- @Override
- public UidRange createFromParcel(Parcel in) {
- int start = in.readInt();
- int stop = in.readInt();
-
- return new UidRange(start, stop);
- }
- @Override
- public UidRange[] newArray(int size) {
- return new UidRange[size];
- }
- };
-
- /**
- * Returns whether any of the UidRange in the collection contains the specified uid
- *
- * @param ranges The collection of UidRange to check
- * @param uid the uid in question
- * @return {@code true} if the uid is contained within the ranges, {@code false} otherwise
- *
- * @see UidRange#contains(int)
- */
- public static boolean containsUid(Collection<UidRange> ranges, int uid) {
- if (ranges == null) return false;
- for (UidRange range : ranges) {
- if (range.contains(uid)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Convert a set of {@code Range<Integer>} to a set of {@link UidRange}.
- */
- @Nullable
- public static ArraySet<UidRange> fromIntRanges(@Nullable Set<Range<Integer>> ranges) {
- if (null == ranges) return null;
-
- final ArraySet<UidRange> uids = new ArraySet<>();
- for (Range<Integer> range : ranges) {
- uids.add(new UidRange(range.getLower(), range.getUpper()));
- }
- return uids;
- }
-
- /**
- * Convert a set of {@link UidRange} to a set of {@code Range<Integer>}.
- */
- @Nullable
- public static ArraySet<Range<Integer>> toIntRanges(@Nullable Set<UidRange> ranges) {
- if (null == ranges) return null;
-
- final ArraySet<Range<Integer>> uids = new ArraySet<>();
- for (UidRange range : ranges) {
- uids.add(new Range<Integer>(range.start, range.stop));
- }
- return uids;
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
deleted file mode 100644
index 4071c9a..0000000
--- a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.net.NetworkCapabilities.RedactionType;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-import java.util.Objects;
-
-/**
- * Container for VPN-specific transport information.
- *
- * @see android.net.TransportInfo
- * @see NetworkCapabilities#getTransportInfo()
- *
- * @hide
- */
-@SystemApi(client = MODULE_LIBRARIES)
-public final class VpnTransportInfo implements TransportInfo, Parcelable {
- /** Type of this VPN. */
- private final int mType;
-
- @Nullable
- private final String mSessionId;
-
- @Override
- public @RedactionType long getApplicableRedactions() {
- return REDACT_FOR_NETWORK_SETTINGS;
- }
-
- /**
- * Create a copy of a {@link VpnTransportInfo} with the sessionId redacted if necessary.
- */
- @NonNull
- public VpnTransportInfo makeCopy(@RedactionType long redactions) {
- return new VpnTransportInfo(mType,
- ((redactions & REDACT_FOR_NETWORK_SETTINGS) != 0) ? null : mSessionId);
- }
-
- public VpnTransportInfo(int type, @Nullable String sessionId) {
- this.mType = type;
- this.mSessionId = sessionId;
- }
-
- /**
- * Returns the session Id of this VpnTransportInfo.
- */
- @Nullable
- public String getSessionId() {
- return mSessionId;
- }
-
- /**
- * Returns the type of this VPN.
- */
- public int getType() {
- return mType;
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof VpnTransportInfo)) return false;
-
- VpnTransportInfo that = (VpnTransportInfo) o;
- return (this.mType == that.mType) && TextUtils.equals(this.mSessionId, that.mSessionId);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mType, mSessionId);
- }
-
- @Override
- public String toString() {
- return String.format("VpnTransportInfo{type=%d, sessionId=%s}", mType, mSessionId);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mType);
- dest.writeString(mSessionId);
- }
-
- public static final @NonNull Creator<VpnTransportInfo> CREATOR =
- new Creator<VpnTransportInfo>() {
- public VpnTransportInfo createFromParcel(Parcel in) {
- return new VpnTransportInfo(in.readInt(), in.readString());
- }
- public VpnTransportInfo[] newArray(int size) {
- return new VpnTransportInfo[size];
- }
- };
-}
diff --git a/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java b/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java
deleted file mode 100644
index 663c1b3..0000000
--- a/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.apf;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.content.Context;
-import android.content.res.Resources;
-import android.net.ConnectivityResources;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * APF program support capabilities. APF stands for Android Packet Filtering and it is a flexible
- * way to drop unwanted network packets to save power.
- *
- * See documentation at hardware/google/apf/apf.h
- *
- * This class is immutable.
- * @hide
- */
-@SystemApi
-public final class ApfCapabilities implements Parcelable {
- private static ConnectivityResources sResources;
-
- /**
- * Version of APF instruction set supported for packet filtering. 0 indicates no support for
- * packet filtering using APF programs.
- */
- public final int apfVersionSupported;
-
- /**
- * Maximum size of APF program allowed.
- */
- public final int maximumApfProgramSize;
-
- /**
- * Format of packets passed to APF filter. Should be one of ARPHRD_*
- */
- public final int apfPacketFormat;
-
- public ApfCapabilities(
- int apfVersionSupported, int maximumApfProgramSize, int apfPacketFormat) {
- this.apfVersionSupported = apfVersionSupported;
- this.maximumApfProgramSize = maximumApfProgramSize;
- this.apfPacketFormat = apfPacketFormat;
- }
-
- private ApfCapabilities(Parcel in) {
- apfVersionSupported = in.readInt();
- maximumApfProgramSize = in.readInt();
- apfPacketFormat = in.readInt();
- }
-
- @NonNull
- private static synchronized ConnectivityResources getResources(@NonNull Context ctx) {
- if (sResources == null) {
- sResources = new ConnectivityResources(ctx);
- }
- return sResources;
- }
-
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(apfVersionSupported);
- dest.writeInt(maximumApfProgramSize);
- dest.writeInt(apfPacketFormat);
- }
-
- public static final Creator<ApfCapabilities> CREATOR = new Creator<ApfCapabilities>() {
- @Override
- public ApfCapabilities createFromParcel(Parcel in) {
- return new ApfCapabilities(in);
- }
-
- @Override
- public ApfCapabilities[] newArray(int size) {
- return new ApfCapabilities[size];
- }
- };
-
- @NonNull
- @Override
- public String toString() {
- return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(),
- apfVersionSupported, maximumApfProgramSize, apfPacketFormat);
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (!(obj instanceof ApfCapabilities)) return false;
- final ApfCapabilities other = (ApfCapabilities) obj;
- return apfVersionSupported == other.apfVersionSupported
- && maximumApfProgramSize == other.maximumApfProgramSize
- && apfPacketFormat == other.apfPacketFormat;
- }
-
- /**
- * Determines whether the APF interpreter advertises support for the data buffer access opcodes
- * LDDW (LoaD Data Word) and STDW (STore Data Word). Full LDDW (LoaD Data Word) and
- * STDW (STore Data Word) support is present from APFv4 on.
- *
- * @return {@code true} if the IWifiStaIface#readApfPacketFilterData is supported.
- */
- public boolean hasDataAccess() {
- return apfVersionSupported >= 4;
- }
-
- /**
- * @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames.
- */
- public static boolean getApfDrop8023Frames() {
- // TODO: deprecate/remove this method (now unused in the platform), as the resource was
- // moved to NetworkStack.
- final Resources systemRes = Resources.getSystem();
- final int id = systemRes.getIdentifier("config_apfDrop802_3Frames", "bool", "android");
- return systemRes.getBoolean(id);
- }
-
- /**
- * @return An array of denylisted EtherType, packets with EtherTypes within it will be dropped.
- */
- public static @NonNull int[] getApfEtherTypeBlackList() {
- // TODO: deprecate/remove this method (now unused in the platform), as the resource was
- // moved to NetworkStack.
- final Resources systemRes = Resources.getSystem();
- final int id = systemRes.getIdentifier("config_apfEthTypeBlackList", "array", "android");
- return systemRes.getIntArray(id);
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/util/DnsUtils.java b/packages/Connectivity/framework/src/android/net/util/DnsUtils.java
deleted file mode 100644
index 3fe245e..0000000
--- a/packages/Connectivity/framework/src/android/net/util/DnsUtils.java
+++ /dev/null
@@ -1,377 +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 android.net.util;
-
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_DGRAM;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.InetAddresses;
-import android.net.Network;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.util.Log;
-
-import libcore.io.IoUtils;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-/**
- * @hide
- */
-public class DnsUtils {
- private static final String TAG = "DnsUtils";
- private static final int CHAR_BIT = 8;
- public static final int IPV6_ADDR_SCOPE_NODELOCAL = 0x01;
- public static final int IPV6_ADDR_SCOPE_LINKLOCAL = 0x02;
- public static final int IPV6_ADDR_SCOPE_SITELOCAL = 0x05;
- public static final int IPV6_ADDR_SCOPE_GLOBAL = 0x0e;
- private static final Comparator<SortableAddress> sRfc6724Comparator = new Rfc6724Comparator();
-
- /**
- * Comparator to sort SortableAddress in Rfc6724 style.
- */
- public static class Rfc6724Comparator implements Comparator<SortableAddress> {
- // This function matches the behaviour of _rfc6724_compare in the native resolver.
- @Override
- public int compare(SortableAddress span1, SortableAddress span2) {
- // Rule 1: Avoid unusable destinations.
- if (span1.hasSrcAddr != span2.hasSrcAddr) {
- return span2.hasSrcAddr - span1.hasSrcAddr;
- }
-
- // Rule 2: Prefer matching scope.
- if (span1.scopeMatch != span2.scopeMatch) {
- return span2.scopeMatch - span1.scopeMatch;
- }
-
- // TODO: Implement rule 3: Avoid deprecated addresses.
- // TODO: Implement rule 4: Prefer home addresses.
-
- // Rule 5: Prefer matching label.
- if (span1.labelMatch != span2.labelMatch) {
- return span2.labelMatch - span1.labelMatch;
- }
-
- // Rule 6: Prefer higher precedence.
- if (span1.precedence != span2.precedence) {
- return span2.precedence - span1.precedence;
- }
-
- // TODO: Implement rule 7: Prefer native transport.
-
- // Rule 8: Prefer smaller scope.
- if (span1.scope != span2.scope) {
- return span1.scope - span2.scope;
- }
-
- // Rule 9: Use longest matching prefix. IPv6 only.
- if (span1.prefixMatchLen != span2.prefixMatchLen) {
- return span2.prefixMatchLen - span1.prefixMatchLen;
- }
-
- // Rule 10: Leave the order unchanged. Collections.sort is a stable sort.
- return 0;
- }
- }
-
- /**
- * Class used to sort with RFC 6724
- */
- public static class SortableAddress {
- public final int label;
- public final int labelMatch;
- public final int scope;
- public final int scopeMatch;
- public final int precedence;
- public final int prefixMatchLen;
- public final int hasSrcAddr;
- public final InetAddress address;
-
- public SortableAddress(@NonNull InetAddress addr, @Nullable InetAddress srcAddr) {
- address = addr;
- hasSrcAddr = (srcAddr != null) ? 1 : 0;
- label = findLabel(addr);
- scope = findScope(addr);
- precedence = findPrecedence(addr);
- labelMatch = ((srcAddr != null) && (label == findLabel(srcAddr))) ? 1 : 0;
- scopeMatch = ((srcAddr != null) && (scope == findScope(srcAddr))) ? 1 : 0;
- if (isIpv6Address(addr) && isIpv6Address(srcAddr)) {
- prefixMatchLen = compareIpv6PrefixMatchLen(srcAddr, addr);
- } else {
- prefixMatchLen = 0;
- }
- }
- }
-
- /**
- * Sort the given address list in RFC6724 order.
- * Will leave the list unchanged if an error occurs.
- *
- * This function matches the behaviour of _rfc6724_sort in the native resolver.
- */
- public static @NonNull List<InetAddress> rfc6724Sort(@Nullable Network network,
- @NonNull List<InetAddress> answers) {
- final ArrayList<SortableAddress> sortableAnswerList = new ArrayList<>();
- for (InetAddress addr : answers) {
- sortableAnswerList.add(new SortableAddress(addr, findSrcAddress(network, addr)));
- }
-
- Collections.sort(sortableAnswerList, sRfc6724Comparator);
-
- final List<InetAddress> sortedAnswers = new ArrayList<>();
- for (SortableAddress ans : sortableAnswerList) {
- sortedAnswers.add(ans.address);
- }
-
- return sortedAnswers;
- }
-
- private static @Nullable InetAddress findSrcAddress(@Nullable Network network,
- @NonNull InetAddress addr) {
- final int domain;
- if (isIpv4Address(addr)) {
- domain = AF_INET;
- } else if (isIpv6Address(addr)) {
- domain = AF_INET6;
- } else {
- return null;
- }
- final FileDescriptor socket;
- try {
- socket = Os.socket(domain, SOCK_DGRAM, IPPROTO_UDP);
- } catch (ErrnoException e) {
- Log.e(TAG, "findSrcAddress:" + e.toString());
- return null;
- }
- try {
- if (network != null) network.bindSocket(socket);
- Os.connect(socket, new InetSocketAddress(addr, 0));
- return ((InetSocketAddress) Os.getsockname(socket)).getAddress();
- } catch (IOException | ErrnoException e) {
- return null;
- } finally {
- IoUtils.closeQuietly(socket);
- }
- }
-
- /**
- * Get the label for a given IPv4/IPv6 address.
- * RFC 6724, section 2.1.
- *
- * Note that Java will return an IPv4-mapped address as an IPv4 address.
- */
- private static int findLabel(@NonNull InetAddress addr) {
- if (isIpv4Address(addr)) {
- return 4;
- } else if (isIpv6Address(addr)) {
- if (addr.isLoopbackAddress()) {
- return 0;
- } else if (isIpv6Address6To4(addr)) {
- return 2;
- } else if (isIpv6AddressTeredo(addr)) {
- return 5;
- } else if (isIpv6AddressULA(addr)) {
- return 13;
- } else if (((Inet6Address) addr).isIPv4CompatibleAddress()) {
- return 3;
- } else if (addr.isSiteLocalAddress()) {
- return 11;
- } else if (isIpv6Address6Bone(addr)) {
- return 12;
- } else {
- // All other IPv6 addresses, including global unicast addresses.
- return 1;
- }
- } else {
- // This should never happen.
- return 1;
- }
- }
-
- private static boolean isIpv6Address(@Nullable InetAddress addr) {
- return addr instanceof Inet6Address;
- }
-
- private static boolean isIpv4Address(@Nullable InetAddress addr) {
- return addr instanceof Inet4Address;
- }
-
- private static boolean isIpv6Address6To4(@NonNull InetAddress addr) {
- if (!isIpv6Address(addr)) return false;
- final byte[] byteAddr = addr.getAddress();
- return byteAddr[0] == 0x20 && byteAddr[1] == 0x02;
- }
-
- private static boolean isIpv6AddressTeredo(@NonNull InetAddress addr) {
- if (!isIpv6Address(addr)) return false;
- final byte[] byteAddr = addr.getAddress();
- return byteAddr[0] == 0x20 && byteAddr[1] == 0x01 && byteAddr[2] == 0x00
- && byteAddr[3] == 0x00;
- }
-
- private static boolean isIpv6AddressULA(@NonNull InetAddress addr) {
- return isIpv6Address(addr) && (addr.getAddress()[0] & 0xfe) == 0xfc;
- }
-
- private static boolean isIpv6Address6Bone(@NonNull InetAddress addr) {
- if (!isIpv6Address(addr)) return false;
- final byte[] byteAddr = addr.getAddress();
- return byteAddr[0] == 0x3f && byteAddr[1] == (byte) 0xfe;
- }
-
- private static int getIpv6MulticastScope(@NonNull InetAddress addr) {
- return !isIpv6Address(addr) ? 0 : (addr.getAddress()[1] & 0x0f);
- }
-
- private static int findScope(@NonNull InetAddress addr) {
- if (isIpv6Address(addr)) {
- if (addr.isMulticastAddress()) {
- return getIpv6MulticastScope(addr);
- } else if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) {
- /**
- * RFC 4291 section 2.5.3 says loopback is to be treated as having
- * link-local scope.
- */
- return IPV6_ADDR_SCOPE_LINKLOCAL;
- } else if (addr.isSiteLocalAddress()) {
- return IPV6_ADDR_SCOPE_SITELOCAL;
- } else {
- return IPV6_ADDR_SCOPE_GLOBAL;
- }
- } else if (isIpv4Address(addr)) {
- if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) {
- return IPV6_ADDR_SCOPE_LINKLOCAL;
- } else {
- /**
- * RFC 6724 section 3.2. Other IPv4 addresses, including private addresses
- * and shared addresses (100.64.0.0/10), are assigned global scope.
- */
- return IPV6_ADDR_SCOPE_GLOBAL;
- }
- } else {
- /**
- * This should never happen.
- * Return a scope with low priority as a last resort.
- */
- return IPV6_ADDR_SCOPE_NODELOCAL;
- }
- }
-
- /**
- * Get the precedence for a given IPv4/IPv6 address.
- * RFC 6724, section 2.1.
- *
- * Note that Java will return an IPv4-mapped address as an IPv4 address.
- */
- private static int findPrecedence(@NonNull InetAddress addr) {
- if (isIpv4Address(addr)) {
- return 35;
- } else if (isIpv6Address(addr)) {
- if (addr.isLoopbackAddress()) {
- return 50;
- } else if (isIpv6Address6To4(addr)) {
- return 30;
- } else if (isIpv6AddressTeredo(addr)) {
- return 5;
- } else if (isIpv6AddressULA(addr)) {
- return 3;
- } else if (((Inet6Address) addr).isIPv4CompatibleAddress() || addr.isSiteLocalAddress()
- || isIpv6Address6Bone(addr)) {
- return 1;
- } else {
- // All other IPv6 addresses, including global unicast addresses.
- return 40;
- }
- } else {
- return 1;
- }
- }
-
- /**
- * Find number of matching initial bits between the two addresses.
- */
- private static int compareIpv6PrefixMatchLen(@NonNull InetAddress srcAddr,
- @NonNull InetAddress dstAddr) {
- final byte[] srcByte = srcAddr.getAddress();
- final byte[] dstByte = dstAddr.getAddress();
-
- // This should never happen.
- if (srcByte.length != dstByte.length) return 0;
-
- for (int i = 0; i < dstByte.length; ++i) {
- if (srcByte[i] == dstByte[i]) {
- continue;
- }
- int x = (srcByte[i] & 0xff) ^ (dstByte[i] & 0xff);
- return i * CHAR_BIT + (Integer.numberOfLeadingZeros(x) - 24); // Java ints are 32 bits
- }
- return dstByte.length * CHAR_BIT;
- }
-
- /**
- * Check if given network has Ipv4 capability
- * This function matches the behaviour of have_ipv4 in the native resolver.
- */
- public static boolean haveIpv4(@Nullable Network network) {
- final SocketAddress addrIpv4 =
- new InetSocketAddress(InetAddresses.parseNumericAddress("8.8.8.8"), 0);
- return checkConnectivity(network, AF_INET, addrIpv4);
- }
-
- /**
- * Check if given network has Ipv6 capability
- * This function matches the behaviour of have_ipv6 in the native resolver.
- */
- public static boolean haveIpv6(@Nullable Network network) {
- final SocketAddress addrIpv6 =
- new InetSocketAddress(InetAddresses.parseNumericAddress("2000::"), 0);
- return checkConnectivity(network, AF_INET6, addrIpv6);
- }
-
- private static boolean checkConnectivity(@Nullable Network network,
- int domain, @NonNull SocketAddress addr) {
- final FileDescriptor socket;
- try {
- socket = Os.socket(domain, SOCK_DGRAM, IPPROTO_UDP);
- } catch (ErrnoException e) {
- return false;
- }
- try {
- if (network != null) network.bindSocket(socket);
- Os.connect(socket, addr);
- } catch (IOException | ErrnoException e) {
- return false;
- } finally {
- IoUtils.closeQuietly(socket);
- }
- return true;
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java b/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java
deleted file mode 100644
index 8d7a0b3..0000000
--- a/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java
+++ /dev/null
@@ -1,117 +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 android.net.util;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.content.res.Resources;
-import android.net.ConnectivityResources;
-import android.net.NetworkCapabilities;
-import android.text.TextUtils;
-import android.util.AndroidRuntimeException;
-
-/**
- * Collection of utilities for socket keepalive offload.
- *
- * @hide
- */
-public final class KeepaliveUtils {
-
- public static final String TAG = "KeepaliveUtils";
-
- public static class KeepaliveDeviceConfigurationException extends AndroidRuntimeException {
- public KeepaliveDeviceConfigurationException(final String msg) {
- super(msg);
- }
- }
-
- /**
- * Read supported keepalive count for each transport type from overlay resource. This should be
- * used to create a local variable store of resource customization, and use it as the input for
- * {@link getSupportedKeepalivesForNetworkCapabilities}.
- *
- * @param context The context to read resource from.
- * @return An array of supported keepalive count for each transport type.
- */
- @NonNull
- public static int[] getSupportedKeepalives(@NonNull Context context) {
- String[] res = null;
- try {
- final ConnectivityResources connRes = new ConnectivityResources(context);
- // TODO: use R.id.config_networkSupportedKeepaliveCount directly
- final int id = connRes.get().getIdentifier("config_networkSupportedKeepaliveCount",
- "array", connRes.getResourcesContext().getPackageName());
- res = new ConnectivityResources(context).get().getStringArray(id);
- } catch (Resources.NotFoundException unused) {
- }
- if (res == null) throw new KeepaliveDeviceConfigurationException("invalid resource");
-
- final int[] ret = new int[NetworkCapabilities.MAX_TRANSPORT + 1];
- for (final String row : res) {
- if (TextUtils.isEmpty(row)) {
- throw new KeepaliveDeviceConfigurationException("Empty string");
- }
- final String[] arr = row.split(",");
- if (arr.length != 2) {
- throw new KeepaliveDeviceConfigurationException("Invalid parameter length");
- }
-
- int transport;
- int supported;
- try {
- transport = Integer.parseInt(arr[0]);
- supported = Integer.parseInt(arr[1]);
- } catch (NumberFormatException e) {
- throw new KeepaliveDeviceConfigurationException("Invalid number format");
- }
-
- if (!NetworkCapabilities.isValidTransport(transport)) {
- throw new KeepaliveDeviceConfigurationException("Invalid transport " + transport);
- }
-
- if (supported < 0) {
- throw new KeepaliveDeviceConfigurationException(
- "Invalid supported count " + supported + " for "
- + NetworkCapabilities.transportNameOf(transport));
- }
- ret[transport] = supported;
- }
- return ret;
- }
-
- /**
- * Get supported keepalive count for the given {@link NetworkCapabilities}.
- *
- * @param supportedKeepalives An array of supported keepalive count for each transport type.
- * @param nc The {@link NetworkCapabilities} of the network the socket keepalive is on.
- *
- * @return Supported keepalive count for the given {@link NetworkCapabilities}.
- */
- public static int getSupportedKeepalivesForNetworkCapabilities(
- @NonNull int[] supportedKeepalives, @NonNull NetworkCapabilities nc) {
- final int[] transports = nc.getTransportTypes();
- if (transports.length == 0) return 0;
- int supportedCount = supportedKeepalives[transports[0]];
- // Iterate through transports and return minimum supported value.
- for (final int transport : transports) {
- if (supportedCount > supportedKeepalives[transport]) {
- supportedCount = supportedKeepalives[transport];
- }
- }
- return supportedCount;
- }
-}
diff --git a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
deleted file mode 100644
index 0b42a00..0000000
--- a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.util;
-
-import static android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI;
-import static android.net.ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE;
-
-import android.annotation.NonNull;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.net.ConnectivityResources;
-import android.net.Uri;
-import android.os.Handler;
-import android.provider.Settings;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyCallback;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.concurrent.RejectedExecutionException;
-
-/**
- * A class to encapsulate management of the "Smart Networking" capability of
- * avoiding bad Wi-Fi when, for example upstream connectivity is lost or
- * certain critical link failures occur.
- *
- * This enables the device to switch to another form of connectivity, like
- * mobile, if it's available and working.
- *
- * The Runnable |avoidBadWifiCallback|, if given, is posted to the supplied
- * Handler' whenever the computed "avoid bad wifi" value changes.
- *
- * Disabling this reverts the device to a level of networking sophistication
- * circa 2012-13 by disabling disparate code paths each of which contribute to
- * maintaining continuous, working Internet connectivity.
- *
- * @hide
- */
-public class MultinetworkPolicyTracker {
- private static String TAG = MultinetworkPolicyTracker.class.getSimpleName();
-
- private final Context mContext;
- private final ConnectivityResources mResources;
- private final Handler mHandler;
- private final Runnable mAvoidBadWifiCallback;
- private final List<Uri> mSettingsUris;
- private final ContentResolver mResolver;
- private final SettingObserver mSettingObserver;
- private final BroadcastReceiver mBroadcastReceiver;
-
- private volatile boolean mAvoidBadWifi = true;
- private volatile int mMeteredMultipathPreference;
- private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-
- // Mainline module can't use internal HandlerExecutor, so add an identical executor here.
- private static class HandlerExecutor implements Executor {
- @NonNull
- private final Handler mHandler;
-
- HandlerExecutor(@NonNull Handler handler) {
- mHandler = handler;
- }
- @Override
- public void execute(Runnable command) {
- if (!mHandler.post(command)) {
- throw new RejectedExecutionException(mHandler + " is shutting down");
- }
- }
- }
-
- @VisibleForTesting
- protected class ActiveDataSubscriptionIdListener extends TelephonyCallback
- implements TelephonyCallback.ActiveDataSubscriptionIdListener {
- @Override
- public void onActiveDataSubscriptionIdChanged(int subId) {
- mActiveSubId = subId;
- reevaluateInternal();
- }
- }
-
- public MultinetworkPolicyTracker(Context ctx, Handler handler) {
- this(ctx, handler, null);
- }
-
- public MultinetworkPolicyTracker(Context ctx, Handler handler, Runnable avoidBadWifiCallback) {
- mContext = ctx;
- mResources = new ConnectivityResources(ctx);
- mHandler = handler;
- mAvoidBadWifiCallback = avoidBadWifiCallback;
- mSettingsUris = Arrays.asList(
- Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI),
- Settings.Global.getUriFor(NETWORK_METERED_MULTIPATH_PREFERENCE));
- mResolver = mContext.getContentResolver();
- mSettingObserver = new SettingObserver();
- mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- reevaluateInternal();
- }
- };
-
- ctx.getSystemService(TelephonyManager.class).registerTelephonyCallback(
- new HandlerExecutor(handler), new ActiveDataSubscriptionIdListener());
-
- updateAvoidBadWifi();
- updateMeteredMultipathPreference();
- }
-
- public void start() {
- for (Uri uri : mSettingsUris) {
- mResolver.registerContentObserver(uri, false, mSettingObserver);
- }
-
- final IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- mContext.registerReceiverForAllUsers(mBroadcastReceiver, intentFilter,
- null /* broadcastPermission */, mHandler);
-
- reevaluate();
- }
-
- public void shutdown() {
- mResolver.unregisterContentObserver(mSettingObserver);
-
- mContext.unregisterReceiver(mBroadcastReceiver);
- }
-
- public boolean getAvoidBadWifi() {
- return mAvoidBadWifi;
- }
-
- // TODO: move this to MultipathPolicyTracker.
- public int getMeteredMultipathPreference() {
- return mMeteredMultipathPreference;
- }
-
- /**
- * Whether the device or carrier configuration disables avoiding bad wifi by default.
- */
- public boolean configRestrictsAvoidBadWifi() {
- // TODO: use R.integer.config_networkAvoidBadWifi directly
- final int id = mResources.get().getIdentifier("config_networkAvoidBadWifi",
- "integer", mResources.getResourcesContext().getPackageName());
- return (getResourcesForActiveSubId().getInteger(id) == 0);
- }
-
- @NonNull
- private Resources getResourcesForActiveSubId() {
- return SubscriptionManager.getResourcesForSubId(
- mResources.getResourcesContext(), mActiveSubId);
- }
-
- /**
- * Whether we should display a notification when wifi becomes unvalidated.
- */
- public boolean shouldNotifyWifiUnvalidated() {
- return configRestrictsAvoidBadWifi() && getAvoidBadWifiSetting() == null;
- }
-
- public String getAvoidBadWifiSetting() {
- return Settings.Global.getString(mResolver, NETWORK_AVOID_BAD_WIFI);
- }
-
- @VisibleForTesting
- public void reevaluate() {
- mHandler.post(this::reevaluateInternal);
- }
-
- /**
- * Reevaluate the settings. Must be called on the handler thread.
- */
- private void reevaluateInternal() {
- if (updateAvoidBadWifi() && mAvoidBadWifiCallback != null) {
- mAvoidBadWifiCallback.run();
- }
- updateMeteredMultipathPreference();
- }
-
- public boolean updateAvoidBadWifi() {
- final boolean settingAvoidBadWifi = "1".equals(getAvoidBadWifiSetting());
- final boolean prev = mAvoidBadWifi;
- mAvoidBadWifi = settingAvoidBadWifi || !configRestrictsAvoidBadWifi();
- return mAvoidBadWifi != prev;
- }
-
- /**
- * The default (device and carrier-dependent) value for metered multipath preference.
- */
- public int configMeteredMultipathPreference() {
- // TODO: use R.integer.config_networkMeteredMultipathPreference directly
- final int id = mResources.get().getIdentifier("config_networkMeteredMultipathPreference",
- "integer", mResources.getResourcesContext().getPackageName());
- return mResources.get().getInteger(id);
- }
-
- public void updateMeteredMultipathPreference() {
- String setting = Settings.Global.getString(mResolver, NETWORK_METERED_MULTIPATH_PREFERENCE);
- try {
- mMeteredMultipathPreference = Integer.parseInt(setting);
- } catch (NumberFormatException e) {
- mMeteredMultipathPreference = configMeteredMultipathPreference();
- }
- }
-
- private class SettingObserver extends ContentObserver {
- public SettingObserver() {
- super(null);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- Log.wtf(TAG, "Should never be reached.");
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- if (!mSettingsUris.contains(uri)) {
- Log.wtf(TAG, "Unexpected settings observation: " + uri);
- }
- reevaluate();
- }
- }
-}
diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp
deleted file mode 100644
index 7265426..0000000
--- a/packages/Connectivity/service/Android.bp
+++ /dev/null
@@ -1,119 +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 {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-cc_library_shared {
- name: "libservice-connectivity",
- min_sdk_version: "30",
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-unused-parameter",
- "-Wthread-safety",
- ],
- srcs: [
- "jni/com_android_server_TestNetworkService.cpp",
- "jni/onload.cpp",
- ],
- stl: "libc++_static",
- header_libs: [
- "libbase_headers",
- ],
- shared_libs: [
- "liblog",
- "libnativehelper",
- ],
- apex_available: [
- "com.android.tethering",
- ],
-}
-
-java_library {
- name: "service-connectivity-pre-jarjar",
- sdk_version: "system_server_current",
- min_sdk_version: "30",
- srcs: [
- "src/**/*.java",
- ":framework-connectivity-shared-srcs",
- ":services-connectivity-shared-srcs",
- // TODO: move to net-utils-device-common, enable shrink optimization to avoid extra classes
- ":net-module-utils-srcs",
- ],
- libs: [
- // TODO (b/183097033) remove once system_server_current includes core_current
- "stable.core.platform.api.stubs",
- "android_system_server_stubs_current",
- "framework-annotations-lib",
- "framework-connectivity-annotations",
- "framework-connectivity.impl",
- "framework-tethering.stubs.module_lib",
- "framework-wifi.stubs.module_lib",
- "unsupportedappusage",
- "ServiceConnectivityResources",
- ],
- static_libs: [
- "dnsresolver_aidl_interface-V8-java",
- "modules-utils-os",
- "net-utils-device-common",
- "net-utils-framework-common",
- "netd-client",
- "netlink-client",
- "networkstack-client",
- "PlatformProperties",
- "service-connectivity-protos",
- ],
- apex_available: [
- "com.android.tethering",
- ],
-}
-
-java_library {
- name: "service-connectivity-protos",
- sdk_version: "system_current",
- min_sdk_version: "30",
- proto: {
- type: "nano",
- },
- srcs: [
- ":system-messages-proto-src",
- ],
- libs: ["libprotobuf-java-nano"],
- apex_available: [
- "com.android.tethering",
- ],
-}
-
-java_library {
- name: "service-connectivity",
- sdk_version: "system_server_current",
- min_sdk_version: "30",
- installable: true,
- static_libs: [
- "service-connectivity-pre-jarjar",
- ],
- jarjar_rules: "jarjar-rules.txt",
- apex_available: [
- "com.android.tethering",
- ],
-}
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/Android.bp b/packages/Connectivity/service/ServiceConnectivityResources/Android.bp
deleted file mode 100644
index f491cc7..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/Android.bp
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-// APK to hold all the wifi overlayable resources.
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-android_app {
- name: "ServiceConnectivityResources",
- sdk_version: "module_30",
- min_sdk_version: "30",
- resource_dirs: [
- "res",
- ],
- privileged: true,
- export_package_resources: true,
- apex_available: [
- "com.android.tethering",
- ],
- certificate: ":com.android.connectivity.resources.certificate",
-}
-
-android_app_certificate {
- name: "com.android.connectivity.resources.certificate",
- certificate: "resources-certs/com.android.connectivity.resources",
-}
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/AndroidManifest.xml b/packages/Connectivity/service/ServiceConnectivityResources/AndroidManifest.xml
deleted file mode 100644
index 2c30302..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/AndroidManifest.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<!-- Manifest for connectivity resources APK -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.connectivity.resources"
- coreApp="true"
- android:versionCode="1"
- android:versionName="S-initial">
- <application
- android:label="@string/connectivityResourcesAppLabel"
- android:defaultToDeviceProtectedStorage="true"
- android:directBootAware="true">
- <!-- This is only used to identify this app by resolving the action.
- The activity is never actually triggered. -->
- <activity android:name="android.app.Activity" android:exported="true" android:enabled="true">
- <intent-filter>
- <action android:name="com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-hdpi/stat_notify_rssi_in_range.png b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-hdpi/stat_notify_rssi_in_range.png
deleted file mode 100644
index 74977e6..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-hdpi/stat_notify_rssi_in_range.png
+++ /dev/null
Binary files differ
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-mdpi/stat_notify_rssi_in_range.png b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-mdpi/stat_notify_rssi_in_range.png
deleted file mode 100644
index 62e4fe9..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-mdpi/stat_notify_rssi_in_range.png
+++ /dev/null
Binary files differ
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xhdpi/stat_notify_rssi_in_range.png b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xhdpi/stat_notify_rssi_in_range.png
deleted file mode 100644
index c0586d8..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xhdpi/stat_notify_rssi_in_range.png
+++ /dev/null
Binary files differ
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xxhdpi/stat_notify_rssi_in_range.png b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xxhdpi/stat_notify_rssi_in_range.png
deleted file mode 100644
index 86c34ed..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable-xxhdpi/stat_notify_rssi_in_range.png
+++ /dev/null
Binary files differ
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable/stat_notify_wifi_in_range.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/drawable/stat_notify_wifi_in_range.xml
deleted file mode 100644
index a271ca5..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/drawable/stat_notify_wifi_in_range.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-Copyright (C) 2014 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="26.0dp"
- android:height="24.0dp"
- android:viewportWidth="26.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#4DFFFFFF"
- android:pathData="M19.1,14l-3.4,0l0,-1.5c0,-1.8 0.8,-2.8 1.5,-3.4C18.1,8.3 19.200001,8 20.6,8c1.2,0 2.3,0.3 3.1,0.8l1.9,-2.3C25.1,6.1 20.299999,2.1 13,2.1S0.9,6.1 0.4,6.5L13,22l0,0l0,0l0,0l0,0l6.5,-8.1L19.1,14z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.5,17.799999c0,-0.8 0.1,-1.3 0.2,-1.6c0.2,-0.3 0.5,-0.7 1.1,-1.2c0.4,-0.4 0.7,-0.8 1,-1.1s0.4,-0.8 0.4,-1.2c0,-0.5 -0.1,-0.9 -0.4,-1.2c-0.3,-0.3 -0.7,-0.4 -1.2,-0.4c-0.4,0 -0.8,0.1 -1.1,0.3c-0.3,0.2 -0.4,0.6 -0.4,1.1l-1.9,0c0,-1 0.3,-1.7 1,-2.2c0.6,-0.5 1.5,-0.8 2.5,-0.8c1.1,0 2,0.3 2.6,0.8c0.6,0.5 0.9,1.3 0.9,2.3c0,0.7 -0.2,1.3 -0.6,1.8c-0.4,0.6 -0.9,1.1 -1.5,1.6c-0.3,0.3 -0.5,0.5 -0.6,0.7c-0.1,0.2 -0.1,0.6 -0.1,1L19.5,17.700001zM21.4,21l-1.9,0l0,-1.8l1.9,0L21.4,21z"/>
-</vector>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-af/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-af/strings.xml
deleted file mode 100644
index 550ab8a..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-af/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Stelselkonnektiwiteithulpbronne"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Meld aan by Wi-Fi-netwerk"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Meld by netwerk aan"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> het geen internettoegang nie"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Tik vir opsies"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Selnetwerk het nie internettoegang nie"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Netwerk het nie internettoegang nie"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Daar kan nie by private DNS-bediener ingegaan word nie"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> het beperkte konnektiwiteit"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Tik om in elk geval te koppel"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Het oorgeskakel na <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Toestel gebruik <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internettoegang het nie. Heffings kan geld."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Het oorgeskakel van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobiele data"</item>
- <item msgid="6341719431034774569">"Wi-fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"\'n onbekende netwerktipe"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-am/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-am/strings.xml
deleted file mode 100644
index 7f1a9db..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-am/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"የስርዓት ግንኙነት መርጃዎች"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"ወደ Wi-Fi አውታረ መረብ በመለያ ግባ"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"ወደ አውታረ መረብ በመለያ ይግቡ"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ምንም የበይነ መረብ መዳረሻ የለም"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"ለአማራጮች መታ ያድርጉ"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"የተንቀሳቃሽ ስልክ አውታረ መረብ የበይነመረብ መዳረሻ የለውም"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"አውታረ መረብ የበይነመረብ መዳረሻ የለውም"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"የግል ዲኤንኤስ አገልጋይ ሊደረስበት አይችልም"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> የተገደበ ግንኙነት አለው"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"ለማንኛውም ለማገናኘት መታ ያድርጉ"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"ወደ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ተቀይሯል"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ምንም ዓይነት የበይነመረብ ግንኙነት በማይኖረው ጊዜ መሣሪያዎች <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ን ይጠቀማሉ። ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ።"</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"ከ<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ወደ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ተቀይሯል"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"የተንቀሳቃሽ ስልክ ውሂብ"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"ብሉቱዝ"</item>
- <item msgid="1160736166977503463">"ኢተርኔት"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"አንድ ያልታወቀ አውታረ መረብ ዓይነት"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ar/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ar/strings.xml
deleted file mode 100644
index b7a62c5..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ar/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"مصادر إمكانية اتصال الخادم"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"تسجيل الدخول إلى شبكة Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"تسجيل الدخول إلى الشبكة"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"لا يتوفّر في <xliff:g id="NETWORK_SSID">%1$s</xliff:g> إمكانية الاتصال بالإنترنت."</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"انقر للحصول على الخيارات."</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"شبكة الجوّال هذه غير متصلة بالإنترنت"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"الشبكة غير متصلة بالإنترنت"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"لا يمكن الوصول إلى خادم أسماء نظام نطاقات خاص"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"إمكانية اتصال <xliff:g id="NETWORK_SSID">%1$s</xliff:g> محدودة."</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"يمكنك النقر للاتصال على أي حال."</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"تم التبديل إلى <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"يستخدم الجهاز <xliff:g id="NEW_NETWORK">%1$s</xliff:g> عندما لا يتوفر اتصال بالإنترنت في شبكة <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>، ويمكن أن يتم فرض رسوم مقابل ذلك."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"تم التبديل من <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> إلى <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"بيانات الجوّال"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"بلوتوث"</item>
- <item msgid="1160736166977503463">"إيثرنت"</item>
- <item msgid="7347618872551558605">"شبكة افتراضية خاصة (VPN)"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"نوع شبكة غير معروف"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-as/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-as/strings.xml
deleted file mode 100644
index cf8e6ac..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-as/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"ছিষ্টেম সংযোগৰ উৎস"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"ৱাই-ফাই নেটৱৰ্কত ছাইন ইন কৰক"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"নেটৱৰ্কত ছাইন ইন কৰক"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ৰ ইণ্টাৰনেটৰ এক্সেছ নাই"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"অধিক বিকল্পৰ বাবে টিপক"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"ম’বাইল নেটৱৰ্কৰ কোনো ইণ্টাৰনেটৰ এক্সেছ নাই"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"নেটৱৰ্কৰ কোনো ইণ্টাৰনেটৰ এক্সেছ নাই"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"ব্যক্তিগত DNS ছাৰ্ভাৰ এক্সেছ কৰিব নোৱাৰি"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ৰ সকলো সেৱাৰ এক্সেছ নাই"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"যিকোনো প্ৰকাৰে সংযোগ কৰিবলৈ টিপক"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>লৈ সলনি কৰা হ’ল"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"যেতিয়া <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>ত ইণ্টাৰনেট নাথাকে, তেতিয়া ডিভাইচে <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ক ব্যৱহাৰ কৰে। মাচুল প্ৰযোজ্য হ\'ব পাৰে।"</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>ৰ পৰা <xliff:g id="NEW_NETWORK">%2$s</xliff:g> লৈ সলনি কৰা হ’ল"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"ম’বাইল ডেটা"</item>
- <item msgid="6341719431034774569">"ৱাই-ফাই"</item>
- <item msgid="5081440868800877512">"ব্লুটুথ"</item>
- <item msgid="1160736166977503463">"ইথাৰনেট"</item>
- <item msgid="7347618872551558605">"ভিপিএন"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"অজ্ঞাত প্ৰকাৰৰ নেটৱৰ্ক"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-az/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-az/strings.xml
deleted file mode 100644
index 7e927ed..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-az/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Sistem Bağlantı Resursları"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Wi-Fi şəbəkəsinə daxil ol"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Şəbəkəyə daxil olun"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> üçün internet girişi əlçatan deyil"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Seçimlər üçün tıklayın"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobil şəbəkənin internetə girişi yoxdur"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Şəbəkənin internetə girişi yoxdur"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Özəl DNS serverinə giriş mümkün deyil"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> bağlantını məhdudlaşdırdı"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"İstənilən halda klikləyin"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> şəbəkə növünə keçirildi"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> şəbəkəsinin internetə girişi olmadıqda, cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> şəbəkəsini istifadə edir. Xidmət haqqı tutula bilər."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> şəbəkəsindən <xliff:g id="NEW_NETWORK">%2$s</xliff:g> şəbəkəsinə keçirildi"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobil data"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"naməlum şəbəkə növü"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-b+sr+Latn/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-b+sr+Latn/strings.xml
deleted file mode 100644
index 3f1b976..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-b+sr+Latn/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Resursi za povezivanje sa sistemom"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Prijavljivanje na WiFi mrežu"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Prijavite se na mrežu"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nema pristup internetu"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Dodirnite za opcije"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobilna mreža nema pristup internetu"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Mreža nema pristup internetu"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Pristup privatnom DNS serveru nije uspeo"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu vezu"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Dodirnite da biste se ipak povezali"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Prešli ste na tip mreže <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Uređaj koristi tip mreže <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kada tip mreže <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu. Možda će se naplaćivati troškovi."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Prešli ste sa tipa mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na tip mreže <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobilni podaci"</item>
- <item msgid="6341719431034774569">"WiFi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Eternet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"nepoznat tip mreže"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-be/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-be/strings.xml
deleted file mode 100644
index 21edf24..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-be/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Рэсурсы для падключэння да сістэмы"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Уваход у сетку Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Увайдзіце ў сетку"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> не мае доступу ў інтэрнэт"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Дакраніцеся, каб убачыць параметры"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Мабільная сетка не мае доступу ў інтэрнэт"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Сетка не мае доступу ў інтэрнэт"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Не ўдалося атрымаць доступ да прыватнага DNS-сервера"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> мае абмежаваную магчымасць падключэння"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Націсніце, каб падключыцца"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Выкананы пераход да <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Прылада выкарыстоўвае сетку <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, калі ў сетцы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма доступу да інтэрнэту. Можа спаганяцца плата."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Выкананы пераход з <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> да <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"мабільная перадача даных"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"невядомы тып сеткі"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-bg/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-bg/strings.xml
deleted file mode 100644
index c3c2d72..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-bg/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Ресурси за свързаността на системата"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Влизане в Wi-Fi мрежа"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Вход в мрежата"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> няма достъп до интернет"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Докоснете за опции"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Мобилната мрежа няма достъп до интернет"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Мрежата няма достъп до интернет"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Не може да се осъществи достъп до частния DNS сървър"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничена свързаност"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Докоснете, за да се свържете въпреки това"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Превключи се към <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Устройството използва <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, когато <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма достъп до интернет. Възможно е да бъдете таксувани."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Превключи се от <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> към <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"мобилни данни"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"неизвестен тип мрежа"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-bn/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-bn/strings.xml
deleted file mode 100644
index 0f693bd..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-bn/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"সিস্টেম কানেক্টিভিটি রিসোর্সেস"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"ওয়াই-ফাই নেটওয়ার্কে সাইন-ইন করুন"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"নেটওয়ার্কে সাইন-ইন করুন"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-এর ইন্টারনেটে অ্যাক্সেস নেই"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"বিকল্পগুলির জন্য আলতো চাপুন"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"মোবাইল নেটওয়ার্কে কোনও ইন্টারনেট অ্যাক্সেস নেই"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"নেটওয়ার্কে কোনও ইন্টারনেট অ্যাক্সেস নেই"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"ব্যক্তিগত ডিএনএস সার্ভার অ্যাক্সেস করা যাবে না"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-এর সীমিত কানেক্টিভিটি আছে"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"তবুও কানেক্ট করতে ট্যাপ করুন"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> এ পাল্টানো হয়েছে"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> এ ইন্টারনেট অ্যাক্সেস না থাকলে <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ব্যবহার করা হয়৷ ডেটা চার্জ প্রযোজ্য৷"</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> থেকে <xliff:g id="NEW_NETWORK">%2$s</xliff:g> এ পাল্টানো হয়েছে"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"মোবাইল ডেটা"</item>
- <item msgid="6341719431034774569">"ওয়াই-ফাই"</item>
- <item msgid="5081440868800877512">"ব্লুটুথ"</item>
- <item msgid="1160736166977503463">"ইথারনেট"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"এই নেটওয়ার্কের ধরন অজানা"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-bs/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-bs/strings.xml
deleted file mode 100644
index 33d6ed9..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-bs/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Izvori povezivosti sistema"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Prijavljivanje na WiFi mrežu"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Prijava na mrežu"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"Mreža <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nema pristup internetu"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Dodirnite za opcije"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobilna mreža nema pristup internetu"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Mreža nema pristup internetu"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Nije moguće pristupiti privatnom DNS serveru"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"Mreža <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu povezivost"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Dodirnite da se ipak povežete"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Prebačeno na: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, uređaj koristi mrežu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata usluge."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Prebačeno iz mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> u <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mrežu"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"prijenos podataka na mobilnoj mreži"</item>
- <item msgid="6341719431034774569">"WiFi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"nepoznata vrsta mreže"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ca/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ca/strings.xml
deleted file mode 100644
index 04f6bd2..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ca/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Recursos de connectivitat del sistema"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Inicia la sessió a la xarxa Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Inicia la sessió a la xarxa"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> no té accés a Internet"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Toca per veure les opcions"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"La xarxa mòbil no té accés a Internet"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"La xarxa no té accés a Internet"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"No es pot accedir al servidor DNS privat"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> té una connectivitat limitada"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Toca per connectar igualment"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Actualment en ús: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"El dispositiu utilitza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> en cas que <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tingui accés a Internet. És possible que s\'hi apliquin càrrecs."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Abans es feia servir la xarxa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>; ara s\'utilitza <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"dades mòbils"</item>
- <item msgid="6341719431034774569">"Wi‑Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"un tipus de xarxa desconegut"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-cs/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-cs/strings.xml
deleted file mode 100644
index 6309e78..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-cs/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Zdroje pro připojení systému"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Přihlásit se k síti Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Přihlásit se k síti"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"Síť <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nemá přístup k internetu"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Klepnutím zobrazíte možnosti"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobilní síť nemá přístup k internetu"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Síť nemá přístup k internetu"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Nelze získat přístup k soukromému serveru DNS"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"Síť <xliff:g id="NETWORK_SSID">%1$s</xliff:g> umožňuje jen omezené připojení"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Klepnutím se i přesto připojíte"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Přechod na síť <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Když síť <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nebude mít přístup k internetu, zařízení použije síť <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Mohou být účtovány poplatky."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Přechod ze sítě <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na síť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobilní data"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"neznámý typ sítě"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-da/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-da/strings.xml
deleted file mode 100644
index 57c58af..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-da/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Systemets forbindelsesressourcer"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Log ind på Wi-Fi-netværk"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Log ind på netværk"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har ingen internetforbindelse"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Tryk for at se valgmuligheder"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobilnetværket har ingen internetadgang"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Netværket har ingen internetadgang"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Der er ikke adgang til den private DNS-server"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begrænset forbindelse"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Tryk for at oprette forbindelse alligevel"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Der blev skiftet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Enheden benytter <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, når der ikke er internetadgang via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Der opkræves muligvis betaling."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Der blev skiftet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobildata"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"en ukendt netværkstype"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-de/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-de/strings.xml
deleted file mode 100644
index d0c2551..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-de/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Systemverbindungsressourcen"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"In WLAN anmelden"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Im Netzwerk anmelden"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> hat keinen Internetzugriff"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Für Optionen tippen"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobiles Netzwerk hat keinen Internetzugriff"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Netzwerk hat keinen Internetzugriff"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Auf den privaten DNS-Server kann nicht zugegriffen werden"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"Schlechte Verbindung mit <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Tippen, um die Verbindung trotzdem herzustellen"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Zu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> gewechselt"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Auf dem Gerät werden <xliff:g id="NEW_NETWORK">%1$s</xliff:g> genutzt, wenn über <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> kein Internet verfügbar ist. Eventuell fallen Gebühren an."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Von \"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>\" zu \"<xliff:g id="NEW_NETWORK">%2$s</xliff:g>\" gewechselt"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"Mobile Daten"</item>
- <item msgid="6341719431034774569">"WLAN"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"ein unbekannter Netzwerktyp"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-el/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-el/strings.xml
deleted file mode 100644
index 1c2838d..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-el/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Πόροι συνδεσιμότητας συστήματος"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Συνδεθείτε στο δίκτυο Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Σύνδεση στο δίκτυο"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"Η εφαρμογή <xliff:g id="NETWORK_SSID">%1$s</xliff:g> δεν έχει πρόσβαση στο διαδίκτυο"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Πατήστε για να δείτε τις επιλογές"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Το δίκτυο κινητής τηλεφωνίας δεν έχει πρόσβαση στο διαδίκτυο."</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Το δίκτυο δεν έχει πρόσβαση στο διαδίκτυο."</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Δεν είναι δυνατή η πρόσβαση στον ιδιωτικό διακομιστή DNS."</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"Το δίκτυο <xliff:g id="NETWORK_SSID">%1$s</xliff:g> έχει περιορισμένη συνδεσιμότητα"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Πατήστε για σύνδεση ούτως ή άλλως"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Μετάβαση σε δίκτυο <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Η συσκευή χρησιμοποιεί το δίκτυο <xliff:g id="NEW_NETWORK">%1$s</xliff:g> όταν το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> δεν έχει πρόσβαση στο διαδίκτυο. Μπορεί να ισχύουν χρεώσεις."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Μετάβαση από το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> στο δίκτυο <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"δεδομένα κινητής τηλεφωνίας"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"άγνωστος τύπος δικτύου"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rAU/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rAU/strings.xml
deleted file mode 100644
index db5ad70..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rAU/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"System connectivity resources"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Sign in to a Wi-Fi network"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Sign in to network"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Tap for options"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobile network has no Internet access"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Network has no Internet access"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Private DNS server cannot be accessed"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Tap to connect anyway"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobile data"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"an unknown network type"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rCA/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rCA/strings.xml
deleted file mode 100644
index db5ad70..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rCA/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"System connectivity resources"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Sign in to a Wi-Fi network"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Sign in to network"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Tap for options"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobile network has no Internet access"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Network has no Internet access"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Private DNS server cannot be accessed"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Tap to connect anyway"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobile data"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"an unknown network type"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rGB/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rGB/strings.xml
deleted file mode 100644
index db5ad70..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rGB/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"System connectivity resources"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Sign in to a Wi-Fi network"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Sign in to network"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Tap for options"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobile network has no Internet access"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Network has no Internet access"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Private DNS server cannot be accessed"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Tap to connect anyway"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobile data"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"an unknown network type"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rIN/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rIN/strings.xml
deleted file mode 100644
index db5ad70..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rIN/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"System connectivity resources"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Sign in to a Wi-Fi network"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Sign in to network"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no Internet access"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Tap for options"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobile network has no Internet access"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Network has no Internet access"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Private DNS server cannot be accessed"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Tap to connect anyway"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobile data"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"an unknown network type"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rXC/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rXC/strings.xml
deleted file mode 100644
index 2602bfa..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-en-rXC/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"System Connectivity Resources"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Sign in to Wi-Fi network"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Sign in to network"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has no internet access"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Tap for options"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobile network has no internet access"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Network has no internet access"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Private DNS server cannot be accessed"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Tap to connect anyway"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no internet access. Charges may apply."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobile data"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"an unknown network type"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-es-rUS/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-es-rUS/strings.xml
deleted file mode 100644
index e5f1833..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Recursos de conectividad del sistema"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Accede a una red Wi-Fi."</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Acceder a la red"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>no tiene acceso a Internet"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Presiona para ver opciones"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"La red móvil no tiene acceso a Internet"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"La red no tiene acceso a Internet"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"No se puede acceder al servidor DNS privado"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiene conectividad limitada"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Presiona para conectarte de todas formas"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Se cambió a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"El dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Se cambió de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"Datos móviles"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"un tipo de red desconocido"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-es/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-es/strings.xml
deleted file mode 100644
index e4f4307..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-es/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Recursos de conectividad del sistema"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Iniciar sesión en red Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Iniciar sesión en la red"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> no tiene acceso a Internet"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Toca para ver opciones"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"La red móvil no tiene acceso a Internet"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"La red no tiene acceso a Internet"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"No se ha podido acceder al servidor DNS privado"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiene una conectividad limitada"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Toca para conectarte de todas formas"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Se ha cambiado a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"El dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Se ha cambiado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"datos móviles"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"un tipo de red desconocido"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-et/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-et/strings.xml
deleted file mode 100644
index cec408f..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-et/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Süsteemi ühenduvuse allikad"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Logi sisse WiFi-võrku"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Võrku sisselogimine"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"Võrgul <xliff:g id="NETWORK_SSID">%1$s</xliff:g> puudub Interneti-ühendus"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Puudutage valikute nägemiseks"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobiilsidevõrgul puudub Interneti-ühendus"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Võrgul puudub Interneti-ühendus"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Privaatsele DNS-serverile ei pääse juurde"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"Võrgu <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ühendus on piiratud"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Puudutage, kui soovite siiski ühenduse luua"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Lülitati võrgule <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Seade kasutab võrku <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, kui võrgul <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> puudub juurdepääs Internetile. Rakenduda võivad tasud."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Lülitati võrgult <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> võrgule <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobiilne andmeside"</item>
- <item msgid="6341719431034774569">"WiFi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"tundmatu võrgutüüp"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-eu/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-eu/strings.xml
deleted file mode 100644
index f3ee9b1..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-eu/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Sistemaren konexio-baliabideak"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Hasi saioa Wi-Fi sarean"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Hasi saioa sarean"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"Ezin da konektatu Internetera <xliff:g id="NETWORK_SSID">%1$s</xliff:g> sarearen bidez"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Sakatu aukerak ikusteko"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Sare mugikorra ezin da konektatu Internetera"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Sarea ezin da konektatu Internetera"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Ezin da atzitu DNS zerbitzari pribatua"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> sareak konektagarritasun murriztua du"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Sakatu hala ere konektatzeko"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> erabiltzen ari zara orain"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> Internetera konektatzeko gauza ez denean, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> erabiltzen du gailuak. Agian kostuak ordaindu beharko dituzu."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> erabiltzen ari zinen, baina <xliff:g id="NEW_NETWORK">%2$s</xliff:g> erabiltzen ari zara orain"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"datu-konexioa"</item>
- <item msgid="6341719431034774569">"Wifia"</item>
- <item msgid="5081440868800877512">"Bluetooth-a"</item>
- <item msgid="1160736166977503463">"Ethernet-a"</item>
- <item msgid="7347618872551558605">"VPNa"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"sare mota ezezaguna"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-fa/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fa/strings.xml
deleted file mode 100644
index 0c5b147..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-fa/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"منابع اتصال سیستم"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"ورود به شبکه Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"ورود به سیستم شبکه"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> به اینترنت دسترسی ندارد"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"برای گزینهها ضربه بزنید"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"شبکه تلفن همراه به اینترنت دسترسی ندارد"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"شبکه به اینترنت دسترسی ندارد"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"سرور DNS خصوصی قابل دسترسی نیست"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> اتصال محدودی دارد"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"بههرصورت، برای اتصال ضربه بزنید"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"به <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> تغییر کرد"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"وقتی <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> به اینترنت دسترسی نداشته باشد، دستگاه از <xliff:g id="NEW_NETWORK">%1$s</xliff:g> استفاده میکند. ممکن است هزینههایی اعمال شود."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"از <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> به <xliff:g id="NEW_NETWORK">%2$s</xliff:g> تغییر کرد"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"داده تلفن همراه"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"بلوتوث"</item>
- <item msgid="1160736166977503463">"اترنت"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"نوع شبکه نامشخص"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-fi/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fi/strings.xml
deleted file mode 100644
index 84c0034..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-fi/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Järjestelmän yhteysresurssit"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Kirjaudu Wi-Fi-verkkoon"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Kirjaudu verkkoon"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ei ole yhteydessä internetiin"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Näytä vaihtoehdot napauttamalla."</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobiiliverkko ei ole yhteydessä internetiin"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Verkko ei ole yhteydessä internetiin"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Ei pääsyä yksityiselle DNS-palvelimelle"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> toimii rajoitetulla yhteydellä"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Yhdistä napauttamalla"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> otettiin käyttöön"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> otetaan käyttöön, kun <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ei voi muodostaa yhteyttä internetiin. Veloitukset ovat mahdollisia."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> poistettiin käytöstä ja <xliff:g id="NEW_NETWORK">%2$s</xliff:g> otettiin käyttöön."</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobiilidata"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"tuntematon verkon tyyppi"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr-rCA/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr-rCA/strings.xml
deleted file mode 100644
index 0badf1b..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr-rCA/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Ressources de connectivité système"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Connectez-vous au réseau Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Connectez-vous au réseau"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"Le réseau <xliff:g id="NETWORK_SSID">%1$s</xliff:g> n\'offre aucun accès à Internet"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Touchez pour afficher les options"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Le réseau cellulaire n\'offre aucun accès à Internet"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Le réseau n\'offre aucun accès à Internet"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Impossible d\'accéder au serveur DNS privé"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"Le réseau <xliff:g id="NETWORK_SSID">%1$s</xliff:g> offre une connectivité limitée"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Touchez pour vous connecter quand même"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Passé au réseau <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quand <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas d\'accès à Internet. Des frais peuvent s\'appliquer."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Passé du réseau <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> au <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"données cellulaires"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"RPV"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"un type de réseau inconnu"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr/strings.xml
deleted file mode 100644
index b483525..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-fr/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Ressources de connectivité système"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Connectez-vous au réseau Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Se connecter au réseau"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"Aucune connexion à Internet pour <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Appuyez ici pour afficher des options."</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Le réseau mobile ne dispose d\'aucun accès à Internet"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Le réseau ne dispose d\'aucun accès à Internet"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Impossible d\'accéder au serveur DNS privé"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"La connectivité de <xliff:g id="NETWORK_SSID">%1$s</xliff:g> est limitée"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Appuyer pour se connecter quand même"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Nouveau réseau : <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> lorsque <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas de connexion Internet. Des frais peuvent s\'appliquer."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Ancien réseau : <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>. Nouveau réseau : <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"données mobiles"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"type de réseau inconnu"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-gl/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-gl/strings.xml
deleted file mode 100644
index dfe8137..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-gl/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Recursos de conectividade do sistema"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Inicia sesión na rede wifi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Inicia sesión na rede"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> non ten acceso a Internet"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Toca para ver opcións."</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"A rede de telefonía móbil non ten acceso a Internet"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"A rede non ten acceso a Internet"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Non se puido acceder ao servidor DNS privado"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"A conectividade de <xliff:g id="NETWORK_SSID">%1$s</xliff:g> é limitada"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Toca para conectarte de todas formas"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Cambiouse a: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ten acceso a Internet. Pódense aplicar cargos."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Cambiouse de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"datos móbiles"</item>
- <item msgid="6341719431034774569">"wifi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"un tipo de rede descoñecido"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-gu/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-gu/strings.xml
deleted file mode 100644
index e49b11d..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-gu/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"સિસ્ટમની કનેક્ટિવિટીનાં સાધનો"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"વાઇ-ફાઇ નેટવર્ક પર સાઇન ઇન કરો"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"નેટવર્ક પર સાઇન ઇન કરો"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ઇન્ટરનેટ ઍક્સેસ ધરાવતું નથી"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"વિકલ્પો માટે ટૅપ કરો"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"મોબાઇલ નેટવર્ક કોઈ ઇન્ટરનેટ ઍક્સેસ ધરાવતું નથી"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"નેટવર્ક કોઈ ઇન્ટરનેટ ઍક્સેસ ધરાવતું નથી"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"ખાનગી DNS સર્વર ઍક્સેસ કરી શકાતા નથી"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> મર્યાદિત કનેક્ટિવિટી ધરાવે છે"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"છતાં કનેક્ટ કરવા માટે ટૅપ કરો"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> પર સ્વિચ કર્યું"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"જ્યારે <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> પાસે કોઈ ઇન્ટરનેટ ઍક્સેસ ન હોય ત્યારે ઉપકરણ <xliff:g id="NEW_NETWORK">%1$s</xliff:g>નો ઉપયોગ કરે છે. શુલ્ક લાગુ થઈ શકે છે."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> પરથી <xliff:g id="NEW_NETWORK">%2$s</xliff:g> પર સ્વિચ કર્યું"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"મોબાઇલ ડેટા"</item>
- <item msgid="6341719431034774569">"વાઇ-ફાઇ"</item>
- <item msgid="5081440868800877512">"બ્લૂટૂથ"</item>
- <item msgid="1160736166977503463">"ઇથરનેટ"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"કોઈ અજાણ્યો નેટવર્કનો પ્રકાર"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-hi/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hi/strings.xml
deleted file mode 100644
index 80ed699..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-hi/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"सिस्टम कनेक्टिविटी के संसाधन"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"वाई-फ़ाई नेटवर्क में साइन इन करें"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"नेटवर्क में साइन इन करें"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> का इंटरनेट नहीं चल रहा है"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"विकल्पों के लिए टैप करें"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"मोबाइल नेटवर्क पर इंटरनेट ऐक्सेस नहीं है"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"इस नेटवर्क पर इंटरनेट ऐक्सेस नहीं है"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"निजी डीएनएस सर्वर को ऐक्सेस नहीं किया जा सकता"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> की कनेक्टिविटी सीमित है"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"फिर भी कनेक्ट करने के लिए टैप करें"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> पर ले जाया गया"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> में इंटरनेट की सुविधा नहीं होने पर डिवाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> का इस्तेमाल करता है. इसके लिए शुल्क लिया जा सकता है."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> से <xliff:g id="NEW_NETWORK">%2$s</xliff:g> पर ले जाया गया"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"मोबाइल डेटा"</item>
- <item msgid="6341719431034774569">"वाई-फ़ाई"</item>
- <item msgid="5081440868800877512">"ब्लूटूथ"</item>
- <item msgid="1160736166977503463">"ईथरनेट"</item>
- <item msgid="7347618872551558605">"वीपीएन"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"अज्ञात नेटवर्क टाइप"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-hr/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hr/strings.xml
deleted file mode 100644
index 24bb22f..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-hr/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Resursi za povezivost sustava"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Prijava na Wi-Fi mrežu"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Prijava na mrežu"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nema pristup internetu"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Dodirnite za opcije"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobilna mreža nema pristup internetu"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Mreža nema pristup internetu"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Nije moguće pristupiti privatnom DNS poslužitelju"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu povezivost"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Dodirnite da biste se ipak povezali"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Prelazak na drugu mrežu: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, na uređaju se upotrebljava <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata naknade."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Mreža je promijenjena: <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> > <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobilni podaci"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"nepoznata vrsta mreže"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-hu/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hu/strings.xml
deleted file mode 100644
index 47a1142..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-hu/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Rendszerkapcsolat erőforrásai"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Bejelentkezés Wi-Fi hálózatba"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Bejelentkezés a hálózatba"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"A(z) <xliff:g id="NETWORK_SSID">%1$s</xliff:g> hálózaton nincs internet-hozzáférés"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Koppintson a beállítások megjelenítéséhez"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"A mobilhálózaton nincs internet-hozzáférés"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"A hálózaton nincs internet-hozzáférés"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"A privát DNS-kiszolgálóhoz nem lehet hozzáférni"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"A(z) <xliff:g id="NETWORK_SSID">%1$s</xliff:g> hálózat korlátozott kapcsolatot biztosít"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Koppintson, ha mindenképpen csatlakozni szeretne"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Átváltva erre: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> használata, ha nincs internet-hozzáférés <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-kapcsolaton keresztül. A szolgáltató díjat számíthat fel."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Átváltva <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-hálózatról erre: <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobiladatok"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"ismeretlen hálózati típus"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-hy/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-hy/strings.xml
deleted file mode 100644
index dd951e8..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-hy/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"System Connectivity Resources"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Մուտք գործեք Wi-Fi ցանց"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Մուտք գործեք ցանց"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ցանցը չունի մուտք ինտերնետին"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Հպեք՝ ընտրանքները տեսնելու համար"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Բջջային ցանցը չի ապահովում ինտերնետ կապ"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Ցանցը միացված չէ ինտերնետին"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Մասնավոր DNS սերվերն անհասանելի է"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ցանցի կապը սահմանափակ է"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Հպեք՝ միանալու համար"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Անցել է <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ցանցի"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Երբ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ցանցում ինտերնետ կապ չի լինում, սարքն անցնում է <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ցանցի: Նման դեպքում կարող են վճարներ գանձվել:"</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ցանցից անցել է <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ցանցի"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"բջջային ինտերնետ"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"ցանցի անհայտ տեսակ"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-in/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-in/strings.xml
deleted file mode 100644
index d559f6b..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-in/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Resource Konektivitas Sistem"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Login ke jaringan Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Login ke jaringan"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tidak memiliki akses internet"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Ketuk untuk melihat opsi"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Jaringan seluler tidak memiliki akses internet"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Jaringan tidak memiliki akses internet"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Server DNS pribadi tidak dapat diakses"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> memiliki konektivitas terbatas"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Ketuk untuk tetap menyambungkan"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Dialihkan ke <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Perangkat menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> jika <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tidak memiliki akses internet. Tarif mungkin berlaku."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Dialihkan dari <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ke <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"data seluler"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"jenis jaringan yang tidak dikenal"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-is/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-is/strings.xml
deleted file mode 100644
index 877c85f..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-is/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Tengigögn kerfis"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Skrá inn á Wi-Fi net"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Skrá inn á net"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> er ekki með internetaðgang"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Ýttu til að sjá valkosti"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Farsímakerfið er ekki tengt við internetið"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Netkerfið er ekki tengt við internetið"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Ekki næst í DNS-einkaþjón"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"Tengigeta <xliff:g id="NETWORK_SSID">%1$s</xliff:g> er takmörkuð"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Ýttu til að tengjast samt"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Skipt yfir á <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Tækið notar <xliff:g id="NEW_NETWORK">%1$s</xliff:g> þegar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> er ekki með internetaðgang. Gjöld kunna að eiga við."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Skipt úr <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> yfir í <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"farsímagögn"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"óþekkt tegund netkerfis"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-it/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-it/strings.xml
deleted file mode 100644
index bcac393..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-it/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Risorse per connettività di sistema"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Accedi a rete Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Accedi alla rete"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> non ha accesso a Internet"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Tocca per le opzioni"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"La rete mobile non ha accesso a Internet"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"La rete non ha accesso a Internet"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Non è possibile accedere al server DNS privato"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ha una connettività limitata"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Tocca per connettere comunque"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Passato a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Il dispositivo utilizza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ha accesso a Internet. Potrebbero essere applicati costi."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Passato da <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"dati mobili"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"tipo di rete sconosciuto"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-iw/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-iw/strings.xml
deleted file mode 100644
index d6684ce..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-iw/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"משאבי קישוריות מערכת"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"היכנס לרשת Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"היכנס לרשת"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"ל-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> אין גישה לאינטרנט"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"הקש לקבלת אפשרויות"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"לרשת הסלולרית אין גישה לאינטרנט"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"לרשת אין גישה לאינטרנט"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"לא ניתן לגשת לשרת DNS הפרטי"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"הקישוריות של <xliff:g id="NETWORK_SSID">%1$s</xliff:g> מוגבלת"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"כדי להתחבר למרות זאת יש להקיש"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"מעבר אל <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"המכשיר משתמש ברשת <xliff:g id="NEW_NETWORK">%1$s</xliff:g> כשלרשת <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> אין גישה לאינטרנט. עשויים לחול חיובים."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"עבר מרשת <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> לרשת <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"חבילת גלישה"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"אתרנט"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"סוג רשת לא מזוהה"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ja/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ja/strings.xml
deleted file mode 100644
index fa4a30a..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ja/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"システム接続リソース"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Wi-Fiネットワークにログイン"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"ネットワークにログインしてください"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> はインターネットにアクセスできません"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"タップしてその他のオプションを表示"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"モバイル ネットワークがインターネットに接続されていません"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"ネットワークがインターネットに接続されていません"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"プライベート DNS サーバーにアクセスできません"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> の接続が制限されています"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"接続するにはタップしてください"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"「<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>」に切り替えました"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"デバイスで「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」によるインターネット接続ができない場合に「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」を使用します。通信料が発生することがあります。"</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"「<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>」から「<xliff:g id="NEW_NETWORK">%2$s</xliff:g>」に切り替えました"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"モバイルデータ"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"イーサネット"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"不明なネットワーク タイプ"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ka/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ka/strings.xml
deleted file mode 100644
index 4183310..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ka/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"სისტემის კავშირის რესურსები"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Wi-Fi ქსელთან დაკავშირება"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"ქსელში შესვლა"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-ს არ აქვს ინტერნეტზე წვდომა"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"შეეხეთ ვარიანტების სანახავად"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"მობილურ ქსელს არ აქვს ინტერნეტზე წვდომა"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"ქსელს არ აქვს ინტერნეტზე წვდომა"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"პირად DNS სერვერზე წვდომა შეუძლებელია"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-ის კავშირები შეზღუდულია"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"შეეხეთ, თუ მაინც გსურთ დაკავშირება"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"ახლა გამოიყენება <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"თუ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ინტერნეტთან კავშირს დაკარგავს, მოწყობილობის მიერ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> იქნება გამოყენებული, რამაც შეიძლება დამატებითი ხარჯები გამოიწვიოს."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"ახლა გამოიყენება <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> (გამოიყენებოდა <xliff:g id="NEW_NETWORK">%2$s</xliff:g>)"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"მობილური ინტერნეტი"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"უცნობი ტიპის ქსელი"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-kk/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-kk/strings.xml
deleted file mode 100644
index 54d5eb3..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-kk/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Жүйе байланысы ресурстары"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Wi-Fi желісіне кіру"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Желіге кіру"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> желісінің интернетті пайдалану мүмкіндігі шектеулі."</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Опциялар үшін түртіңіз"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Мобильдік желі интернетке қосылмаған."</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Желі интернетке қосылмаған."</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Жеке DNS серверіне кіру мүмкін емес."</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> желісінің қосылу мүмкіндігі шектеулі."</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Бәрібір жалғау үшін түртіңіз."</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> желісіне ауысты"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Құрылғы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> желісінде интернетпен байланыс жоғалған жағдайда <xliff:g id="NEW_NETWORK">%1$s</xliff:g> желісін пайдаланады. Деректер ақысы алынуы мүмкін."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> желісінен <xliff:g id="NEW_NETWORK">%2$s</xliff:g> желісіне ауысты"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"мобильдік деректер"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"желі түрі белгісіз"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-km/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-km/strings.xml
deleted file mode 100644
index bd778a1..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-km/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"ធនធានតភ្ជាប់ប្រព័ន្ធ"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"ចូលបណ្ដាញវ៉ាយហ្វាយ"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"ចូលទៅបណ្តាញ"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> មិនមានការតភ្ជាប់អ៊ីនធឺណិតទេ"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"ប៉ះសម្រាប់ជម្រើស"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"បណ្ដាញទូរសព្ទចល័តមិនមានការតភ្ជាប់អ៊ីនធឺណិតទេ"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"បណ្ដាញមិនមានការតភ្ជាប់អ៊ីនធឺណិតទេ"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"មិនអាចចូលប្រើម៉ាស៊ីនមេ DNS ឯកជនបានទេ"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> មានការតភ្ជាប់មានកម្រិត"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"មិនអីទេ ចុចភ្ជាប់ចុះ"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"បានប្តូរទៅ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"ឧបករណ៍ប្រើ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> នៅពេលដែល <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> មិនមានការតភ្ជាប់អ៊ីនធឺណិត។ អាចគិតថ្លៃលើការប្រើប្រាស់ទិន្នន័យ។"</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"បានប្តូរពី <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ទៅ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"ទិន្នន័យទូរសព្ទចល័ត"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"ប៊្លូធូស"</item>
- <item msgid="1160736166977503463">"អ៊ីសឺរណិត"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"ប្រភេទបណ្តាញដែលមិនស្គាល់"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-kn/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-kn/strings.xml
deleted file mode 100644
index 7f3a420..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-kn/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"ಸಿಸ್ಟಂ ಸಂಪರ್ಕ ಕಲ್ಪಿಸುವಿಕೆ ಮಾಹಿತಿಯ ಮೂಲಗಳು"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"ವೈ-ಫೈ ನೆಟ್ವರ್ಕ್ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"ನೆಟ್ವರ್ಕ್ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"ಆಯ್ಕೆಗಳಿಗೆ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"ಮೊಬೈಲ್ ನೆಟ್ವರ್ಕ್ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"ನೆಟ್ವರ್ಕ್ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿಲ್ಲ"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"ಖಾಸಗಿ DNS ಸರ್ವರ್ ಅನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ಸೀಮಿತ ಸಂಪರ್ಕ ಕಲ್ಪಿಸುವಿಕೆಯನ್ನು ಹೊಂದಿದೆ"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"ಹೇಗಾದರೂ ಸಂಪರ್ಕಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶ ಹೊಂದಿಲ್ಲದಿರುವಾಗ, ಸಾಧನವು <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ಬಳಸುತ್ತದೆ. ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ರಿಂದ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"ಮೊಬೈಲ್ ಡೇಟಾ"</item>
- <item msgid="6341719431034774569">"ವೈ-ಫೈ"</item>
- <item msgid="5081440868800877512">"ಬ್ಲೂಟೂತ್"</item>
- <item msgid="1160736166977503463">"ಇಥರ್ನೆಟ್"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"ಅಪರಿಚಿತ ನೆಟ್ವರ್ಕ್ ಪ್ರಕಾರ"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ko/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ko/strings.xml
deleted file mode 100644
index a763cc5..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ko/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"시스템 연결 리소스"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Wi-Fi 네트워크에 로그인"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"네트워크에 로그인"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>이(가) 인터넷에 액세스할 수 없습니다."</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"탭하여 옵션 보기"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"모바일 네트워크에 인터넷이 연결되어 있지 않습니다."</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"네트워크에 인터넷이 연결되어 있지 않습니다."</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"비공개 DNS 서버에 액세스할 수 없습니다."</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>에서 연결을 제한했습니다."</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"계속 연결하려면 탭하세요."</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>(으)로 전환"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>(으)로 인터넷에 연결할 수 없는 경우 기기에서 <xliff:g id="NEW_NETWORK">%1$s</xliff:g>이(가) 사용됩니다. 요금이 부과될 수 있습니다."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>에서 <xliff:g id="NEW_NETWORK">%2$s</xliff:g>(으)로 전환"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"모바일 데이터"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"블루투스"</item>
- <item msgid="1160736166977503463">"이더넷"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"알 수 없는 네트워크 유형"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ky/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ky/strings.xml
deleted file mode 100644
index 3550af8..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ky/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Тутумдун байланыш булагы"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Wi-Fi түйүнүнө кирүү"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Тармакка кирүү"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> Интернетке туташуусу жок"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Параметрлерди ачуу үчүн таптап коюңуз"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Мобилдик Интернет жок"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Тармактын Интернет жок"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Жеке DNS сервери жеткиликсиз"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> байланышы чектелген"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Баары бир туташуу үчүн таптаңыз"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> тармагына которуштурулду"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> тармагы Интернетке туташпай турганда, түзмөгүңүз <xliff:g id="NEW_NETWORK">%1$s</xliff:g> тармагын колдонот. Акы алынышы мүмкүн."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> дегенден <xliff:g id="NEW_NETWORK">%2$s</xliff:g> тармагына которуштурулду"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"мобилдик трафик"</item>
- <item msgid="6341719431034774569">"Wi‑Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"белгисиз тармак түрү"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-lo/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-lo/strings.xml
deleted file mode 100644
index 4b3056f..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-lo/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"ແຫຼ່ງຂໍ້ມູນການເຊື່ອມຕໍ່ລະບົບ"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"ເຂົ້າສູ່ລະບົບເຄືອຂ່າຍ Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"ລົງຊື່ເຂົ້າເຄືອຂ່າຍ"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"ແຕະເພື່ອເບິ່ງຕົວເລືອກ"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"ເຄືອຂ່າຍມືຖືບໍ່ສາມາດເຂົ້າເຖິງອິນເຕີເນັດໄດ້"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"ເຄືອຂ່າຍບໍ່ສາມາດເຂົ້າເຖິງອິນເຕີເນັດໄດ້"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"ບໍ່ສາມາດເຂົ້າເຖິງເຊີບເວີ DNS ສ່ວນຕົວໄດ້"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ມີການເຊື່ອມຕໍ່ທີ່ຈຳກັດ"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"ແຕະເພື່ອຢືນຢັນການເຊື່ອມຕໍ່"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"ສະຫຼັບໄປໃຊ້ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ແລ້ວ"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"ອຸປະກອນຈະໃຊ້ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ເມື່ອ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ. ອາດມີການຮຽກເກັບຄ່າບໍລິການ."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"ສະຫຼັບຈາກ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ໄປໃຊ້ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ແລ້ວ"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"ອິນເຕີເນັດມືຖື"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"ອີເທີເນັດ"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"ບໍ່ຮູ້ຈັກປະເພດເຄືອຂ່າຍ"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-lt/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-lt/strings.xml
deleted file mode 100644
index 8eb41f1..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-lt/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"System Connectivity Resources"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Prisijungti prie „Wi-Fi“ tinklo"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Prisijungti prie tinklo"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"„<xliff:g id="NETWORK_SSID">%1$s</xliff:g>“ negali pasiekti interneto"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Palieskite, kad būtų rodomos parinktys."</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobiliojo ryšio tinkle nėra prieigos prie interneto"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Tinkle nėra prieigos prie interneto"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Privataus DNS serverio negalima pasiekti"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"„<xliff:g id="NETWORK_SSID">%1$s</xliff:g>“ ryšys apribotas"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Palieskite, jei vis tiek norite prisijungti"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Perjungta į tinklą <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Įrenginyje naudojamas kitas tinklas (<xliff:g id="NEW_NETWORK">%1$s</xliff:g>), kai dabartiniame tinkle (<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>) nėra interneto ryšio. Gali būti taikomi mokesčiai."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Perjungta iš tinklo <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> į tinklą <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobiliojo ryšio duomenys"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Eternetas"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"nežinomas tinklo tipas"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-lv/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-lv/strings.xml
deleted file mode 100644
index 0647a4f..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-lv/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Sistēmas savienojamības resursi"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Pierakstieties Wi-Fi tīklā"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Pierakstīšanās tīklā"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"Tīklā <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nav piekļuves internetam"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Pieskarieties, lai skatītu iespējas."</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobilajā tīklā nav piekļuves internetam."</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Tīklā nav piekļuves internetam."</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Nevar piekļūt privātam DNS serverim."</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"Tīklā <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ir ierobežota savienojamība"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Lai tik un tā izveidotu savienojumu, pieskarieties"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Pārslēdzās uz tīklu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Kad vienā tīklā (<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>) nav piekļuves internetam, ierīcē tiek izmantots cits tīkls (<xliff:g id="NEW_NETWORK">%1$s</xliff:g>). Var tikt piemērota maksa."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Pārslēdzās no tīkla <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> uz tīklu <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobilie dati"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"nezināms tīkla veids"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc204-mnc04/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc204-mnc04/config.xml
deleted file mode 100644
index 7e7025f..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc204-mnc04/config.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<!-- Configuration values for ConnectivityService
- DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
- Overlay package following the overlayable.xml configuration in the same directory:
- https://source.android.com/devices/architecture/rros -->
-<resources>
- <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
- Internet access. Actual device behaviour is controlled by
- Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
- <integer translatable="false" name="config_networkAvoidBadWifi">0</integer>
-</resources>
\ No newline at end of file
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc310-mnc004/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc310-mnc004/config.xml
deleted file mode 100644
index 7e7025f..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc310-mnc004/config.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<!-- Configuration values for ConnectivityService
- DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
- Overlay package following the overlayable.xml configuration in the same directory:
- https://source.android.com/devices/architecture/rros -->
-<resources>
- <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
- Internet access. Actual device behaviour is controlled by
- Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
- <integer translatable="false" name="config_networkAvoidBadWifi">0</integer>
-</resources>
\ No newline at end of file
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml
deleted file mode 100644
index 7e7025f..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<!-- Configuration values for ConnectivityService
- DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
- Overlay package following the overlayable.xml configuration in the same directory:
- https://source.android.com/devices/architecture/rros -->
-<resources>
- <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
- Internet access. Actual device behaviour is controlled by
- Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
- <integer translatable="false" name="config_networkAvoidBadWifi">0</integer>
-</resources>
\ No newline at end of file
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mk/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mk/strings.xml
deleted file mode 100644
index b0024e2..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mk/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"System Connectivity Resources"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Најавете се на мрежа на Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Најавете се на мрежа"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> нема интернет-пристап"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Допрете за опции"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Мобилната мрежа нема интернет-пристап"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Мрежата нема интернет-пристап"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Не може да се пристапи до приватниот DNS-сервер"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничена поврзливост"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Допрете за да се поврзете и покрај тоа"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Префрлено на <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Уредот користи <xliff:g id="NEW_NETWORK">%1$s</xliff:g> кога <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема пристап до интернет. Може да се наплатат трошоци."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Префрлено од <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"мобилен интернет"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Етернет"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"непознат тип мрежа"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ml/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ml/strings.xml
deleted file mode 100644
index 8ce7667..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ml/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"സിസ്റ്റം കണക്റ്റിവിറ്റി ഉറവിടങ്ങൾ"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"വൈഫൈ നെറ്റ്വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"നെറ്റ്വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> എന്നതിന് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ല"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"ഓപ്ഷനുകൾക്ക് ടാപ്പുചെയ്യുക"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"മൊബെെൽ നെറ്റ്വർക്കിന് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ല"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"നെറ്റ്വർക്കിന് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ല"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"സ്വകാര്യ DNS സെർവർ ആക്സസ് ചെയ്യാനാവില്ല"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> എന്നതിന് പരിമിതമായ കണക്റ്റിവിറ്റി ഉണ്ട്"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"ഏതുവിധേനയും കണക്റ്റ് ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> എന്നതിലേക്ക് മാറി"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-ന് ഇന്റർനെറ്റ് ആക്സസ് ഇല്ലാത്തപ്പോൾ ഉപകരണം <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ഉപയോഗിക്കുന്നു. നിരക്കുകൾ ബാധകമായേക്കാം."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> നെറ്റ്വർക്കിൽ നിന്ന് <xliff:g id="NEW_NETWORK">%2$s</xliff:g> നെറ്റ്വർക്കിലേക്ക് മാറി"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"മൊബൈൽ ഡാറ്റ"</item>
- <item msgid="6341719431034774569">"വൈഫൈ"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"ഇതർനെറ്റ്"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"അജ്ഞാതമായ നെറ്റ്വർക്ക് തരം"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mn/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mn/strings.xml
deleted file mode 100644
index be8b592..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mn/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Системийн холболтын нөөцүүд"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Wi-Fi сүлжээнд нэвтэрнэ үү"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Сүлжээнд нэвтэрнэ үү"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-д интернэтийн хандалт алга"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Сонголт хийхийн тулд товшино уу"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Мобайл сүлжээнд интернэт хандалт байхгүй байна"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Сүлжээнд интернэт хандалт байхгүй байна"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Хувийн DNS серверт хандах боломжгүй байна"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> зарим үйлчилгээнд хандах боломжгүй байна"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Ямар ч тохиолдолд холбогдохын тулд товших"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> руу шилжүүлсэн"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> интернет холболтгүй үед төхөөрөмж <xliff:g id="NEW_NETWORK">%1$s</xliff:g>-г ашигладаг. Төлбөр гарч болзошгүй."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-с <xliff:g id="NEW_NETWORK">%2$s</xliff:g> руу шилжүүлсэн"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"мобайл дата"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Этернэт"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"үл мэдэгдэх сүлжээний төрөл"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mr/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mr/strings.xml
deleted file mode 100644
index fe7df84..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mr/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"सिस्टम कनेक्टिव्हिटी चे स्रोत"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"वाय-फाय नेटवर्कमध्ये साइन इन करा"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"नेटवर्कवर साइन इन करा"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ला इंटरनेट अॅक्सेस नाही"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"पर्यायांसाठी टॅप करा"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"मोबाइल नेटवर्कला इंटरनेट ॲक्सेस नाही"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"नेटवर्कला इंटरनेट ॲक्सेस नाही"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"खाजगी DNS सर्व्हर ॲक्सेस करू शकत नाही"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ला मर्यादित कनेक्टिव्हिटी आहे"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"तरीही कनेक्ट करण्यासाठी टॅप करा"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> वर स्विच केले"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> कडे इंटरनेटचा अॅक्सेस नसताना डिव्हाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> वापरते. शुल्क लागू शकते."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> वरून <xliff:g id="NEW_NETWORK">%2$s</xliff:g> वर स्विच केले"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"मोबाइल डेटा"</item>
- <item msgid="6341719431034774569">"वाय-फाय"</item>
- <item msgid="5081440868800877512">"ब्लूटूथ"</item>
- <item msgid="1160736166977503463">"इथरनेट"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"अज्ञात नेटवर्क प्रकार"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ms/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ms/strings.xml
deleted file mode 100644
index 54b49a2..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ms/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Sumber Kesambungan Sistem"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Log masuk ke rangkaian Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Log masuk ke rangkaian"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiada akses Internet"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Ketik untuk mendapatkan pilihan"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Rangkaian mudah alih tiada akses Internet"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Rangkaian tiada akses Internet"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Pelayan DNS peribadi tidak boleh diakses"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> mempunyai kesambungan terhad"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Ketik untuk menyambung juga"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Beralih kepada <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Peranti menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> apabila <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tiada akses Internet. Bayaran mungkin dikenakan."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Beralih daripada <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kepada <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"data mudah alih"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"jenis rangkaian tidak diketahui"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-my/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-my/strings.xml
deleted file mode 100644
index 15b75f0..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-my/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"စနစ်ချိတ်ဆက်နိုင်မှု ရင်းမြစ်များ"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"ဝိုင်ဖိုင်ကွန်ရက်သို့ လက်မှတ်ထိုးဝင်ပါ"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"ကွန်ယက်သို့ လက်မှတ်ထိုးဝင်ရန်"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> တွင် အင်တာနက်အသုံးပြုခွင့် မရှိပါ"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"အခြားရွေးချယ်စရာများကိုကြည့်ရန် တို့ပါ"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"မိုဘိုင်းကွန်ရက်တွင် အင်တာနက်ချိတ်ဆက်မှု မရှိပါ"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"ကွန်ရက်တွင် အင်တာနက်အသုံးပြုခွင့် မရှိပါ"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"သီးသန့် ဒီအန်အက်စ် (DNS) ဆာဗာကို သုံး၍မရပါ။"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> တွင် ချိတ်ဆက်မှုကို ကန့်သတ်ထားသည်"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"မည်သို့ပင်ဖြစ်စေ ချိတ်ဆက်ရန် တို့ပါ"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ဖြင့် အင်တာနက် အသုံးမပြုနိုင်သည့်အချိန်တွင် စက်ပစ္စည်းသည် <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ကို သုံးပါသည်။ ဒေတာသုံးစွဲခ ကျသင့်နိုင်ပါသည်။"</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> မှ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"မိုဘိုင်းဒေတာ"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"ဘလူးတုသ်"</item>
- <item msgid="1160736166977503463">"အီသာနက်"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"အမည်မသိကွန်ရက်အမျိုးအစား"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-nb/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-nb/strings.xml
deleted file mode 100644
index a561def..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-nb/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Ressurser for systemtilkobling"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Logg på Wi-Fi-nettverket"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Logg på nettverk"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har ingen internettilkobling"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Trykk for å få alternativer"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobilnettverket har ingen internettilgang"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Nettverket har ingen internettilgang"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Den private DNS-tjeneren kan ikke nås"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begrenset tilkobling"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Trykk for å koble til likevel"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Byttet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Enheten bruker <xliff:g id="NEW_NETWORK">%1$s</xliff:g> når <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ikke har Internett-tilgang. Avgifter kan påløpe."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Byttet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobildata"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"en ukjent nettverkstype"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ne/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ne/strings.xml
deleted file mode 100644
index f74542d..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ne/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"सिस्टम कनेक्टिभिटीका स्रोतहरू"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Wi-Fi नेटवर्कमा साइन इन गर्नुहोस्"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"सञ्जालमा साइन इन गर्नुहोस्"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> को इन्टरनेटमाथि पहुँच छैन"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"विकल्पहरूका लागि ट्याप गर्नुहोस्"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"मोबाइल नेटवर्कको इन्टरनेटमाथि पहुँच छैन"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"नेटवर्कको इन्टरनेटमाथि पहुँच छैन"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"निजी DNS सर्भरमाथि पहुँच प्राप्त गर्न सकिँदैन"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> को जडान सीमित छ"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"जसरी भए पनि जडान गर्न ट्याप गर्नुहोस्"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> मा बदल्नुहोस्"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> मार्फत इन्टरनेटमाथि पहुँच राख्न नसकेको अवस्थामा यन्त्रले <xliff:g id="NEW_NETWORK">%1$s</xliff:g> प्रयोग गर्दछ। शुल्क लाग्न सक्छ।"</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> बाट <xliff:g id="NEW_NETWORK">%2$s</xliff:g> मा परिवर्तन गरियो"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"मोबाइल डेटा"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"ब्लुटुथ"</item>
- <item msgid="1160736166977503463">"इथरनेट"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"नेटवर्कको कुनै अज्ञात प्रकार"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-nl/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-nl/strings.xml
deleted file mode 100644
index 0f3203b..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-nl/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Resources voor systeemconnectiviteit"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Inloggen bij wifi-netwerk"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Inloggen bij netwerk"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> heeft geen internettoegang"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Tik voor opties"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobiel netwerk heeft geen internettoegang"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Netwerk heeft geen internettoegang"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Geen toegang tot privé-DNS-server"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> heeft beperkte connectiviteit"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Tik om toch verbinding te maken"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Overgeschakeld naar <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Apparaat gebruikt <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internetverbinding heeft. Er kunnen kosten in rekening worden gebracht."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Overgeschakeld van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> naar <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobiele data"</item>
- <item msgid="6341719431034774569">"Wifi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"een onbekend netwerktype"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-or/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-or/strings.xml
deleted file mode 100644
index ecf4d69..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-or/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"ସିଷ୍ଟମର ସଂଯୋଗ ସମ୍ବନ୍ଧିତ ରିସୋର୍ସଗୁଡ଼ିକ"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"ୱାଇ-ଫାଇ ନେଟୱର୍କରେ ସାଇନ୍-ଇନ୍ କରନ୍ତୁ"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"ନେଟ୍ୱର୍କରେ ସାଇନ୍ ଇନ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ର ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍ ନାହିଁ"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"ବିକଳ୍ପ ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"ମୋବାଇଲ୍ ନେଟ୍ୱାର୍କରେ ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍ ନାହିଁ"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"ନେଟ୍ୱାର୍କରେ ଇଣ୍ଟର୍ନେଟ୍ ଆକ୍ସେସ୍ ନାହିଁ"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"ବ୍ୟକ୍ତିଗତ DNS ସର୍ଭର୍ ଆକ୍ସେସ୍ କରିହେବ ନାହିଁ"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ର ସୀମିତ ସଂଯୋଗ ଅଛି"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"ତଥାପି ଯୋଗାଯୋଗ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>କୁ ବଦଳାଗଲା"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>ର ଇଣ୍ଟରନେଟ୍ ଆକ୍ସେସ୍ ନଥିବାବେଳେ ଡିଭାଇସ୍ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ବ୍ୟବହାର କରିଥାଏ। ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ।"</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ରୁ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>କୁ ବଦଳାଗଲା"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"ମୋବାଇଲ ଡାଟା"</item>
- <item msgid="6341719431034774569">"ୱାଇ-ଫାଇ"</item>
- <item msgid="5081440868800877512">"ବ୍ଲୁଟୁଥ୍"</item>
- <item msgid="1160736166977503463">"ଇଥରନେଟ୍"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"ଏକ ଅଜଣା ନେଟୱାର୍କ ପ୍ରକାର"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pa/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pa/strings.xml
deleted file mode 100644
index 4328054..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pa/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"ਸਿਸਟਮ ਕਨੈਕਟੀਵਿਟੀ ਸਰੋਤ"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰੋ"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"ਨੈੱਟਵਰਕ \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰੋ"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"ਵਿਕਲਪਾਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਕੋਲ ਇੰਟਰਨੈੱਟ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"ਨੈੱਟਵਰਕ ਕੋਲ ਇੰਟਰਨੈੱਟ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"ਨਿੱਜੀ ਡੋਮੇਨ ਨਾਮ ਪ੍ਰਣਾਲੀ (DNS) ਸਰਵਰ \'ਤੇ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ਕੋਲ ਸੀਮਤ ਕਨੈਕਟੀਵਿਟੀ ਹੈ"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"ਫਿਰ ਵੀ ਕਨੈਕਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"ਬਦਲਕੇ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ਲਿਆਂਦਾ ਗਿਆ"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ਦੀ ਇੰਟਰਨੈੱਟ \'ਤੇ ਪਹੁੰਚ ਨਾ ਹੋਣ \'ਤੇ ਡੀਵਾਈਸ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ। ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ਤੋਂ ਬਦਲਕੇ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> \'ਤੇ ਕੀਤਾ ਗਿਆ"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"ਮੋਬਾਈਲ ਡਾਟਾ"</item>
- <item msgid="6341719431034774569">"ਵਾਈ-ਫਾਈ"</item>
- <item msgid="5081440868800877512">"ਬਲੂਟੁੱਥ"</item>
- <item msgid="1160736166977503463">"ਈਥਰਨੈੱਟ"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"ਕੋਈ ਅਗਿਆਤ ਨੈੱਟਵਰਕ ਦੀ ਕਿਸਮ"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pl/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pl/strings.xml
deleted file mode 100644
index e6b3a0c..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pl/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Zasoby systemowe dotyczące łączności"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Zaloguj się w sieci Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Zaloguj się do sieci"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nie ma dostępu do internetu"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Kliknij, by wyświetlić opcje"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Sieć komórkowa nie ma dostępu do internetu"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Sieć nie ma dostępu do internetu"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Brak dostępu do prywatnego serwera DNS"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ma ograniczoną łączność"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Kliknij, by mimo to nawiązać połączenie"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Zmieniono na połączenie typu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Urządzenie korzysta z połączenia typu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, gdy <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nie dostępu do internetu. Mogą zostać naliczone opłaty."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Przełączono z połączenia typu <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>."</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobilna transmisja danych"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"nieznany typ sieci"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rBR/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rBR/strings.xml
deleted file mode 100644
index f1d0bc0..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rBR/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Recursos de conectividade do sistema"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Fazer login na rede Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Fazer login na rede"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> não tem acesso à Internet"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Toque para ver opções"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"A rede móvel não tem acesso à Internet"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"A rede não tem acesso à Internet"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Não é possível acessar o servidor DNS privado"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conectividade limitada"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Toque para conectar mesmo assim"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Esse serviço pode ser cobrado."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"dados móveis"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"um tipo de rede desconhecido"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rPT/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rPT/strings.xml
deleted file mode 100644
index 163d70b..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt-rPT/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Recursos de conetividade do sistema"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Iniciar sessão na rede Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Início de sessão na rede"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> não tem acesso à Internet"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Toque para obter mais opções"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"A rede móvel não tem acesso à Internet"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"A rede não tem acesso à Internet"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Não é possível aceder ao servidor DNS."</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conetividade limitada."</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Toque para ligar mesmo assim."</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Mudou para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Podem aplicar-se custos."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Mudou de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"dados móveis"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"um tipo de rede desconhecido"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt/strings.xml
deleted file mode 100644
index f1d0bc0..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-pt/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Recursos de conectividade do sistema"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Fazer login na rede Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Fazer login na rede"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> não tem acesso à Internet"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Toque para ver opções"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"A rede móvel não tem acesso à Internet"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"A rede não tem acesso à Internet"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Não é possível acessar o servidor DNS privado"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conectividade limitada"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Toque para conectar mesmo assim"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Esse serviço pode ser cobrado."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"dados móveis"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"um tipo de rede desconhecido"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ro/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ro/strings.xml
deleted file mode 100644
index 221261c..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ro/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Resurse pentru conectivitatea sistemului"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Conectați-vă la rețeaua Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Conectați-vă la rețea"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nu are acces la internet"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Atingeți pentru opțiuni"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Rețeaua mobilă nu are acces la internet"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Rețeaua nu are acces la internet"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Serverul DNS privat nu poate fi accesat"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> are conectivitate limitată"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Atingeți pentru a vă conecta oricum"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"S-a comutat la <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Dispozitivul folosește <xliff:g id="NEW_NETWORK">%1$s</xliff:g> când <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nu are acces la internet. Se pot aplica taxe."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"S-a comutat de la <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> la <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"date mobile"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"un tip de rețea necunoscut"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ru/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ru/strings.xml
deleted file mode 100644
index ba179b7..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ru/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"System Connectivity Resources"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Подключение к Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Регистрация в сети"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"Сеть \"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>\" не подключена к Интернету"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Нажмите, чтобы показать варианты."</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Мобильная сеть не подключена к Интернету"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Сеть не подключена к Интернету"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Доступа к частному DNS-серверу нет."</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"Подключение к сети \"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>\" ограничено"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Нажмите, чтобы подключиться"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Новое подключение: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Устройство использует <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, если подключение к сети <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> недоступно. Может взиматься плата за передачу данных."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Устройство отключено от сети <xliff:g id="NEW_NETWORK">%2$s</xliff:g> и теперь использует <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"мобильный интернет"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"неизвестный тип сети"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-si/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-si/strings.xml
deleted file mode 100644
index 1c493a7..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-si/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"පද්ධති සබැඳුම් හැකියා සම්පත්"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Wi-Fi ජාලයට පුරනය වන්න"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"ජාලයට පුරනය වන්න"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> හට අන්තර්ජාල ප්රවේශය නැත"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"විකල්ප සඳහා තට්ටු කරන්න"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"ජංගම ජාලවලට අන්තර්ජාල ප්රවේශය නැත"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"ජාලයට අන්තර්ජාල ප්රවේශය නැත"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"පුද්ගලික DNS සේවාදායකයට ප්රවේශ වීමට නොහැකිය"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> හට සීමිත සබැඳුම් හැකියාවක් ඇත"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"කෙසේ වෙතත් ඉදිරියට යාමට තට්ටු කරන්න"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> වෙත මාරු විය"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"උපාංගය <xliff:g id="NEW_NETWORK">%1$s</xliff:g> <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> සඳහා අන්තර්ජාල ප්රවේශය නැති විට භාවිත කරයි. ගාස්තු අදාළ විය හැකිය."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> සිට <xliff:g id="NEW_NETWORK">%2$s</xliff:g> වෙත මාරු විය"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"ජංගම දත්ත"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"බ්ලූටූත්"</item>
- <item msgid="1160736166977503463">"ඊතර්නෙට්"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"නොදන්නා ජාල වර්ගයකි"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sk/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sk/strings.xml
deleted file mode 100644
index 1b9313a..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sk/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Zdroje možností pripojenia systému"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Prihlásiť sa do siete Wi‑Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Prihlásenie do siete"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nemá prístup k internetu"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Klepnutím získate možnosti"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobilná sieť nemá prístup k internetu"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Sieť nemá prístup k internetu"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"K súkromnému serveru DNS sa nepodarilo získať prístup"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> má obmedzené pripojenie"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Ak sa chcete aj napriek tomu pripojiť, klepnite"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Prepnuté na sieť: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Keď <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nemá prístup k internetu, zariadenie používa <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Môžu sa účtovať poplatky."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Prepnuté zo siete <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sieť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobilné dáta"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"neznámy typ siete"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sl/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sl/strings.xml
deleted file mode 100644
index 739fb8e..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sl/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Viri povezljivosti sistema"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Prijavite se v omrežje Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Prijava v omrežje"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"Omrežje <xliff:g id="NETWORK_SSID">%1$s</xliff:g> nima dostopa do interneta"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Dotaknite se za možnosti"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobilno omrežje nima dostopa do interneta"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Omrežje nima dostopa do interneta"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Do zasebnega strežnika DNS ni mogoče dostopati"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"Povezljivost omrežja <xliff:g id="NETWORK_SSID">%1$s</xliff:g> je omejena"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Dotaknite se, da kljub temu vzpostavite povezavo"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Preklopljeno na omrežje vrste <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Naprava uporabi omrežje vrste <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, ko omrežje vrste <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nima dostopa do interneta. Prenos podatkov se lahko zaračuna."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Preklopljeno z omrežja vrste <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na omrežje vrste <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"prenos podatkov v mobilnem omrežju"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"neznana vrsta omrežja"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sq/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sq/strings.xml
deleted file mode 100644
index cf8cf3b..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sq/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Burimet e lidhshmërisë së sistemit"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Identifikohu në rrjetin Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Identifikohu në rrjet"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nuk ka qasje në internet"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Trokit për opsionet"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Rrjeti celular nuk ka qasje në internet"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Rrjeti nuk ka qasje në internet"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Serveri privat DNS nuk mund të qaset"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ka lidhshmëri të kufizuar"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Trokit për t\'u lidhur gjithsesi"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Kaloi te <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Pajisja përdor <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kur <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nuk ka qasje në internet. Mund të zbatohen tarifa."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Kaloi nga <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> te <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"të dhënat celulare"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Eternet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"një lloj rrjeti i panjohur"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sr/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sr/strings.xml
deleted file mode 100644
index 1f7c95c..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sr/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Ресурси за повезивање са системом"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Пријављивање на WiFi мрежу"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Пријавите се на мрежу"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> нема приступ интернету"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Додирните за опције"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Мобилна мрежа нема приступ интернету"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Мрежа нема приступ интернету"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Приступ приватном DNS серверу није успео"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничену везу"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Додирните да бисте се ипак повезали"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Прешли сте на тип мреже <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Уређај користи тип мреже <xliff:g id="NEW_NETWORK">%1$s</xliff:g> када тип мреже <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема приступ интернету. Можда ће се наплаћивати трошкови."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Прешли сте са типа мреже <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на тип мреже <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"мобилни подаци"</item>
- <item msgid="6341719431034774569">"WiFi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Етернет"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"непознат тип мреже"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sv/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sv/strings.xml
deleted file mode 100644
index 57e74e9..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sv/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Resurser för systemanslutning"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Logga in på ett wifi-nätverk"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Logga in på nätverket"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har ingen internetanslutning"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Tryck för alternativ"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobilnätverket har ingen internetanslutning"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Nätverket har ingen internetanslutning"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Det går inte att komma åt den privata DNS-servern."</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begränsad anslutning"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Tryck för att ansluta ändå"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Byte av nätverk till <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> används på enheten när det inte finns internetåtkomst via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Avgifter kan tillkomma."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Byte av nätverk från <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> till <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobildata"</item>
- <item msgid="6341719431034774569">"Wifi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"en okänd nätverkstyp"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sw/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-sw/strings.xml
deleted file mode 100644
index 5c4d594..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-sw/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Nyenzo za Muunganisho wa Mfumo"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Ingia kwa mtandao wa Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Ingia katika mtandao"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> haina uwezo wa kufikia intaneti"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Gusa ili upate chaguo"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mtandao wa simu hauna uwezo wa kufikia intaneti"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Mtandao hauna uwezo wa kufikia intaneti"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Seva ya faragha ya DNS haiwezi kufikiwa"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ina muunganisho unaofikia huduma chache."</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Gusa ili uunganishe tu"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Sasa inatumia <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Kifaa hutumia <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wakati <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> haina intaneti. Huenda ukalipishwa."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Imebadilisha mtandao kutoka <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sasa inatumia <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"data ya mtandao wa simu"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethaneti"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"aina ya mtandao isiyojulikana"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ta/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ta/strings.xml
deleted file mode 100644
index 90f89c9..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ta/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"சிஸ்டம் இணைப்பு மூலங்கள்"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"வைஃபை நெட்வொர்க்கில் உள்நுழையவும்"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"நெட்வொர்க்கில் உள்நுழையவும்"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> நெட்வொர்க்கிற்கு இணைய அணுகல் இல்லை"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"விருப்பங்களுக்கு, தட்டவும்"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"மொபைல் நெட்வொர்க்கிற்கு இணைய அணுகல் இல்லை"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"நெட்வொர்க்கிற்கு இணைய அணுகல் இல்லை"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"தனிப்பட்ட DNS சேவையகத்தை அணுக இயலாது"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> வரம்பிற்கு உட்பட்ட இணைப்புநிலையைக் கொண்டுள்ளது"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"எப்படியேனும் இணைப்பதற்குத் தட்டவும்"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> நெட்வொர்க்கில் இண்டர்நெட் அணுகல் இல்லாததால், சாதனமானது <xliff:g id="NEW_NETWORK">%1$s</xliff:g> நெட்வொர்க்கைப் பயன்படுத்துகிறது. கட்டணங்கள் விதிக்கப்படலாம்."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> இலிருந்து <xliff:g id="NEW_NETWORK">%2$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"மொபைல் டேட்டா"</item>
- <item msgid="6341719431034774569">"வைஃபை"</item>
- <item msgid="5081440868800877512">"புளூடூத்"</item>
- <item msgid="1160736166977503463">"ஈதர்நெட்"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"தெரியாத நெட்வொர்க் வகை"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-te/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-te/strings.xml
deleted file mode 100644
index c69b599..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-te/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"సిస్టమ్ కనెక్టివిటీ రిసోర్స్లు"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Wi-Fi నెట్వర్క్కి సైన్ ఇన్ చేయండి"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"నెట్వర్క్కి సైన్ ఇన్ చేయండి"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>కి ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"ఎంపికల కోసం నొక్కండి"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"మొబైల్ నెట్వర్క్కు ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"నెట్వర్క్కు ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"ప్రైవేట్ DNS సర్వర్ను యాక్సెస్ చేయడం సాధ్యపడదు"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> పరిమిత కనెక్టివిటీని కలిగి ఉంది"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"ఏదేమైనా కనెక్ట్ చేయడానికి నొక్కండి"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>కి మార్చబడింది"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"పరికరం <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>కి ఇంటర్నెట్ యాక్సెస్ లేనప్పుడు <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ని ఉపయోగిస్తుంది. ఛార్జీలు వర్తించవచ్చు."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> నుండి <xliff:g id="NEW_NETWORK">%2$s</xliff:g>కి మార్చబడింది"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"మొబైల్ డేటా"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"బ్లూటూత్"</item>
- <item msgid="1160736166977503463">"ఈథర్నెట్"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"తెలియని నెట్వర్క్ రకం"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-th/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-th/strings.xml
deleted file mode 100644
index eee5a35..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-th/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"ทรัพยากรการเชื่อมต่อของระบบ"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"ลงชื่อเข้าใช้เครือข่าย WiFi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"ลงชื่อเข้าใช้เครือข่าย"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> เข้าถึงอินเทอร์เน็ตไม่ได้"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"แตะเพื่อดูตัวเลือก"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"เครือข่ายมือถือไม่มีการเข้าถึงอินเทอร์เน็ต"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"เครือข่ายไม่มีการเข้าถึงอินเทอร์เน็ต"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"เข้าถึงเซิร์ฟเวอร์ DNS ไม่ได้"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> มีการเชื่อมต่อจำกัด"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"แตะเพื่อเชื่อมต่อ"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"เปลี่ยนเป็น <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"อุปกรณ์จะใช้ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> เมื่อ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> เข้าถึงอินเทอร์เน็ตไม่ได้ โดยอาจมีค่าบริการ"</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"เปลี่ยนจาก <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> เป็น <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"อินเทอร์เน็ตมือถือ"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"บลูทูธ"</item>
- <item msgid="1160736166977503463">"อีเทอร์เน็ต"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"ประเภทเครือข่ายที่ไม่รู้จัก"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-tl/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-tl/strings.xml
deleted file mode 100644
index 8d665fe..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-tl/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Mga Resource ng Pagkakonekta ng System"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Mag-sign in sa Wi-Fi network"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Mag-sign in sa network"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"Walang access sa internet ang <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"I-tap para sa mga opsyon"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Walang access sa internet ang mobile network"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Walang access sa internet ang network"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Hindi ma-access ang pribadong DNS server"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"Limitado ang koneksyon ng <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"I-tap para kumonekta pa rin"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Lumipat sa <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Ginagamit ng device ang <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kapag walang access sa internet ang <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Maaaring may mga malapat na singilin."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Lumipat sa <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mula sa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobile data"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"isang hindi kilalang uri ng network"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-tr/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-tr/strings.xml
deleted file mode 100644
index cfb7632..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-tr/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Sistem Bağlantı Kaynakları"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Kablosuz ağda oturum açın"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Ağda oturum açın"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ağının internet bağlantısı yok"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Seçenekler için dokunun"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobil ağın internet bağlantısı yok"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Ağın internet bağlantısı yok"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Gizli DNS sunucusuna erişilemiyor"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> sınırlı bağlantıya sahip"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Yine de bağlanmak için dokunun"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ağına geçildi"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ağının internet erişimi olmadığında cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ağını kullanır. Bunun için ödeme alınabilir."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ağından <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ağına geçildi"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobil veri"</item>
- <item msgid="6341719431034774569">"Kablosuz"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"bilinmeyen ağ türü"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-uk/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-uk/strings.xml
deleted file mode 100644
index c5da746..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-uk/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Ресурси для підключення системи"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Вхід у мережу Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Вхід у мережу"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"Мережа <xliff:g id="NETWORK_SSID">%1$s</xliff:g> не має доступу до Інтернету"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Торкніться, щоб відкрити опції"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Мобільна мережа не має доступу до Інтернету"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Мережа не має доступу до Інтернету"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Немає доступу до приватного DNS-сервера"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"Підключення до мережі <xliff:g id="NETWORK_SSID">%1$s</xliff:g> обмежено"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Натисніть, щоб усе одно підключитися"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Пристрій перейшов на мережу <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Коли мережа <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> не має доступу до Інтернету, використовується <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Може стягуватися плата."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Пристрій перейшов з мережі <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на мережу <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"мобільний Інтернет"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"невідомий тип мережі"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ur/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-ur/strings.xml
deleted file mode 100644
index bd2a228..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-ur/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"سسٹم کنیکٹوٹی کے وسائل"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Wi-Fi نیٹ ورک میں سائن ان کریں"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"نیٹ ورک میں سائن ان کریں"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> کو انٹرنیٹ تک رسائی حاصل نہیں ہے"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"اختیارات کیلئے تھپتھپائیں"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"موبائل نیٹ ورک کو انٹرنیٹ تک رسائی حاصل نہیں ہے"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"نیٹ ورک کو انٹرنیٹ تک رسائی حاصل نہیں ہے"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"نجی DNS سرور تک رسائی حاصل نہیں کی جا سکی"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> کی کنیکٹوٹی محدود ہے"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"بہر حال منسلک کرنے کے لیے تھپتھپائیں"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> پر سوئچ ہو گیا"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"جب <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> کو انٹرنیٹ تک رسائی نہیں ہوتی ہے تو آلہ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> کا استعمال کرتا ہے۔ چارجز لاگو ہو سکتے ہیں۔"</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> سے <xliff:g id="NEW_NETWORK">%2$s</xliff:g> پر سوئچ ہو گیا"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"موبائل ڈیٹا"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"بلوٹوتھ"</item>
- <item msgid="1160736166977503463">"ایتھرنیٹ"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"نامعلوم نیٹ ورک کی قسم"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-uz/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-uz/strings.xml
deleted file mode 100644
index 567aa88..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-uz/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Tizim aloqa resurslari"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Wi-Fi tarmoqqa kirish"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Tarmoqqa kirish"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nomli tarmoqda internetga ruxsati yoʻq"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Variantlarni ko‘rsatish uchun bosing"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mobil tarmoq internetga ulanmagan"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Tarmoq internetga ulanmagan"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Xususiy DNS server ishlamayapti"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nomli tarmoqda aloqa cheklangan"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Baribir ulash uchun bosing"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Yangi ulanish: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Agar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tarmoqda internet uzilsa, qurilma <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ga ulanadi. Sarflangan trafik uchun haq olinishi mumkin."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> tarmog‘idan <xliff:g id="NEW_NETWORK">%2$s</xliff:g> tarmog‘iga o‘tildi"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"mobil internet"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"nomaʼlum tarmoq turi"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-vi/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-vi/strings.xml
deleted file mode 100644
index 590b388..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-vi/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Tài nguyên kết nối hệ thống"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Đăng nhập vào mạng Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Đăng nhập vào mạng"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> không có quyền truy cập Internet"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Nhấn để biết tùy chọn"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Mạng di động không có quyền truy cập Internet"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Mạng không có quyền truy cập Internet"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Không thể truy cập máy chủ DNS riêng tư"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> có khả năng kết nối giới hạn"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Nhấn để tiếp tục kết nối"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Đã chuyển sang <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Thiết bị sử dụng <xliff:g id="NEW_NETWORK">%1$s</xliff:g> khi <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> không có quyền truy cập Internet. Bạn có thể phải trả phí."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Đã chuyển từ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> sang <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"dữ liệu di động"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"Bluetooth"</item>
- <item msgid="1160736166977503463">"Ethernet"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"loại mạng không xác định"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rCN/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rCN/strings.xml
deleted file mode 100644
index 9d6cff9..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"系统网络连接资源"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"登录到WLAN网络"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"登录到网络"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 无法访问互联网"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"点按即可查看相关选项"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"此移动网络无法访问互联网"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"此网络无法访问互联网"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"无法访问私人 DNS 服务器"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 的连接受限"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"点按即可继续连接"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"已切换至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"设备会在<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>无法访问互联网时使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g>(可能需要支付相应的费用)。"</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"已从<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切换至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"移动数据"</item>
- <item msgid="6341719431034774569">"WLAN"</item>
- <item msgid="5081440868800877512">"蓝牙"</item>
- <item msgid="1160736166977503463">"以太网"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"未知网络类型"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rHK/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rHK/strings.xml
deleted file mode 100644
index c84241c..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rHK/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"系統連線資源"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"登入 Wi-Fi 網絡"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"登入網絡"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>未有連接至互聯網"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"輕按即可查看選項"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"流動網絡並未連接互聯網"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"網絡並未連接互聯網"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"無法存取私人 DNS 伺服器"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>連線受限"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"仍要輕按以連結至此網絡"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"裝置會在 <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> 無法連線至互聯網時使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g> (可能需要支付相關費用)。"</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"已從<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"流動數據"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"藍牙"</item>
- <item msgid="1160736166977503463">"以太網絡"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"不明網絡類型"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rTW/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rTW/strings.xml
deleted file mode 100644
index 07540d1..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"系統連線資源"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"登入 Wi-Fi 網路"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"登入網路"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 沒有網際網路連線"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"輕觸即可查看選項"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"這個行動網路沒有網際網路連線"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"這個網路沒有網際網路連線"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"無法存取私人 DNS 伺服器"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 的連線能力受限"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"輕觸即可繼續連線"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"裝置會在無法連上「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」時切換至「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」(可能需要支付相關費用)。"</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"已從 <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> 切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"行動數據"</item>
- <item msgid="6341719431034774569">"Wi-Fi"</item>
- <item msgid="5081440868800877512">"藍牙"</item>
- <item msgid="1160736166977503463">"乙太網路"</item>
- <item msgid="7347618872551558605">"VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"不明的網路類型"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-zu/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-zu/strings.xml
deleted file mode 100644
index 19f390b..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values-zu/strings.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="connectivityResourcesAppLabel" msgid="8294935652079168395">"Izinsiza Zokuxhumeka Zesistimu"</string>
- <string name="wifi_available_sign_in" msgid="5254156478006453593">"Ngena ngemvume kunethiwekhi ye-Wi-Fi"</string>
- <string name="network_available_sign_in" msgid="7794369329839408792">"Ngena ngemvume kunethiwekhi"</string>
- <!-- no translation found for network_available_sign_in_detailed (3643910593681893097) -->
- <skip />
- <string name="wifi_no_internet" msgid="3961697321010262514">"I-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ayinakho ukufinyelela kwe-inthanethi"</string>
- <string name="wifi_no_internet_detailed" msgid="1229067002306296104">"Thepha ukuze uthole izinketho"</string>
- <string name="mobile_no_internet" msgid="2262524005014119639">"Inethiwekhi yeselula ayinakho ukufinyelela kwe-inthanethi"</string>
- <string name="other_networks_no_internet" msgid="8226004998719563755">"Inethiwekhi ayinakho ukufinyelela kwenethiwekhi"</string>
- <string name="private_dns_broken_detailed" msgid="3537567373166991809">"Iseva eyimfihlo ye-DNS ayikwazi ukufinyelelwa"</string>
- <string name="network_partial_connectivity" msgid="5957065286265771273">"I-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> inokuxhumeka okukhawulelwe"</string>
- <string name="network_partial_connectivity_detailed" msgid="6975752539442533034">"Thepha ukuze uxhume noma kunjalo"</string>
- <string name="network_switch_metered" msgid="2814798852883117872">"Kushintshelwe ku-<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
- <string name="network_switch_metered_detail" msgid="605546931076348229">"Idivayisi isebenzisa i-<xliff:g id="NEW_NETWORK">%1$s</xliff:g> uma i-<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> inganakho ukufinyelela kwe-inthanethi. Kungasebenza izindleko."</string>
- <string name="network_switch_metered_toast" msgid="8831325515040986641">"Kushintshelewe kusuka ku-<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kuya ku-<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
- <string-array name="network_switch_type_name">
- <item msgid="5454013645032700715">"idatha yeselula"</item>
- <item msgid="6341719431034774569">"I-Wi-Fi"</item>
- <item msgid="5081440868800877512">"I-Bluetooth"</item>
- <item msgid="1160736166977503463">"I-Ethernet"</item>
- <item msgid="7347618872551558605">"I-VPN"</item>
- </string-array>
- <string name="network_switch_type_name_unknown" msgid="7826330274368951740">"uhlobo olungaziwa lwenethiwekhi"</string>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml
deleted file mode 100644
index 70ddb9a..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml
+++ /dev/null
@@ -1,114 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<!-- Configuration values for ConnectivityService
- DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources
- Overlay package following the overlayable.xml configuration in the same directory:
- https://source.android.com/devices/architecture/rros -->
-<resources>
-
- <!-- Configuration hook for the URL returned by ConnectivityManager#getCaptivePortalServerUrl.
- If empty, the returned value is controlled by Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
- and if that value is empty, the framework will use a hard-coded default.
- This is *NOT* a URL that will always be used by the system network validation to detect
- captive portals: NetworkMonitor may use different strategies and will not necessarily use
- this URL. NetworkMonitor behaviour should be configured with NetworkStack resource overlays
- instead. -->
- <!--suppress CheckTagEmptyBody -->
- <string translatable="false" name="config_networkCaptivePortalServerUrl"></string>
-
- <!-- The maximum duration (in milliseconds) we expect a network transition to take -->
- <integer name="config_networkTransitionTimeout">60000</integer>
-
- <!-- Configuration of network interfaces that support WakeOnLAN -->
- <string-array translatable="false" name="config_wakeonlan_supported_interfaces">
- <!--
- <item>wlan0</item>
- <item>eth0</item>
- -->
- </string-array>
-
- <string-array translatable="false" name="config_legacy_networktype_restore_timers">
- <item>2,60000</item><!-- mobile_mms -->
- <item>3,60000</item><!-- mobile_supl -->
- <item>4,60000</item><!-- mobile_dun -->
- <item>5,60000</item><!-- mobile_hipri -->
- <item>10,60000</item><!-- mobile_fota -->
- <item>11,60000</item><!-- mobile_ims -->
- <item>12,60000</item><!-- mobile_cbs -->
- </string-array>
-
- <!-- Default supported concurrent socket keepalive slots per transport type, used by
- ConnectivityManager.createSocketKeepalive() for calculating the number of keepalive
- offload slots that should be reserved for privileged access. This string array should be
- overridden by the device to present the capability of creating socket keepalives. -->
- <!-- An Array of "[NetworkCapabilities.TRANSPORT_*],[supported keepalives] -->
- <string-array translatable="false" name="config_networkSupportedKeepaliveCount">
- <item>0,1</item>
- <item>1,3</item>
- </string-array>
-
- <!-- Reserved privileged keepalive slots per transport. -->
- <integer translatable="false" name="config_reservedPrivilegedKeepaliveSlots">2</integer>
-
- <!-- Allowed unprivileged keepalive slots per uid. -->
- <integer translatable="false" name="config_allowedUnprivilegedKeepalivePerUid">2</integer>
-
- <!-- Default value for ConnectivityManager.getMultipathPreference() on metered networks. Actual
- device behaviour is controlled by the metered multipath preference in
- ConnectivitySettingsManager. This is the default value of that setting. -->
- <integer translatable="false" name="config_networkMeteredMultipathPreference">0</integer>
-
- <!-- Whether the device should automatically switch away from Wi-Fi networks that lose
- Internet access. Actual device behaviour is controlled by
- Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
- <integer translatable="false" name="config_networkAvoidBadWifi">1</integer>
-
- <!-- Array of ConnectivityManager.TYPE_xxxx constants for networks that may only
- be controlled by systemOrSignature apps. -->
- <integer-array translatable="false" name="config_protectedNetworks">
- <item>10</item>
- <item>11</item>
- <item>12</item>
- <item>14</item>
- <item>15</item>
- </integer-array>
-
- <!-- Whether the internal vehicle network should remain active even when no
- apps requested it. -->
- <bool name="config_vehicleInternalNetworkAlwaysRequested">false</bool>
-
-
- <!-- If the hardware supports specially marking packets that caused a wakeup of the
- main CPU, set this value to the mark used. -->
- <integer name="config_networkWakeupPacketMark">0</integer>
-
- <!-- Mask to use when checking skb mark defined in config_networkWakeupPacketMark above. -->
- <integer name="config_networkWakeupPacketMask">0</integer>
-
- <!-- Whether/how to notify the user on network switches. See LingerMonitor.java. -->
- <integer translatable="false" name="config_networkNotifySwitchType">0</integer>
-
- <!-- What types of network switches to notify. See LingerMonitor.java. -->
- <string-array translatable="false" name="config_networkNotifySwitches">
- </string-array>
-
- <!-- Whether to use an ongoing notification for signing in to captive portals, instead of a
- notification that can be dismissed. -->
- <bool name="config_ongoingSignInNotification">false</bool>
-
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml
deleted file mode 100644
index fd23566..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!-- Copyright (C) 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <overlayable name="ServiceConnectivityResourcesConfig">
- <policy type="product|system|vendor">
- <!-- Configuration values for ConnectivityService -->
- <item type="array" name="config_legacy_networktype_restore_timers"/>
- <item type="string" name="config_networkCaptivePortalServerUrl"/>
- <item type="integer" name="config_networkTransitionTimeout"/>
- <item type="array" name="config_wakeonlan_supported_interfaces"/>
- <item type="integer" name="config_networkMeteredMultipathPreference"/>
- <item type="array" name="config_networkSupportedKeepaliveCount"/>
- <item type="integer" name="config_networkAvoidBadWifi"/>
- <item type="array" name="config_protectedNetworks"/>
- <item type="bool" name="config_vehicleInternalNetworkAlwaysRequested"/>
- <item type="integer" name="config_networkWakeupPacketMark"/>
- <item type="integer" name="config_networkWakeupPacketMask"/>
- <item type="integer" name="config_networkNotifySwitchType"/>
- <item type="array" name="config_networkNotifySwitches"/>
- <item type="bool" name="config_ongoingSignInNotification"/>
-
- </policy>
- </overlayable>
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml
deleted file mode 100644
index b2fa5f5..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- The System Connectivity Resources package is an internal system package that provides
- configuration values for system networking that were pre-configured in the device. This
- is the name of the package to display in the list of system apps. [CHAR LIMIT=40] -->
- <string name="connectivityResourcesAppLabel">System Connectivity Resources</string>
-
- <!-- A notification is shown when a wifi captive portal network is detected. This is the notification's title. -->
- <string name="wifi_available_sign_in">Sign in to Wi-Fi network</string>
-
- <!-- A notification is shown when a captive portal network is detected. This is the notification's title. -->
- <string name="network_available_sign_in">Sign in to network</string>
-
- <!-- A notification is shown when a captive portal network is detected. This is the notification's message. -->
- <string name="network_available_sign_in_detailed"><xliff:g id="network_ssid">%1$s</xliff:g></string>
-
- <!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's title. -->
- <string name="wifi_no_internet"><xliff:g id="network_ssid" example="GoogleGuest">%1$s</xliff:g> has no internet access</string>
-
- <!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's message. -->
- <string name="wifi_no_internet_detailed">Tap for options</string>
-
- <!-- A notification is shown when the user connects to a mobile network without internet access. This is the notification's title. -->
- <string name="mobile_no_internet">Mobile network has no internet access</string>
-
- <!-- A notification is shown when the user connects to a non-mobile and non-wifi network without internet access. This is the notification's title. -->
- <string name="other_networks_no_internet">Network has no internet access</string>
-
- <!-- A notification is shown when connected network without internet due to private dns validation failed. This is the notification's message. [CHAR LIMIT=NONE] -->
- <string name="private_dns_broken_detailed">Private DNS server cannot be accessed</string>
-
- <!-- A notification is shown when the user connects to a network that doesn't have access to some services (e.g. Push notifications may not work). This is the notification's title. [CHAR LIMIT=50] -->
- <string name="network_partial_connectivity"><xliff:g id="network_ssid" example="GoogleGuest">%1$s</xliff:g> has limited connectivity</string>
-
- <!-- A notification is shown when the user connects to a network that doesn't have access to some services (e.g. Push notifications may not work). This is the notification's message. [CHAR LIMIT=50] -->
- <string name="network_partial_connectivity_detailed">Tap to connect anyway</string>
-
- <!-- A notification might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's title. %1$s is the network type that the device switched to, e.g., cellular data. It is one of the strings in the network_switch_type_name array. -->
- <string name="network_switch_metered">Switched to <xliff:g id="network_type">%1$s</xliff:g></string>
-
- <!-- A notification might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the notification's message. %1$s is the network that the device switched to, e.g., cellular data. %2$s is the network type the device switched from, e.g., Wi-Fi. Both are strings in the network_switch_type_name array. -->
- <string name="network_switch_metered_detail">Device uses <xliff:g id="new_network">%1$s</xliff:g> when <xliff:g id="previous_network">%2$s</xliff:g> has no internet access. Charges may apply.</string>
-
- <!-- A toast might be shown if the device switches to another network type (e.g., mobile data) because it detects that the network it was using (e.g., Wi-Fi) has lost Internet connectivity. This is the text of the toast. %1$s is the network that the device switched from, e.g., Wi-Fi. %2$s is the network type the device switched from, e.g., cellular data. Both are strings in the network_switch_type_name array. -->
- <string name="network_switch_metered_toast">Switched from <xliff:g id="previous_network">%1$s</xliff:g> to <xliff:g id="new_network">%2$s</xliff:g></string>
-
- <!-- Network type names used in the network_switch_metered and network_switch_metered_detail strings. These must be kept in the sync with the values NetworkCapabilities.TRANSPORT_xxx values, and in the same order. -->
- <string-array name="network_switch_type_name">
- <item>mobile data</item>
- <item>Wi-Fi</item>
- <item>Bluetooth</item>
- <item>Ethernet</item>
- <item>VPN</item>
- </string-array>
-
- <!-- Network type name displayed if one of the types is not found in network_switch_type_name. -->
- <string name="network_switch_type_name_unknown">an unknown network type</string>
-
-</resources>
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/resources-certs/com.android.connectivity.resources.pk8 b/packages/Connectivity/service/ServiceConnectivityResources/resources-certs/com.android.connectivity.resources.pk8
deleted file mode 100644
index bfdc28b..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/resources-certs/com.android.connectivity.resources.pk8
+++ /dev/null
Binary files differ
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/resources-certs/com.android.connectivity.resources.x509.pem b/packages/Connectivity/service/ServiceConnectivityResources/resources-certs/com.android.connectivity.resources.x509.pem
deleted file mode 100644
index 70eca1c..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/resources-certs/com.android.connectivity.resources.x509.pem
+++ /dev/null
@@ -1,36 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIGQzCCBCugAwIBAgIUZY8nxBMINp/79sziXU77MLPpEXowDQYJKoZIhvcNAQEL
-BQAwga8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
-DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
-b2lkMSswKQYDVQQDDCJjb20uYW5kcm9pZC5jb25uZWN0aXZpdHkucmVzb3VyY2Vz
-MSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMCAXDTIxMDQyMjA3
-MjkxMFoYDzQ3NTkwMzE5MDcyOTEwWjCBrzELMAkGA1UEBhMCVVMxEzARBgNVBAgM
-CkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB0Fu
-ZHJvaWQxEDAOBgNVBAsMB0FuZHJvaWQxKzApBgNVBAMMImNvbS5hbmRyb2lkLmNv
-bm5lY3Rpdml0eS5yZXNvdXJjZXMxIjAgBgkqhkiG9w0BCQEWE2FuZHJvaWRAYW5k
-cm9pZC5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC361NT9qSz
-h3uLcLBD67HNE1QX3ykwGyw8u7ExzqpsqLCzZsOCFRJQJY+CnrgNaAz0NXeNtx7D
-Lpr9OCWWbG1KTQ/ANlR8g6xCqlAk4xdixsAnIlBUJB90+RlkcWrliEY7OwcqIu3x
-/qe+5UR3irIFZOApNHOm760PjRl7VWAnYZC/PhkW0iKwnBuE96ddPIJc+KuiqCcP
-KflgF4/jmbHTZ+5uvVV4qkfovc744HnQtQoCDoYR8WpsJv3YL5xrAv78o3WCRzx6
-xxB+eUlJpuyyfIee2lUCG4Ly4jgOsWaupnUglLDORnz/L8fhhnpv83wLal7E0Shx
-sqvzZZbb1QLuwMWy++gfzdDvGWewES3BdSFp5NwYWXQGZWSkEEFbIiorKSurU1On
-9OwB0jT/H2B/CAFKYJQ2V+hQ4I7PG+z9p7ZFNR6GZbZuhEr+Dpq1CwtI3W45izr3
-RJgcc2IP6Oj7/XC2MmKGMqZkybBWcvazdyAMHzk9EZIBT2Oru3dnOl3uVUUPeZRs
-xRzqaA0MAlyj+GJ9uziEr3W1j+U1CFEnNWtlD/jqcTAwmaOsn1GhWyMAo1KOrJ/o
-LcJvwk5P/0XEyeli7/DSUpGjYiAgWMHWCOn9s6aYw3YFb+A/SgX3/+FIDib/vHTX
-i76JZfO0CfoKsbFDCH9KOMupHM9EO3ftQwIDAQABo1MwUTAdBgNVHQ4EFgQU/KGg
-gmMqXD5YOe5+B0W+YezN9LcwHwYDVR0jBBgwFoAU/KGggmMqXD5YOe5+B0W+YezN
-9LcwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAhr+AaNaIlRyM
-WKyJ+2Aa35fH5e44Xr/xPpriM5HHxsj0evjMCODqCQ7kzfwSEmtXh5uZYYNKb/JP
-ZMDHIFcYi1QCvm6E6YOd+Qn9CVxrwaDhigJv7ylhVf8q201GTvHhJIU99yFIrzJQ
-RNhxw+pNo7FYMZr3J7JZPAy60DN1KZvRV4FjZx5qiPUMyu4zVygzDkr0v5Ilncdp
-l9VVjOi7ocHyBKI+7RkXl97xN4SUe3vszwZQHCVyVopBw+YrMbDBCrknrQzUEgie
-BuI+kj5oOeiQ0P1i1K+UCCAjrLwhNyc9H02rKUtBHxa2AVjw7YpAJlBesb49Qvq+
-5L6JjHFVSSOEbIjboNib26zNackjbiefF74meSUbGVGfcJ1OdkZsXZWphmER8V7X
-Wz3Z8JwOXW1RLPgcbjilHUR5g8pEmWBv4KrTCSg5IvOJr4w3pyyMBiiVI9NI5sB7
-g5Mi9v3ifPD1OHA4Y3wYCb26mMEpRb8ogOhMHcGNbdnL3QtIUg4cmXGqGSY/LbpU
-np0sIQDSjc46o79F0boPsLlaN3US5WZIu0nc9SHkjoNhd0CJQ5r9aEn4/wNrZgxs
-s8OEKsqcS7OsWiIE6nG51TMDsCuyRBrGedtSUyFFSVSpivpYIrPVNKKlHsJ/o+Nv
-Udb6dBjCraPvJB8binB1aojwya3MwRs=
------END CERTIFICATE-----
diff --git a/packages/Connectivity/service/ServiceConnectivityResources/resources-certs/key.pem b/packages/Connectivity/service/ServiceConnectivityResources/resources-certs/key.pem
deleted file mode 100644
index 38771c2..0000000
--- a/packages/Connectivity/service/ServiceConnectivityResources/resources-certs/key.pem
+++ /dev/null
@@ -1,52 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC361NT9qSzh3uL
-cLBD67HNE1QX3ykwGyw8u7ExzqpsqLCzZsOCFRJQJY+CnrgNaAz0NXeNtx7DLpr9
-OCWWbG1KTQ/ANlR8g6xCqlAk4xdixsAnIlBUJB90+RlkcWrliEY7OwcqIu3x/qe+
-5UR3irIFZOApNHOm760PjRl7VWAnYZC/PhkW0iKwnBuE96ddPIJc+KuiqCcPKflg
-F4/jmbHTZ+5uvVV4qkfovc744HnQtQoCDoYR8WpsJv3YL5xrAv78o3WCRzx6xxB+
-eUlJpuyyfIee2lUCG4Ly4jgOsWaupnUglLDORnz/L8fhhnpv83wLal7E0Shxsqvz
-ZZbb1QLuwMWy++gfzdDvGWewES3BdSFp5NwYWXQGZWSkEEFbIiorKSurU1On9OwB
-0jT/H2B/CAFKYJQ2V+hQ4I7PG+z9p7ZFNR6GZbZuhEr+Dpq1CwtI3W45izr3RJgc
-c2IP6Oj7/XC2MmKGMqZkybBWcvazdyAMHzk9EZIBT2Oru3dnOl3uVUUPeZRsxRzq
-aA0MAlyj+GJ9uziEr3W1j+U1CFEnNWtlD/jqcTAwmaOsn1GhWyMAo1KOrJ/oLcJv
-wk5P/0XEyeli7/DSUpGjYiAgWMHWCOn9s6aYw3YFb+A/SgX3/+FIDib/vHTXi76J
-ZfO0CfoKsbFDCH9KOMupHM9EO3ftQwIDAQABAoICAQCXM/GKqtAXBIBOT/Ops0C2
-n3hYM9BRy1UgDRKNJyG3OSwkIY0ECbzHhUmpkkEwTGWx8675JB43Sr6DBUDpnPRw
-zE/xrvjgcQQSvqAq40PbohhhU/WEZzoxWYVFrXS7hcBve4TVYGgMtlZEO4qBWNYo
-Vxlu5r9Z89tsWI0ldzgYyD5O64eG2nVIit6Y/11p6pAmTQ4WKHYMIm7xUA2siTPH
-4L8F7cQx8pQxxLI+q5WaPuweasBQShA7IAc7T1EiLRFitCOsWlJfgf6Oa7oTwhcA
-Wh7JOyf+Fo4ejlqVwcTwOss6YOPGge7LgQWr5HoORbeqTuXgmy/L4Z85+EABNOs1
-5muHZvsuPXSmW6g1bCi8zvQcjFIX31yBVg8zkdG8WRezFxiVlN8UFAx4rwo03aBs
-rDyU4GCxoUBvF/M9534l1gKOyr0hlQ40nQ4kBabbm2wWOKCVzmLEtFmWX9RV0tjX
-pEtTCqgsGlsIypLy21+uow8SBojhkZ+xORCF2XivGu6SKtvwGvjpYXpXrI6DN4Lw
-kH5J5FwSu1SNY8tnIEJEmj8IMTp+Vw20kwNVTcwdC2nJDDiezJum4PqZRdWIuupm
-BWzXD3fvMXqHmT02sJTQ+FRAgiQLLWDzNAYMJUofzuIwycs4iO9MOPHjkHScvk4N
-FXLrzFBSbdw+wi1DdzzMuQKCAQEA5wx07O5bHBHybs6tpwuZ0TuJ3OIVXh/ocNVR
-gSOCSMirv+K4u3jToXwjfTXUc9lcn+DenZPpGmUWF0sZ83ytZm1eFVgGZpP6941C
-waSeb8zGsgbEyZIQTVILfgtyPDwdtgu0d1Ip+ppj9czXmnxMY/ruHOX1Do1UfZoA
-UA1ytHJSjFKU6saAhHrdk91soTVzc/E3uo7U4Ff0L8/3tT3DAEFYxDXUCH8W2IZZ
-6zVvlqnPH4elxsPYM6rtIwq52reOTLNxC+SFSamK/82zu09Kjj5sQ6HKlvKJFiL5
-bULWu4lenoDfEN0lng+QopJTgZq4/tgOLum43C/Zd0PGC9R6PwKCAQEAy8fvPqwM
-gPbNasni9qGVG+FfiFd/wEMlgKlVVqi+WzF6tCAnXCQXXg3A7FpLQrX8hVKdMznq
-wPgM5AXP4FOguBFNk65chZmPizBIUDPJ4TNHI8FcGgcxbKGvDdVHsUpa/h5rJlvV
-GLJTKV4KjcsTjl5tlRsJ48bSfpBNQHpSKlCswT6jjteiDY6Rln0GFKQIKDHqp3I6
-Zn1E4yfdiIz9VnMPfg1fbjBeR7s1zNzlrR8Dv9oK9tkzI5G1wSbdzksg2O1q2tvg
-WrZrTAA3Uw6sPUMft0vk5Jw6a6CLkrcfayv3xDHwvM/4P3HgP8j9WQ8at8ttHpfD
-oWyt3fZ3pBuj/QKCAQANqxH7tjoTlgg2f+mL+Ua3NwN32rQS5mZUznnM3vHlJmHq
-rxnolURHyFU9IgMYe2JcXuwsfESM+C/vXtUBL33+kje/oX53cQemv2eUlw18ZavX
-ekkH96kZOeJOKZUvdQr46wZZDLZJCfsh3mVe0T2fqIePlBcELl4yM/sSwUjo3d5+
-SKBgpy+RJseW6MF1Y/kZgcqfMbXsM6fRcEciJK41hKggq2KIwiPy2TfWj0mzqwYC
-wn6PHKTcoZ73tLm786Hqba8hWfp8mhgL+/pG+XDaq1yyP48BkQWFFrqUuSCE5aKA
-U/VeRQblq9wNkgR4pVOOV++23MK/2+DMimjb6Ez3AoIBABIXK7wKlgmU32ONjKKM
-capJ9asq6WJuE5Q6dCL/U/bQi64V9KiPY6ur2OailW/UrBhB30a+64I6AxrzESM/
-CVON5a8omXoayc13edP05QUjAjvAXKbK4K5eJCY8OuMYUL+if6ymFmLc4dkYSiOQ
-Vaob4+qKvfQEoIcv1EvXEBhFlTCKmQaDShWeBHqxmqqWbUr0M3qt/1U95bGsxlPr
-AEp+aG+uTDyB+ryvd/U53wHhcPnFJ5gGbC3KL7J3+tTngoD/gq7vOhmTfC8BDehH
-sy61GMmy6R0KaX1IgVuC+j0PaC14qYB5jfZD675930/asWqDmqpOmsVn2n+L888T
-zRkCggEBAIMuNhhfGGY6E4PLUcPM0LZA4tI/wTpeYEahunU1hWIYo/iZB9od2biz
-EeYY4BtkzCoE5ZWYXqTgiMxN4hJ4ufB+5umZ4BO0Gyx4p2/Ik2uv1BXu++GbM+TI
-eeFmaBh00dTtjccpeZEDgNkjAO7Rh9GV2ifl3uhqg0MnFXywPUX2Vm2bmwQXnfV9
-wY2TXgOmBN2epFBOArJwiA5IfV+bSqXCFCx8fgyOWpMNq9+zDRd6KCeHyge54ahm
-jMhCncp1OPDPaV+gnUdgWDGcywYg0KQvu5dLuCFfvucnsWoH2txsVZrXFha5XSM4
-/4Pif3Aj5E9dm1zkUtZJYQbII5SKQ94=
------END PRIVATE KEY-----
diff --git a/packages/Connectivity/service/jarjar-rules.txt b/packages/Connectivity/service/jarjar-rules.txt
deleted file mode 100644
index 5caa11b..0000000
--- a/packages/Connectivity/service/jarjar-rules.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-rule android.sysprop.** com.android.connectivity.sysprop.@1
-rule com.android.net.module.util.** com.android.connectivity.net-utils.@1
-rule com.android.modules.utils.** com.android.connectivity.modules-utils.@1
-
-# internal util classes
-# Exclude AsyncChannel. TODO: remove AsyncChannel usage in ConnectivityService
-rule com.android.internal.util.AsyncChannel* @0
-# Exclude LocationPermissionChecker. This is going to be moved to libs/net
-rule com.android.internal.util.LocationPermissionChecker* @0
-rule android.util.LocalLog* com.android.connectivity.util.LocalLog@1
-# android.util.IndentingPrintWriter* should use a different package name from
-# the one in com.android.internal.util
-rule android.util.IndentingPrintWriter* android.connectivity.util.IndentingPrintWriter@1
-rule com.android.internal.util.** com.android.connectivity.util.@1
-
-rule com.android.internal.messages.** com.android.connectivity.messages.@1
-rule com.google.protobuf.** com.android.connectivity.protobuf.@1
diff --git a/packages/Connectivity/service/jni/com_android_server_TestNetworkService.cpp b/packages/Connectivity/service/jni/com_android_server_TestNetworkService.cpp
deleted file mode 100644
index e7a40e5..0000000
--- a/packages/Connectivity/service/jni/com_android_server_TestNetworkService.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2018 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 "TestNetworkServiceJni"
-
-#include <arpa/inet.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/if.h>
-#include <linux/if_tun.h>
-#include <linux/ipv6_route.h>
-#include <linux/route.h>
-#include <netinet/in.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <log/log.h>
-
-#include "jni.h"
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedUtfChars.h>
-
-namespace android {
-
-//------------------------------------------------------------------------------
-
-static void throwException(JNIEnv* env, int error, const char* action, const char* iface) {
- const std::string& msg = "Error: " + std::string(action) + " " + std::string(iface) + ": "
- + std::string(strerror(error));
- jniThrowException(env, "java/lang/IllegalStateException", msg.c_str());
-}
-
-static int createTunTapInterface(JNIEnv* env, bool isTun, const char* iface) {
- base::unique_fd tun(open("/dev/tun", O_RDWR | O_NONBLOCK));
- ifreq ifr{};
-
- // Allocate interface.
- ifr.ifr_flags = (isTun ? IFF_TUN : IFF_TAP) | IFF_NO_PI;
- strlcpy(ifr.ifr_name, iface, IFNAMSIZ);
- if (ioctl(tun.get(), TUNSETIFF, &ifr)) {
- throwException(env, errno, "allocating", ifr.ifr_name);
- return -1;
- }
-
- // Activate interface using an unconnected datagram socket.
- base::unique_fd inet6CtrlSock(socket(AF_INET6, SOCK_DGRAM, 0));
- ifr.ifr_flags = IFF_UP;
-
- if (ioctl(inet6CtrlSock.get(), SIOCSIFFLAGS, &ifr)) {
- throwException(env, errno, "activating", ifr.ifr_name);
- return -1;
- }
-
- return tun.release();
-}
-
-//------------------------------------------------------------------------------
-
-static jint create(JNIEnv* env, jobject /* thiz */, jboolean isTun, jstring jIface) {
- ScopedUtfChars iface(env, jIface);
- if (!iface.c_str()) {
- jniThrowNullPointerException(env, "iface");
- return -1;
- }
-
- int tun = createTunTapInterface(env, isTun, iface.c_str());
-
- // Any exceptions will be thrown from the createTunTapInterface call
- return tun;
-}
-
-//------------------------------------------------------------------------------
-
-static const JNINativeMethod gMethods[] = {
- {"jniCreateTunTap", "(ZLjava/lang/String;)I", (void*)create},
-};
-
-int register_android_server_TestNetworkService(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "com/android/server/TestNetworkService", gMethods,
- NELEM(gMethods));
-}
-
-}; // namespace android
diff --git a/packages/Connectivity/service/jni/onload.cpp b/packages/Connectivity/service/jni/onload.cpp
deleted file mode 100644
index 0012879..0000000
--- a/packages/Connectivity/service/jni/onload.cpp
+++ /dev/null
@@ -1,38 +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.
- */
-
-#include <nativehelper/JNIHelp.h>
-#include <log/log.h>
-
-namespace android {
-
-int register_android_server_TestNetworkService(JNIEnv* env);
-
-extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
- JNIEnv *env;
- if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
- ALOGE("GetEnv failed");
- return JNI_ERR;
- }
-
- if (register_android_server_TestNetworkService(env) < 0) {
- return JNI_ERR;
- }
-
- return JNI_VERSION_1_6;
-}
-
-};
diff --git a/packages/Connectivity/service/lint-baseline.xml b/packages/Connectivity/service/lint-baseline.xml
deleted file mode 100644
index 95c169c..0000000
--- a/packages/Connectivity/service/lint-baseline.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#isDataCapable`"
- errorLine1=" if (tm.isDataCapable()) {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/Connectivity/service/src/com/android/server/ConnectivityService.java"
- line="787"
- column="20"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.content.Context#sendStickyBroadcast`"
- errorLine1=" mUserAllContext.sendStickyBroadcast(intent, options);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/Connectivity/service/src/com/android/server/ConnectivityService.java"
- line="2681"
- column="33"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.content.pm.PackageManager#getTargetSdkVersion`"
- errorLine1=" final int callingVersion = pm.getTargetSdkVersion(callingPackageName);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/Connectivity/service/src/com/android/server/ConnectivityService.java"
- line="5851"
- column="43"/>
- </issue>
-
-</issues>
diff --git a/packages/Connectivity/service/src/com/android/server/ConnectivityService.java b/packages/Connectivity/service/src/com/android/server/ConnectivityService.java
deleted file mode 100644
index 6027a99..0000000
--- a/packages/Connectivity/service/src/com/android/server/ConnectivityService.java
+++ /dev/null
@@ -1,10060 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.server;
-
-import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
-import static android.content.pm.PackageManager.FEATURE_BLUETOOTH;
-import static android.content.pm.PackageManager.FEATURE_WATCH;
-import static android.content.pm.PackageManager.FEATURE_WIFI;
-import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK;
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_VALIDATION_RESULT;
-import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_DNS_EVENTS;
-import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_TCP_METRICS;
-import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS;
-import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS;
-import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE;
-import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
-import static android.net.ConnectivityManager.BLOCKED_REASON_LOCKDOWN_VPN;
-import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
-import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
-import static android.net.ConnectivityManager.TYPE_ETHERNET;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_MOBILE_CBS;
-import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
-import static android.net.ConnectivityManager.TYPE_MOBILE_EMERGENCY;
-import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
-import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
-import static android.net.ConnectivityManager.TYPE_MOBILE_IA;
-import static android.net.ConnectivityManager.TYPE_MOBILE_IMS;
-import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
-import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
-import static android.net.ConnectivityManager.TYPE_NONE;
-import static android.net.ConnectivityManager.TYPE_PROXY;
-import static android.net.ConnectivityManager.TYPE_VPN;
-import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
-import static android.net.ConnectivityManager.getNetworkTypeName;
-import static android.net.ConnectivityManager.isNetworkTypeValid;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
-import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
-import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
-import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_TEST;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST;
-import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired;
-import static android.os.Process.INVALID_UID;
-import static android.os.Process.VPN_UID;
-import static android.system.OsConstants.IPPROTO_TCP;
-import static android.system.OsConstants.IPPROTO_UDP;
-
-import static java.util.Map.Entry;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.AppOpsManager;
-import android.app.BroadcastOptions;
-import android.app.PendingIntent;
-import android.app.usage.NetworkStatsManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.database.ContentObserver;
-import android.net.CaptivePortal;
-import android.net.CaptivePortalData;
-import android.net.ConnectionInfo;
-import android.net.ConnectivityAnnotations.RestrictBackgroundStatus;
-import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
-import android.net.ConnectivityDiagnosticsManager.DataStallReport;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.BlockedReason;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.ConnectivityResources;
-import android.net.ConnectivitySettingsManager;
-import android.net.DataStallReportParcelable;
-import android.net.DnsResolverServiceManager;
-import android.net.ICaptivePortal;
-import android.net.IConnectivityDiagnosticsCallback;
-import android.net.IConnectivityManager;
-import android.net.IDnsResolver;
-import android.net.INetd;
-import android.net.INetworkActivityListener;
-import android.net.INetworkAgent;
-import android.net.INetworkMonitor;
-import android.net.INetworkMonitorCallbacks;
-import android.net.INetworkOfferCallback;
-import android.net.IOnCompleteListener;
-import android.net.IQosCallback;
-import android.net.ISocketKeepaliveCallback;
-import android.net.InetAddresses;
-import android.net.IpMemoryStore;
-import android.net.IpPrefix;
-import android.net.LinkProperties;
-import android.net.MatchAllNetworkSpecifier;
-import android.net.NativeNetworkConfig;
-import android.net.NativeNetworkType;
-import android.net.NattSocketKeepalive;
-import android.net.Network;
-import android.net.NetworkAgent;
-import android.net.NetworkAgentConfig;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkMonitorManager;
-import android.net.NetworkPolicyManager;
-import android.net.NetworkPolicyManager.NetworkPolicyCallback;
-import android.net.NetworkProvider;
-import android.net.NetworkRequest;
-import android.net.NetworkScore;
-import android.net.NetworkSpecifier;
-import android.net.NetworkStack;
-import android.net.NetworkState;
-import android.net.NetworkStateSnapshot;
-import android.net.NetworkTestResultParcelable;
-import android.net.NetworkUtils;
-import android.net.NetworkWatchlistManager;
-import android.net.OemNetworkPreferences;
-import android.net.PrivateDnsConfigParcel;
-import android.net.ProxyInfo;
-import android.net.QosCallbackException;
-import android.net.QosFilter;
-import android.net.QosSocketFilter;
-import android.net.QosSocketInfo;
-import android.net.RouteInfo;
-import android.net.RouteInfoParcel;
-import android.net.SocketKeepalive;
-import android.net.TetheringManager;
-import android.net.TransportInfo;
-import android.net.UidRange;
-import android.net.UidRangeParcel;
-import android.net.UnderlyingNetworkInfo;
-import android.net.Uri;
-import android.net.VpnManager;
-import android.net.VpnTransportInfo;
-import android.net.metrics.IpConnectivityLog;
-import android.net.metrics.NetworkEvent;
-import android.net.netlink.InetDiagMessage;
-import android.net.networkstack.ModuleNetworkStackClient;
-import android.net.networkstack.NetworkStackClientBase;
-import android.net.resolv.aidl.DnsHealthEventParcel;
-import android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener;
-import android.net.resolv.aidl.Nat64PrefixEventParcel;
-import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
-import android.net.shared.PrivateDnsConfig;
-import android.net.util.MultinetworkPolicyTracker;
-import android.os.BatteryStatsManager;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
-import android.os.PersistableBundle;
-import android.os.PowerManager;
-import android.os.Process;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.sysprop.NetworkProperties;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.LocalLog;
-import android.util.Log;
-import android.util.Pair;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-
-import com.android.connectivity.resources.R;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.MessageUtils;
-import com.android.modules.utils.BasicShellCommandHandler;
-import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
-import com.android.net.module.util.CollectionUtils;
-import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult;
-import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
-import com.android.net.module.util.LocationPermissionChecker;
-import com.android.net.module.util.NetworkCapabilitiesUtils;
-import com.android.net.module.util.PermissionUtils;
-import com.android.server.connectivity.AutodestructReference;
-import com.android.server.connectivity.DnsManager;
-import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
-import com.android.server.connectivity.FullScore;
-import com.android.server.connectivity.KeepaliveTracker;
-import com.android.server.connectivity.LingerMonitor;
-import com.android.server.connectivity.MockableSystemProperties;
-import com.android.server.connectivity.NetworkAgentInfo;
-import com.android.server.connectivity.NetworkDiagnostics;
-import com.android.server.connectivity.NetworkNotificationManager;
-import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
-import com.android.server.connectivity.NetworkOffer;
-import com.android.server.connectivity.NetworkRanker;
-import com.android.server.connectivity.PermissionMonitor;
-import com.android.server.connectivity.ProfileNetworkPreferences;
-import com.android.server.connectivity.ProxyTracker;
-import com.android.server.connectivity.QosCallbackTracker;
-
-import libcore.io.IoUtils;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.ConcurrentModificationException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.StringJoiner;
-import java.util.TreeSet;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * @hide
- */
-public class ConnectivityService extends IConnectivityManager.Stub
- implements PendingIntent.OnFinished {
- private static final String TAG = ConnectivityService.class.getSimpleName();
-
- private static final String DIAG_ARG = "--diag";
- public static final String SHORT_ARG = "--short";
- private static final String NETWORK_ARG = "networks";
- private static final String REQUEST_ARG = "requests";
-
- private static final boolean DBG = true;
- private static final boolean DDBG = Log.isLoggable(TAG, Log.DEBUG);
- private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
-
- private static final boolean LOGD_BLOCKED_NETWORKINFO = true;
-
- /**
- * Default URL to use for {@link #getCaptivePortalServerUrl()}. This should not be changed
- * by OEMs for configuration purposes, as this value is overridden by
- * ConnectivitySettingsManager.CAPTIVE_PORTAL_HTTP_URL.
- * R.string.config_networkCaptivePortalServerUrl should be overridden instead for this purpose
- * (preferably via runtime resource overlays).
- */
- private static final String DEFAULT_CAPTIVE_PORTAL_HTTP_URL =
- "http://connectivitycheck.gstatic.com/generate_204";
-
- // TODO: create better separation between radio types and network types
-
- // how long to wait before switching back to a radio's default network
- private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
- // system property that can override the above value
- private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
- "android.telephony.apn-restore";
-
- // How long to wait before putting up a "This network doesn't have an Internet connection,
- // connect anyway?" dialog after the user selects a network that doesn't validate.
- private static final int PROMPT_UNVALIDATED_DELAY_MS = 8 * 1000;
-
- // Default to 30s linger time-out, and 5s for nascent network. Modifiable only for testing.
- private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger";
- private static final int DEFAULT_LINGER_DELAY_MS = 30_000;
- private static final int DEFAULT_NASCENT_DELAY_MS = 5_000;
-
- // The maximum number of network request allowed per uid before an exception is thrown.
- private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
-
- // The maximum number of network request allowed for system UIDs before an exception is thrown.
- @VisibleForTesting
- static final int MAX_NETWORK_REQUESTS_PER_SYSTEM_UID = 250;
-
- @VisibleForTesting
- protected int mLingerDelayMs; // Can't be final, or test subclass constructors can't change it.
- @VisibleForTesting
- protected int mNascentDelayMs;
-
- // How long to delay to removal of a pending intent based request.
- // See ConnectivitySettingsManager.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
- private final int mReleasePendingIntentDelayMs;
-
- private MockableSystemProperties mSystemProperties;
-
- @VisibleForTesting
- protected final PermissionMonitor mPermissionMonitor;
-
- private final PerUidCounter mNetworkRequestCounter;
- @VisibleForTesting
- final PerUidCounter mSystemNetworkRequestCounter;
-
- private volatile boolean mLockdownEnabled;
-
- /**
- * Stale copy of uid blocked reasons provided by NPMS. As long as they are accessed only in
- * internal handler thread, they don't need a lock.
- */
- private SparseIntArray mUidBlockedReasons = new SparseIntArray();
-
- private final Context mContext;
- private final ConnectivityResources mResources;
- // The Context is created for UserHandle.ALL.
- private final Context mUserAllContext;
- private final Dependencies mDeps;
- // 0 is full bad, 100 is full good
- private int mDefaultInetConditionPublished = 0;
-
- @VisibleForTesting
- protected IDnsResolver mDnsResolver;
- @VisibleForTesting
- protected INetd mNetd;
- private NetworkStatsManager mStatsManager;
- private NetworkPolicyManager mPolicyManager;
- private final NetdCallback mNetdCallback;
-
- /**
- * TestNetworkService (lazily) created upon first usage. Locked to prevent creation of multiple
- * instances.
- */
- @GuardedBy("mTNSLock")
- private TestNetworkService mTNS;
-
- private final Object mTNSLock = new Object();
-
- private String mCurrentTcpBufferSizes;
-
- private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
- new Class[] { ConnectivityService.class, NetworkAgent.class, NetworkAgentInfo.class });
-
- private enum ReapUnvalidatedNetworks {
- // Tear down networks that have no chance (e.g. even if validated) of becoming
- // the highest scoring network satisfying a NetworkRequest. This should be passed when
- // all networks have been rematched against all NetworkRequests.
- REAP,
- // Don't reap networks. This should be passed when some networks have not yet been
- // rematched against all NetworkRequests.
- DONT_REAP
- }
-
- private enum UnneededFor {
- LINGER, // Determine whether this network is unneeded and should be lingered.
- TEARDOWN, // Determine whether this network is unneeded and should be torn down.
- }
-
- /**
- * used internally to clear a wakelock when transitioning
- * from one net to another. Clear happens when we get a new
- * network - EVENT_EXPIRE_NET_TRANSITION_WAKELOCK happens
- * after a timeout if no network is found (typically 1 min).
- */
- private static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK = 8;
-
- /**
- * used internally to reload global proxy settings
- */
- private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY = 9;
-
- /**
- * PAC manager has received new port.
- */
- private static final int EVENT_PROXY_HAS_CHANGED = 16;
-
- /**
- * used internally when registering NetworkProviders
- * obj = NetworkProviderInfo
- */
- private static final int EVENT_REGISTER_NETWORK_PROVIDER = 17;
-
- /**
- * used internally when registering NetworkAgents
- * obj = Messenger
- */
- private static final int EVENT_REGISTER_NETWORK_AGENT = 18;
-
- /**
- * used to add a network request
- * includes a NetworkRequestInfo
- */
- private static final int EVENT_REGISTER_NETWORK_REQUEST = 19;
-
- /**
- * indicates a timeout period is over - check if we had a network yet or not
- * and if not, call the timeout callback (but leave the request live until they
- * cancel it.
- * includes a NetworkRequestInfo
- */
- private static final int EVENT_TIMEOUT_NETWORK_REQUEST = 20;
-
- /**
- * used to add a network listener - no request
- * includes a NetworkRequestInfo
- */
- private static final int EVENT_REGISTER_NETWORK_LISTENER = 21;
-
- /**
- * used to remove a network request, either a listener or a real request
- * arg1 = UID of caller
- * obj = NetworkRequest
- */
- private static final int EVENT_RELEASE_NETWORK_REQUEST = 22;
-
- /**
- * used internally when registering NetworkProviders
- * obj = Messenger
- */
- private static final int EVENT_UNREGISTER_NETWORK_PROVIDER = 23;
-
- /**
- * used internally to expire a wakelock when transitioning
- * from one net to another. Expire happens when we fail to find
- * a new network (typically after 1 minute) -
- * EVENT_CLEAR_NET_TRANSITION_WAKELOCK happens if we had found
- * a replacement network.
- */
- private static final int EVENT_EXPIRE_NET_TRANSITION_WAKELOCK = 24;
-
- /**
- * used to add a network request with a pending intent
- * obj = NetworkRequestInfo
- */
- private static final int EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT = 26;
-
- /**
- * used to remove a pending intent and its associated network request.
- * arg1 = UID of caller
- * obj = PendingIntent
- */
- private static final int EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT = 27;
-
- /**
- * used to specify whether a network should be used even if unvalidated.
- * arg1 = whether to accept the network if it's unvalidated (1 or 0)
- * arg2 = whether to remember this choice in the future (1 or 0)
- * obj = network
- */
- private static final int EVENT_SET_ACCEPT_UNVALIDATED = 28;
-
- /**
- * used to ask the user to confirm a connection to an unvalidated network.
- * obj = network
- */
- private static final int EVENT_PROMPT_UNVALIDATED = 29;
-
- /**
- * used internally to (re)configure always-on networks.
- */
- private static final int EVENT_CONFIGURE_ALWAYS_ON_NETWORKS = 30;
-
- /**
- * used to add a network listener with a pending intent
- * obj = NetworkRequestInfo
- */
- private static final int EVENT_REGISTER_NETWORK_LISTENER_WITH_INTENT = 31;
-
- /**
- * used to specify whether a network should not be penalized when it becomes unvalidated.
- */
- private static final int EVENT_SET_AVOID_UNVALIDATED = 35;
-
- /**
- * used to trigger revalidation of a network.
- */
- private static final int EVENT_REVALIDATE_NETWORK = 36;
-
- // Handle changes in Private DNS settings.
- private static final int EVENT_PRIVATE_DNS_SETTINGS_CHANGED = 37;
-
- // Handle private DNS validation status updates.
- private static final int EVENT_PRIVATE_DNS_VALIDATION_UPDATE = 38;
-
- /**
- * Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the network has
- * been tested.
- * obj = {@link NetworkTestedResults} representing information sent from NetworkMonitor.
- * data = PersistableBundle of extras passed from NetworkMonitor. If {@link
- * NetworkMonitorCallbacks#notifyNetworkTested} is called, this will be null.
- */
- private static final int EVENT_NETWORK_TESTED = 41;
-
- /**
- * Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the private DNS
- * config was resolved.
- * obj = PrivateDnsConfig
- * arg2 = netid
- */
- private static final int EVENT_PRIVATE_DNS_CONFIG_RESOLVED = 42;
-
- /**
- * Request ConnectivityService display provisioning notification.
- * arg1 = Whether to make the notification visible.
- * arg2 = NetID.
- * obj = Intent to be launched when notification selected by user, null if !arg1.
- */
- private static final int EVENT_PROVISIONING_NOTIFICATION = 43;
-
- /**
- * Used to specify whether a network should be used even if connectivity is partial.
- * arg1 = whether to accept the network if its connectivity is partial (1 for true or 0 for
- * false)
- * arg2 = whether to remember this choice in the future (1 for true or 0 for false)
- * obj = network
- */
- private static final int EVENT_SET_ACCEPT_PARTIAL_CONNECTIVITY = 44;
-
- /**
- * Event for NetworkMonitor to inform ConnectivityService that the probe status has changed.
- * Both of the arguments are bitmasks, and the value of bits come from
- * INetworkMonitor.NETWORK_VALIDATION_PROBE_*.
- * arg1 = A bitmask to describe which probes are completed.
- * arg2 = A bitmask to describe which probes are successful.
- */
- public static final int EVENT_PROBE_STATUS_CHANGED = 45;
-
- /**
- * Event for NetworkMonitor to inform ConnectivityService that captive portal data has changed.
- * arg1 = unused
- * arg2 = netId
- * obj = captive portal data
- */
- private static final int EVENT_CAPPORT_DATA_CHANGED = 46;
-
- /**
- * Used by setRequireVpnForUids.
- * arg1 = whether the specified UID ranges are required to use a VPN.
- * obj = Array of UidRange objects.
- */
- private static final int EVENT_SET_REQUIRE_VPN_FOR_UIDS = 47;
-
- /**
- * Used internally when setting the default networks for OemNetworkPreferences.
- * obj = Pair<OemNetworkPreferences, listener>
- */
- private static final int EVENT_SET_OEM_NETWORK_PREFERENCE = 48;
-
- /**
- * Used to indicate the system default network becomes active.
- */
- private static final int EVENT_REPORT_NETWORK_ACTIVITY = 49;
-
- /**
- * Used internally when setting a network preference for a user profile.
- * obj = Pair<ProfileNetworkPreference, Listener>
- */
- private static final int EVENT_SET_PROFILE_NETWORK_PREFERENCE = 50;
-
- /**
- * Event to specify that reasons for why an uid is blocked changed.
- * arg1 = uid
- * arg2 = blockedReasons
- */
- private static final int EVENT_UID_BLOCKED_REASON_CHANGED = 51;
-
- /**
- * Event to register a new network offer
- * obj = NetworkOffer
- */
- private static final int EVENT_REGISTER_NETWORK_OFFER = 52;
-
- /**
- * Event to unregister an existing network offer
- * obj = INetworkOfferCallback
- */
- private static final int EVENT_UNREGISTER_NETWORK_OFFER = 53;
-
- /**
- * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
- * should be shown.
- */
- private static final int PROVISIONING_NOTIFICATION_SHOW = 1;
-
- /**
- * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
- * should be hidden.
- */
- private static final int PROVISIONING_NOTIFICATION_HIDE = 0;
-
- private static String eventName(int what) {
- return sMagicDecoderRing.get(what, Integer.toString(what));
- }
-
- private static IDnsResolver getDnsResolver(Context context) {
- final DnsResolverServiceManager dsm = context.getSystemService(
- DnsResolverServiceManager.class);
- return IDnsResolver.Stub.asInterface(dsm.getService());
- }
-
- /** Handler thread used for all of the handlers below. */
- @VisibleForTesting
- protected final HandlerThread mHandlerThread;
- /** Handler used for internal events. */
- final private InternalHandler mHandler;
- /** Handler used for incoming {@link NetworkStateTracker} events. */
- final private NetworkStateTrackerHandler mTrackerHandler;
- /** Handler used for processing {@link android.net.ConnectivityDiagnosticsManager} events */
- @VisibleForTesting
- final ConnectivityDiagnosticsHandler mConnectivityDiagnosticsHandler;
-
- private final DnsManager mDnsManager;
- private final NetworkRanker mNetworkRanker;
-
- private boolean mSystemReady;
- private Intent mInitialBroadcast;
-
- private PowerManager.WakeLock mNetTransitionWakeLock;
- private final PowerManager.WakeLock mPendingIntentWakeLock;
-
- // A helper object to track the current default HTTP proxy. ConnectivityService needs to tell
- // the world when it changes.
- @VisibleForTesting
- protected final ProxyTracker mProxyTracker;
-
- final private SettingsObserver mSettingsObserver;
-
- private UserManager mUserManager;
-
- // the set of network types that can only be enabled by system/sig apps
- private List<Integer> mProtectedNetworks;
-
- private Set<String> mWolSupportedInterfaces;
-
- private final TelephonyManager mTelephonyManager;
- private final AppOpsManager mAppOpsManager;
-
- private final LocationPermissionChecker mLocationPermissionChecker;
-
- private KeepaliveTracker mKeepaliveTracker;
- private QosCallbackTracker mQosCallbackTracker;
- private NetworkNotificationManager mNotifier;
- private LingerMonitor mLingerMonitor;
-
- // sequence number of NetworkRequests
- private int mNextNetworkRequestId = NetworkRequest.FIRST_REQUEST_ID;
-
- // Sequence number for NetworkProvider IDs.
- private final AtomicInteger mNextNetworkProviderId = new AtomicInteger(
- NetworkProvider.FIRST_PROVIDER_ID);
-
- // NetworkRequest activity String log entries.
- private static final int MAX_NETWORK_REQUEST_LOGS = 20;
- private final LocalLog mNetworkRequestInfoLogs = new LocalLog(MAX_NETWORK_REQUEST_LOGS);
-
- // NetworkInfo blocked and unblocked String log entries
- private static final int MAX_NETWORK_INFO_LOGS = 40;
- private final LocalLog mNetworkInfoBlockingLogs = new LocalLog(MAX_NETWORK_INFO_LOGS);
-
- private static final int MAX_WAKELOCK_LOGS = 20;
- private final LocalLog mWakelockLogs = new LocalLog(MAX_WAKELOCK_LOGS);
- private int mTotalWakelockAcquisitions = 0;
- private int mTotalWakelockReleases = 0;
- private long mTotalWakelockDurationMs = 0;
- private long mMaxWakelockDurationMs = 0;
- private long mLastWakeLockAcquireTimestamp = 0;
-
- private final IpConnectivityLog mMetricsLog;
-
- @GuardedBy("mBandwidthRequests")
- private final SparseArray<Integer> mBandwidthRequests = new SparseArray(10);
-
- @VisibleForTesting
- final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
-
- @VisibleForTesting
- final Map<IBinder, ConnectivityDiagnosticsCallbackInfo> mConnectivityDiagnosticsCallbacks =
- new HashMap<>();
-
- /**
- * Implements support for the legacy "one network per network type" model.
- *
- * We used to have a static array of NetworkStateTrackers, one for each
- * network type, but that doesn't work any more now that we can have,
- * for example, more that one wifi network. This class stores all the
- * NetworkAgentInfo objects that support a given type, but the legacy
- * API will only see the first one.
- *
- * It serves two main purposes:
- *
- * 1. Provide information about "the network for a given type" (since this
- * API only supports one).
- * 2. Send legacy connectivity change broadcasts. Broadcasts are sent if
- * the first network for a given type changes, or if the default network
- * changes.
- */
- @VisibleForTesting
- static class LegacyTypeTracker {
-
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- /**
- * Array of lists, one per legacy network type (e.g., TYPE_MOBILE_MMS).
- * Each list holds references to all NetworkAgentInfos that are used to
- * satisfy requests for that network type.
- *
- * This array is built out at startup such that an unsupported network
- * doesn't get an ArrayList instance, making this a tristate:
- * unsupported, supported but not active and active.
- *
- * The actual lists are populated when we scan the network types that
- * are supported on this device.
- *
- * Threading model:
- * - addSupportedType() is only called in the constructor
- * - add(), update(), remove() are only called from the ConnectivityService handler thread.
- * They are therefore not thread-safe with respect to each other.
- * - getNetworkForType() can be called at any time on binder threads. It is synchronized
- * on mTypeLists to be thread-safe with respect to a concurrent remove call.
- * - getRestoreTimerForType(type) is also synchronized on mTypeLists.
- * - dump is thread-safe with respect to concurrent add and remove calls.
- */
- private final ArrayList<NetworkAgentInfo> mTypeLists[];
- @NonNull
- private final ConnectivityService mService;
-
- // Restore timers for requestNetworkForFeature (network type -> timer in ms). Types without
- // an entry have no timer (equivalent to -1). Lazily loaded.
- @NonNull
- private ArrayMap<Integer, Integer> mRestoreTimers = new ArrayMap<>();
-
- LegacyTypeTracker(@NonNull ConnectivityService service) {
- mService = service;
- mTypeLists = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1];
- }
-
- public void loadSupportedTypes(@NonNull Context ctx, @NonNull TelephonyManager tm) {
- final PackageManager pm = ctx.getPackageManager();
- if (pm.hasSystemFeature(FEATURE_WIFI)) {
- addSupportedType(TYPE_WIFI);
- }
- if (pm.hasSystemFeature(FEATURE_WIFI_DIRECT)) {
- addSupportedType(TYPE_WIFI_P2P);
- }
- if (tm.isDataCapable()) {
- // Telephony does not have granular support for these types: they are either all
- // supported, or none is supported
- addSupportedType(TYPE_MOBILE);
- addSupportedType(TYPE_MOBILE_MMS);
- addSupportedType(TYPE_MOBILE_SUPL);
- addSupportedType(TYPE_MOBILE_DUN);
- addSupportedType(TYPE_MOBILE_HIPRI);
- addSupportedType(TYPE_MOBILE_FOTA);
- addSupportedType(TYPE_MOBILE_IMS);
- addSupportedType(TYPE_MOBILE_CBS);
- addSupportedType(TYPE_MOBILE_IA);
- addSupportedType(TYPE_MOBILE_EMERGENCY);
- }
- if (pm.hasSystemFeature(FEATURE_BLUETOOTH)) {
- addSupportedType(TYPE_BLUETOOTH);
- }
- if (pm.hasSystemFeature(FEATURE_WATCH)) {
- // TYPE_PROXY is only used on Wear
- addSupportedType(TYPE_PROXY);
- }
- // Ethernet is often not specified in the configs, although many devices can use it via
- // USB host adapters. Add it as long as the ethernet service is here.
- if (ctx.getSystemService(Context.ETHERNET_SERVICE) != null) {
- addSupportedType(TYPE_ETHERNET);
- }
-
- // Always add TYPE_VPN as a supported type
- addSupportedType(TYPE_VPN);
- }
-
- private void addSupportedType(int type) {
- if (mTypeLists[type] != null) {
- throw new IllegalStateException(
- "legacy list for type " + type + "already initialized");
- }
- mTypeLists[type] = new ArrayList<>();
- }
-
- public boolean isTypeSupported(int type) {
- return isNetworkTypeValid(type) && mTypeLists[type] != null;
- }
-
- public NetworkAgentInfo getNetworkForType(int type) {
- synchronized (mTypeLists) {
- if (isTypeSupported(type) && !mTypeLists[type].isEmpty()) {
- return mTypeLists[type].get(0);
- }
- }
- return null;
- }
-
- public int getRestoreTimerForType(int type) {
- synchronized (mTypeLists) {
- if (mRestoreTimers == null) {
- mRestoreTimers = loadRestoreTimers();
- }
- return mRestoreTimers.getOrDefault(type, -1);
- }
- }
-
- private ArrayMap<Integer, Integer> loadRestoreTimers() {
- final String[] configs = mService.mResources.get().getStringArray(
- R.array.config_legacy_networktype_restore_timers);
- final ArrayMap<Integer, Integer> ret = new ArrayMap<>(configs.length);
- for (final String config : configs) {
- final String[] splits = TextUtils.split(config, ",");
- if (splits.length != 2) {
- logwtf("Invalid restore timer token count: " + config);
- continue;
- }
- try {
- ret.put(Integer.parseInt(splits[0]), Integer.parseInt(splits[1]));
- } catch (NumberFormatException e) {
- logwtf("Invalid restore timer number format: " + config, e);
- }
- }
- return ret;
- }
-
- private void maybeLogBroadcast(NetworkAgentInfo nai, DetailedState state, int type,
- boolean isDefaultNetwork) {
- if (DBG) {
- log("Sending " + state
- + " broadcast for type " + type + " " + nai.toShortString()
- + " isDefaultNetwork=" + isDefaultNetwork);
- }
- }
-
- // When a lockdown VPN connects, send another CONNECTED broadcast for the underlying
- // network type, to preserve previous behaviour.
- private void maybeSendLegacyLockdownBroadcast(@NonNull NetworkAgentInfo vpnNai) {
- if (vpnNai != mService.getLegacyLockdownNai()) return;
-
- if (vpnNai.declaredUnderlyingNetworks == null
- || vpnNai.declaredUnderlyingNetworks.length != 1) {
- Log.wtf(TAG, "Legacy lockdown VPN must have exactly one underlying network: "
- + Arrays.toString(vpnNai.declaredUnderlyingNetworks));
- return;
- }
- final NetworkAgentInfo underlyingNai = mService.getNetworkAgentInfoForNetwork(
- vpnNai.declaredUnderlyingNetworks[0]);
- if (underlyingNai == null) return;
-
- final int type = underlyingNai.networkInfo.getType();
- final DetailedState state = DetailedState.CONNECTED;
- maybeLogBroadcast(underlyingNai, state, type, true /* isDefaultNetwork */);
- mService.sendLegacyNetworkBroadcast(underlyingNai, state, type);
- }
-
- /** Adds the given network to the specified legacy type list. */
- public void add(int type, NetworkAgentInfo nai) {
- if (!isTypeSupported(type)) {
- return; // Invalid network type.
- }
- if (VDBG) log("Adding agent " + nai + " for legacy network type " + type);
-
- ArrayList<NetworkAgentInfo> list = mTypeLists[type];
- if (list.contains(nai)) {
- return;
- }
- synchronized (mTypeLists) {
- list.add(nai);
- }
-
- // Send a broadcast if this is the first network of its type or if it's the default.
- final boolean isDefaultNetwork = mService.isDefaultNetwork(nai);
-
- // If a legacy lockdown VPN is active, override the NetworkInfo state in all broadcasts
- // to preserve previous behaviour.
- final DetailedState state = mService.getLegacyLockdownState(DetailedState.CONNECTED);
- if ((list.size() == 1) || isDefaultNetwork) {
- maybeLogBroadcast(nai, state, type, isDefaultNetwork);
- mService.sendLegacyNetworkBroadcast(nai, state, type);
- }
-
- if (type == TYPE_VPN && state == DetailedState.CONNECTED) {
- maybeSendLegacyLockdownBroadcast(nai);
- }
- }
-
- /** Removes the given network from the specified legacy type list. */
- public void remove(int type, NetworkAgentInfo nai, boolean wasDefault) {
- ArrayList<NetworkAgentInfo> list = mTypeLists[type];
- if (list == null || list.isEmpty()) {
- return;
- }
- final boolean wasFirstNetwork = list.get(0).equals(nai);
-
- synchronized (mTypeLists) {
- if (!list.remove(nai)) {
- return;
- }
- }
-
- if (wasFirstNetwork || wasDefault) {
- maybeLogBroadcast(nai, DetailedState.DISCONNECTED, type, wasDefault);
- mService.sendLegacyNetworkBroadcast(nai, DetailedState.DISCONNECTED, type);
- }
-
- if (!list.isEmpty() && wasFirstNetwork) {
- if (DBG) log("Other network available for type " + type +
- ", sending connected broadcast");
- final NetworkAgentInfo replacement = list.get(0);
- maybeLogBroadcast(replacement, DetailedState.CONNECTED, type,
- mService.isDefaultNetwork(replacement));
- mService.sendLegacyNetworkBroadcast(replacement, DetailedState.CONNECTED, type);
- }
- }
-
- /** Removes the given network from all legacy type lists. */
- public void remove(NetworkAgentInfo nai, boolean wasDefault) {
- if (VDBG) log("Removing agent " + nai + " wasDefault=" + wasDefault);
- for (int type = 0; type < mTypeLists.length; type++) {
- remove(type, nai, wasDefault);
- }
- }
-
- // send out another legacy broadcast - currently only used for suspend/unsuspend
- // toggle
- public void update(NetworkAgentInfo nai) {
- final boolean isDefault = mService.isDefaultNetwork(nai);
- final DetailedState state = nai.networkInfo.getDetailedState();
- for (int type = 0; type < mTypeLists.length; type++) {
- final ArrayList<NetworkAgentInfo> list = mTypeLists[type];
- final boolean contains = (list != null && list.contains(nai));
- final boolean isFirst = contains && (nai == list.get(0));
- if (isFirst || contains && isDefault) {
- maybeLogBroadcast(nai, state, type, isDefault);
- mService.sendLegacyNetworkBroadcast(nai, state, type);
- }
- }
- }
-
- public void dump(IndentingPrintWriter pw) {
- pw.println("mLegacyTypeTracker:");
- pw.increaseIndent();
- pw.print("Supported types:");
- for (int type = 0; type < mTypeLists.length; type++) {
- if (mTypeLists[type] != null) pw.print(" " + type);
- }
- pw.println();
- pw.println("Current state:");
- pw.increaseIndent();
- synchronized (mTypeLists) {
- for (int type = 0; type < mTypeLists.length; type++) {
- if (mTypeLists[type] == null || mTypeLists[type].isEmpty()) continue;
- for (NetworkAgentInfo nai : mTypeLists[type]) {
- pw.println(type + " " + nai.toShortString());
- }
- }
- }
- pw.decreaseIndent();
- pw.decreaseIndent();
- pw.println();
- }
- }
- private final LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker(this);
-
- final LocalPriorityDump mPriorityDumper = new LocalPriorityDump();
- /**
- * Helper class which parses out priority arguments and dumps sections according to their
- * priority. If priority arguments are omitted, function calls the legacy dump command.
- */
- private class LocalPriorityDump {
- private static final String PRIORITY_ARG = "--dump-priority";
- private static final String PRIORITY_ARG_HIGH = "HIGH";
- private static final String PRIORITY_ARG_NORMAL = "NORMAL";
-
- LocalPriorityDump() {}
-
- private void dumpHigh(FileDescriptor fd, PrintWriter pw) {
- doDump(fd, pw, new String[] {DIAG_ARG});
- doDump(fd, pw, new String[] {SHORT_ARG});
- }
-
- private void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) {
- doDump(fd, pw, args);
- }
-
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (args == null) {
- dumpNormal(fd, pw, args);
- return;
- }
-
- String priority = null;
- for (int argIndex = 0; argIndex < args.length; argIndex++) {
- if (args[argIndex].equals(PRIORITY_ARG) && argIndex + 1 < args.length) {
- argIndex++;
- priority = args[argIndex];
- }
- }
-
- if (PRIORITY_ARG_HIGH.equals(priority)) {
- dumpHigh(fd, pw);
- } else if (PRIORITY_ARG_NORMAL.equals(priority)) {
- dumpNormal(fd, pw, args);
- } else {
- // ConnectivityService publishes binder service using publishBinderService() with
- // no priority assigned will be treated as NORMAL priority. Dumpsys does not send
- // "--dump-priority" arguments to the service. Thus, dump NORMAL only to align the
- // legacy output for dumpsys connectivity.
- // TODO: Integrate into signal dump.
- dumpNormal(fd, pw, args);
- }
- }
- }
-
- /**
- * Keeps track of the number of requests made under different uids.
- */
- public static class PerUidCounter {
- private final int mMaxCountPerUid;
-
- // Map from UID to number of NetworkRequests that UID has filed.
- @VisibleForTesting
- @GuardedBy("mUidToNetworkRequestCount")
- final SparseIntArray mUidToNetworkRequestCount = new SparseIntArray();
-
- /**
- * Constructor
- *
- * @param maxCountPerUid the maximum count per uid allowed
- */
- public PerUidCounter(final int maxCountPerUid) {
- mMaxCountPerUid = maxCountPerUid;
- }
-
- /**
- * Increments the request count of the given uid. Throws an exception if the number
- * of open requests for the uid exceeds the value of maxCounterPerUid which is the value
- * passed into the constructor. see: {@link #PerUidCounter(int)}.
- *
- * @throws ServiceSpecificException with
- * {@link ConnectivityManager.Errors.TOO_MANY_REQUESTS} if the number of requests for
- * the uid exceed the allowed number.
- *
- * @param uid the uid that the request was made under
- */
- public void incrementCountOrThrow(final int uid) {
- synchronized (mUidToNetworkRequestCount) {
- incrementCountOrThrow(uid, 1 /* numToIncrement */);
- }
- }
-
- private void incrementCountOrThrow(final int uid, final int numToIncrement) {
- final int newRequestCount =
- mUidToNetworkRequestCount.get(uid, 0) + numToIncrement;
- if (newRequestCount >= mMaxCountPerUid) {
- throw new ServiceSpecificException(
- ConnectivityManager.Errors.TOO_MANY_REQUESTS);
- }
- mUidToNetworkRequestCount.put(uid, newRequestCount);
- }
-
- /**
- * Decrements the request count of the given uid.
- *
- * @param uid the uid that the request was made under
- */
- public void decrementCount(final int uid) {
- synchronized (mUidToNetworkRequestCount) {
- decrementCount(uid, 1 /* numToDecrement */);
- }
- }
-
- private void decrementCount(final int uid, final int numToDecrement) {
- final int newRequestCount =
- mUidToNetworkRequestCount.get(uid, 0) - numToDecrement;
- if (newRequestCount < 0) {
- logwtf("BUG: too small request count " + newRequestCount + " for UID " + uid);
- } else if (newRequestCount == 0) {
- mUidToNetworkRequestCount.delete(uid);
- } else {
- mUidToNetworkRequestCount.put(uid, newRequestCount);
- }
- }
-
- /**
- * Used to adjust the request counter for the per-app API flows. Directly adjusting the
- * counter is not ideal however in the per-app flows, the nris can't be removed until they
- * are used to create the new nris upon set. Therefore the request count limit can be
- * artificially hit. This method is used as a workaround for this particular case so that
- * the request counts are accounted for correctly.
- * @param uid the uid to adjust counts for
- * @param numOfNewRequests the new request count to account for
- * @param r the runnable to execute
- */
- public void transact(final int uid, final int numOfNewRequests, @NonNull final Runnable r) {
- // This should only be used on the handler thread as per all current and foreseen
- // use-cases. ensureRunningOnConnectivityServiceThread() can't be used because there is
- // no ref to the outer ConnectivityService.
- synchronized (mUidToNetworkRequestCount) {
- final int reqCountOverage = getCallingUidRequestCountOverage(uid, numOfNewRequests);
- decrementCount(uid, reqCountOverage);
- r.run();
- incrementCountOrThrow(uid, reqCountOverage);
- }
- }
-
- private int getCallingUidRequestCountOverage(final int uid, final int numOfNewRequests) {
- final int newUidRequestCount = mUidToNetworkRequestCount.get(uid, 0)
- + numOfNewRequests;
- return newUidRequestCount >= MAX_NETWORK_REQUESTS_PER_SYSTEM_UID
- ? newUidRequestCount - (MAX_NETWORK_REQUESTS_PER_SYSTEM_UID - 1) : 0;
- }
- }
-
- /**
- * Dependencies of ConnectivityService, for injection in tests.
- */
- @VisibleForTesting
- public static class Dependencies {
- public int getCallingUid() {
- return Binder.getCallingUid();
- }
-
- /**
- * Get system properties to use in ConnectivityService.
- */
- public MockableSystemProperties getSystemProperties() {
- return new MockableSystemProperties();
- }
-
- /**
- * Get the {@link ConnectivityResources} to use in ConnectivityService.
- */
- public ConnectivityResources getResources(@NonNull Context ctx) {
- return new ConnectivityResources(ctx);
- }
-
- /**
- * Create a HandlerThread to use in ConnectivityService.
- */
- public HandlerThread makeHandlerThread() {
- return new HandlerThread("ConnectivityServiceThread");
- }
-
- /**
- * Get a reference to the ModuleNetworkStackClient.
- */
- public NetworkStackClientBase getNetworkStack() {
- return ModuleNetworkStackClient.getInstance(null);
- }
-
- /**
- * @see ProxyTracker
- */
- public ProxyTracker makeProxyTracker(@NonNull Context context,
- @NonNull Handler connServiceHandler) {
- return new ProxyTracker(context, connServiceHandler, EVENT_PROXY_HAS_CHANGED);
- }
-
- /**
- * @see NetIdManager
- */
- public NetIdManager makeNetIdManager() {
- return new NetIdManager();
- }
-
- /**
- * @see NetworkUtils#queryUserAccess(int, int)
- */
- public boolean queryUserAccess(int uid, Network network, ConnectivityService cs) {
- return cs.queryUserAccess(uid, network);
- }
-
- /**
- * Gets the UID that owns a socket connection. Needed because opening SOCK_DIAG sockets
- * requires CAP_NET_ADMIN, which the unit tests do not have.
- */
- public int getConnectionOwnerUid(int protocol, InetSocketAddress local,
- InetSocketAddress remote) {
- return InetDiagMessage.getConnectionOwnerUid(protocol, local, remote);
- }
-
- /**
- * @see MultinetworkPolicyTracker
- */
- public MultinetworkPolicyTracker makeMultinetworkPolicyTracker(
- @NonNull Context c, @NonNull Handler h, @NonNull Runnable r) {
- return new MultinetworkPolicyTracker(c, h, r);
- }
-
- /**
- * @see BatteryStatsManager
- */
- public void reportNetworkInterfaceForTransports(Context context, String iface,
- int[] transportTypes) {
- final BatteryStatsManager batteryStats =
- context.getSystemService(BatteryStatsManager.class);
- batteryStats.reportNetworkInterfaceForTransports(iface, transportTypes);
- }
-
- public boolean getCellular464XlatEnabled() {
- return NetworkProperties.isCellular464XlatEnabled().orElse(true);
- }
- }
-
- public ConnectivityService(Context context) {
- this(context, getDnsResolver(context), new IpConnectivityLog(),
- INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE)),
- new Dependencies());
- }
-
- @VisibleForTesting
- protected ConnectivityService(Context context, IDnsResolver dnsresolver,
- IpConnectivityLog logger, INetd netd, Dependencies deps) {
- if (DBG) log("ConnectivityService starting up");
-
- mDeps = Objects.requireNonNull(deps, "missing Dependencies");
- mSystemProperties = mDeps.getSystemProperties();
- mNetIdManager = mDeps.makeNetIdManager();
- mContext = Objects.requireNonNull(context, "missing Context");
- mResources = deps.getResources(mContext);
- mNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_UID);
- mSystemNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_SYSTEM_UID);
-
- mMetricsLog = logger;
- mNetworkRanker = new NetworkRanker();
- final NetworkRequest defaultInternetRequest = createDefaultRequest();
- mDefaultRequest = new NetworkRequestInfo(
- Process.myUid(), defaultInternetRequest, null,
- new Binder(), NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
- null /* attributionTags */);
- mNetworkRequests.put(defaultInternetRequest, mDefaultRequest);
- mDefaultNetworkRequests.add(mDefaultRequest);
- mNetworkRequestInfoLogs.log("REGISTER " + mDefaultRequest);
-
- mDefaultMobileDataRequest = createDefaultInternetRequestForTransport(
- NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);
-
- // The default WiFi request is a background request so that apps using WiFi are
- // migrated to a better network (typically ethernet) when one comes up, instead
- // of staying on WiFi forever.
- mDefaultWifiRequest = createDefaultInternetRequestForTransport(
- NetworkCapabilities.TRANSPORT_WIFI, NetworkRequest.Type.BACKGROUND_REQUEST);
-
- mDefaultVehicleRequest = createAlwaysOnRequestForCapability(
- NetworkCapabilities.NET_CAPABILITY_VEHICLE_INTERNAL,
- NetworkRequest.Type.BACKGROUND_REQUEST);
-
- mHandlerThread = mDeps.makeHandlerThread();
- mHandlerThread.start();
- mHandler = new InternalHandler(mHandlerThread.getLooper());
- mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());
- mConnectivityDiagnosticsHandler =
- new ConnectivityDiagnosticsHandler(mHandlerThread.getLooper());
-
- mReleasePendingIntentDelayMs = Settings.Secure.getInt(context.getContentResolver(),
- ConnectivitySettingsManager.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
-
- mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
- // TODO: Consider making the timer customizable.
- mNascentDelayMs = DEFAULT_NASCENT_DELAY_MS;
-
- mStatsManager = mContext.getSystemService(NetworkStatsManager.class);
- mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
- mDnsResolver = Objects.requireNonNull(dnsresolver, "missing IDnsResolver");
- mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
-
- mNetd = netd;
- mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
- mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
- mLocationPermissionChecker = new LocationPermissionChecker(mContext);
-
- // To ensure uid state is synchronized with Network Policy, register for
- // NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService
- // reading existing policy from disk.
- mPolicyManager.registerNetworkPolicyCallback(null, mPolicyCallback);
-
- final PowerManager powerManager = (PowerManager) context.getSystemService(
- Context.POWER_SERVICE);
- mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
- mPendingIntentWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-
- mLegacyTypeTracker.loadSupportedTypes(mContext, mTelephonyManager);
- mProtectedNetworks = new ArrayList<>();
- int[] protectedNetworks = mResources.get().getIntArray(R.array.config_protectedNetworks);
- for (int p : protectedNetworks) {
- if (mLegacyTypeTracker.isTypeSupported(p) && !mProtectedNetworks.contains(p)) {
- mProtectedNetworks.add(p);
- } else {
- if (DBG) loge("Ignoring protectedNetwork " + p);
- }
- }
-
- mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-
- mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
-
- mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
- // Listen for user add/removes to inform PermissionMonitor.
- // Should run on mHandler to avoid any races.
- final IntentFilter userIntentFilter = new IntentFilter();
- userIntentFilter.addAction(Intent.ACTION_USER_ADDED);
- userIntentFilter.addAction(Intent.ACTION_USER_REMOVED);
- mUserAllContext.registerReceiver(mUserIntentReceiver, userIntentFilter,
- null /* broadcastPermission */, mHandler);
-
- // Listen to package add/removes for netd
- final IntentFilter packageIntentFilter = new IntentFilter();
- packageIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
- packageIntentFilter.addDataScheme("package");
- mUserAllContext.registerReceiver(mPackageIntentReceiver, packageIntentFilter,
- null /* broadcastPermission */, mHandler);
-
- mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNetd);
-
- mNetdCallback = new NetdCallback();
- try {
- mNetd.registerUnsolicitedEventListener(mNetdCallback);
- } catch (RemoteException | ServiceSpecificException e) {
- loge("Error registering event listener :" + e);
- }
-
- mSettingsObserver = new SettingsObserver(mContext, mHandler);
- registerSettingsCallbacks();
-
- mKeepaliveTracker = new KeepaliveTracker(mContext, mHandler);
- mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager);
- mQosCallbackTracker = new QosCallbackTracker(mHandler, mNetworkRequestCounter);
-
- final int dailyLimit = Settings.Global.getInt(mContext.getContentResolver(),
- ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
- LingerMonitor.DEFAULT_NOTIFICATION_DAILY_LIMIT);
- final long rateLimit = Settings.Global.getLong(mContext.getContentResolver(),
- ConnectivitySettingsManager.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
- LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS);
- mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);
-
- mMultinetworkPolicyTracker = mDeps.makeMultinetworkPolicyTracker(
- mContext, mHandler, () -> updateAvoidBadWifi());
- mMultinetworkPolicyTracker.start();
-
- mDnsManager = new DnsManager(mContext, mDnsResolver);
- registerPrivateDnsSettingsCallbacks();
-
- // This NAI is a sentinel used to offer no service to apps that are on a multi-layer
- // request that doesn't allow fallback to the default network. It should never be visible
- // to apps. As such, it's not in the list of NAIs and doesn't need many of the normal
- // arguments like the handler or the DnsResolver.
- // TODO : remove this ; it is probably better handled with a sentinel request.
- mNoServiceNetwork = new NetworkAgentInfo(null,
- new Network(INetd.UNREACHABLE_NET_ID),
- new NetworkInfo(TYPE_NONE, 0, "", ""),
- new LinkProperties(), new NetworkCapabilities(),
- new NetworkScore.Builder().setLegacyInt(0).build(), mContext, null,
- new NetworkAgentConfig(), this, null, null, 0, INVALID_UID,
- mLingerDelayMs, mQosCallbackTracker, mDeps);
- }
-
- private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
- return createDefaultNetworkCapabilitiesForUidRange(new UidRange(uid, uid));
- }
-
- private static NetworkCapabilities createDefaultNetworkCapabilitiesForUidRange(
- @NonNull final UidRange uids) {
- final NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
- netCap.setUids(UidRange.toIntRanges(Collections.singleton(uids)));
- return netCap;
- }
-
- private NetworkRequest createDefaultRequest() {
- return createDefaultInternetRequestForTransport(
- TYPE_NONE, NetworkRequest.Type.REQUEST);
- }
-
- private NetworkRequest createDefaultInternetRequestForTransport(
- int transportType, NetworkRequest.Type type) {
- final NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
- if (transportType > TYPE_NONE) {
- netCap.addTransportType(transportType);
- }
- return createNetworkRequest(type, netCap);
- }
-
- private NetworkRequest createNetworkRequest(
- NetworkRequest.Type type, NetworkCapabilities netCap) {
- return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), type);
- }
-
- private NetworkRequest createAlwaysOnRequestForCapability(int capability,
- NetworkRequest.Type type) {
- final NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.clearAll();
- netCap.addCapability(capability);
- netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
- return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), type);
- }
-
- // Used only for testing.
- // TODO: Delete this and either:
- // 1. Give FakeSettingsProvider the ability to send settings change notifications (requires
- // changing ContentResolver to make registerContentObserver non-final).
- // 2. Give FakeSettingsProvider an alternative notification mechanism and have the test use it
- // by subclassing SettingsObserver.
- @VisibleForTesting
- void updateAlwaysOnNetworks() {
- mHandler.sendEmptyMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
- }
-
- // See FakeSettingsProvider comment above.
- @VisibleForTesting
- void updatePrivateDnsSettings() {
- mHandler.sendEmptyMessage(EVENT_PRIVATE_DNS_SETTINGS_CHANGED);
- }
-
- private void handleAlwaysOnNetworkRequest(NetworkRequest networkRequest, int id) {
- final boolean enable = mContext.getResources().getBoolean(id);
- handleAlwaysOnNetworkRequest(networkRequest, enable);
- }
-
- private void handleAlwaysOnNetworkRequest(
- NetworkRequest networkRequest, String settingName, boolean defaultValue) {
- final boolean enable = toBool(Settings.Global.getInt(
- mContext.getContentResolver(), settingName, encodeBool(defaultValue)));
- handleAlwaysOnNetworkRequest(networkRequest, enable);
- }
-
- private void handleAlwaysOnNetworkRequest(NetworkRequest networkRequest, boolean enable) {
- final boolean isEnabled = (mNetworkRequests.get(networkRequest) != null);
- if (enable == isEnabled) {
- return; // Nothing to do.
- }
-
- if (enable) {
- handleRegisterNetworkRequest(new NetworkRequestInfo(
- Process.myUid(), networkRequest, null, new Binder(),
- NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
- null /* attributionTags */));
- } else {
- handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID,
- /* callOnUnavailable */ false);
- }
- }
-
- private void handleConfigureAlwaysOnNetworks() {
- handleAlwaysOnNetworkRequest(mDefaultMobileDataRequest,
- ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON, true /* defaultValue */);
- handleAlwaysOnNetworkRequest(mDefaultWifiRequest,
- ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED, false /* defaultValue */);
- final boolean vehicleAlwaysRequested = mResources.get().getBoolean(
- R.bool.config_vehicleInternalNetworkAlwaysRequested);
- handleAlwaysOnNetworkRequest(mDefaultVehicleRequest, vehicleAlwaysRequested);
- }
-
- private void registerSettingsCallbacks() {
- // Watch for global HTTP proxy changes.
- mSettingsObserver.observe(
- Settings.Global.getUriFor(Settings.Global.HTTP_PROXY),
- EVENT_APPLY_GLOBAL_HTTP_PROXY);
-
- // Watch for whether or not to keep mobile data always on.
- mSettingsObserver.observe(
- Settings.Global.getUriFor(ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON),
- EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
-
- // Watch for whether or not to keep wifi always on.
- mSettingsObserver.observe(
- Settings.Global.getUriFor(ConnectivitySettingsManager.WIFI_ALWAYS_REQUESTED),
- EVENT_CONFIGURE_ALWAYS_ON_NETWORKS);
- }
-
- private void registerPrivateDnsSettingsCallbacks() {
- for (Uri uri : DnsManager.getPrivateDnsSettingsUris()) {
- mSettingsObserver.observe(uri, EVENT_PRIVATE_DNS_SETTINGS_CHANGED);
- }
- }
-
- private synchronized int nextNetworkRequestId() {
- // TODO: Consider handle wrapping and exclude {@link NetworkRequest#REQUEST_ID_NONE} if
- // doing that.
- return mNextNetworkRequestId++;
- }
-
- @VisibleForTesting
- protected NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) {
- if (network == null) {
- return null;
- }
- return getNetworkAgentInfoForNetId(network.getNetId());
- }
-
- private NetworkAgentInfo getNetworkAgentInfoForNetId(int netId) {
- synchronized (mNetworkForNetId) {
- return mNetworkForNetId.get(netId);
- }
- }
-
- // TODO: determine what to do when more than one VPN applies to |uid|.
- private NetworkAgentInfo getVpnForUid(int uid) {
- synchronized (mNetworkForNetId) {
- for (int i = 0; i < mNetworkForNetId.size(); i++) {
- final NetworkAgentInfo nai = mNetworkForNetId.valueAt(i);
- if (nai.isVPN() && nai.everConnected && nai.networkCapabilities.appliesToUid(uid)) {
- return nai;
- }
- }
- }
- return null;
- }
-
- private Network[] getVpnUnderlyingNetworks(int uid) {
- if (mLockdownEnabled) return null;
- final NetworkAgentInfo nai = getVpnForUid(uid);
- if (nai != null) return nai.declaredUnderlyingNetworks;
- return null;
- }
-
- private NetworkAgentInfo getNetworkAgentInfoForUid(int uid) {
- NetworkAgentInfo nai = getDefaultNetworkForUid(uid);
-
- final Network[] networks = getVpnUnderlyingNetworks(uid);
- if (networks != null) {
- // getUnderlyingNetworks() returns:
- // null => there was no VPN, or the VPN didn't specify anything, so we use the default.
- // empty array => the VPN explicitly said "no default network".
- // non-empty array => the VPN specified one or more default networks; we use the
- // first one.
- if (networks.length > 0) {
- nai = getNetworkAgentInfoForNetwork(networks[0]);
- } else {
- nai = null;
- }
- }
- return nai;
- }
-
- /**
- * Check if UID should be blocked from using the specified network.
- */
- private boolean isNetworkWithCapabilitiesBlocked(@Nullable final NetworkCapabilities nc,
- final int uid, final boolean ignoreBlocked) {
- // Networks aren't blocked when ignoring blocked status
- if (ignoreBlocked) {
- return false;
- }
- if (isUidBlockedByVpn(uid, mVpnBlockedUidRanges)) return true;
- final long ident = Binder.clearCallingIdentity();
- try {
- final boolean metered = nc == null ? true : nc.isMetered();
- return mPolicyManager.isUidNetworkingBlocked(uid, metered);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- private void maybeLogBlockedNetworkInfo(NetworkInfo ni, int uid) {
- if (ni == null || !LOGD_BLOCKED_NETWORKINFO) {
- return;
- }
- final boolean blocked;
- synchronized (mBlockedAppUids) {
- if (ni.getDetailedState() == DetailedState.BLOCKED && mBlockedAppUids.add(uid)) {
- blocked = true;
- } else if (ni.isConnected() && mBlockedAppUids.remove(uid)) {
- blocked = false;
- } else {
- return;
- }
- }
- String action = blocked ? "BLOCKED" : "UNBLOCKED";
- log(String.format("Returning %s NetworkInfo to uid=%d", action, uid));
- mNetworkInfoBlockingLogs.log(action + " " + uid);
- }
-
- private void maybeLogBlockedStatusChanged(NetworkRequestInfo nri, Network net, int blocked) {
- if (nri == null || net == null || !LOGD_BLOCKED_NETWORKINFO) {
- return;
- }
- final String action = (blocked != 0) ? "BLOCKED" : "UNBLOCKED";
- final int requestId = nri.getActiveRequest() != null
- ? nri.getActiveRequest().requestId : nri.mRequests.get(0).requestId;
- mNetworkInfoBlockingLogs.log(String.format(
- "%s %d(%d) on netId %d: %s", action, nri.mAsUid, requestId, net.getNetId(),
- Integer.toHexString(blocked)));
- }
-
- /**
- * Apply any relevant filters to the specified {@link NetworkInfo} for the given UID. For
- * example, this may mark the network as {@link DetailedState#BLOCKED} based
- * on {@link #isNetworkWithCapabilitiesBlocked}.
- */
- @NonNull
- private NetworkInfo filterNetworkInfo(@NonNull NetworkInfo networkInfo, int type,
- @NonNull NetworkCapabilities nc, int uid, boolean ignoreBlocked) {
- final NetworkInfo filtered = new NetworkInfo(networkInfo);
- // Many legacy types (e.g,. TYPE_MOBILE_HIPRI) are not actually a property of the network
- // but only exists if an app asks about them or requests them. Ensure the requesting app
- // gets the type it asks for.
- filtered.setType(type);
- if (isNetworkWithCapabilitiesBlocked(nc, uid, ignoreBlocked)) {
- filtered.setDetailedState(DetailedState.BLOCKED, null /* reason */,
- null /* extraInfo */);
- }
- filterForLegacyLockdown(filtered);
- return filtered;
- }
-
- private NetworkInfo getFilteredNetworkInfo(NetworkAgentInfo nai, int uid,
- boolean ignoreBlocked) {
- return filterNetworkInfo(nai.networkInfo, nai.networkInfo.getType(),
- nai.networkCapabilities, uid, ignoreBlocked);
- }
-
- /**
- * Return NetworkInfo for the active (i.e., connected) network interface.
- * It is assumed that at most one network is active at a time. If more
- * than one is active, it is indeterminate which will be returned.
- * @return the info for the active network, or {@code null} if none is
- * active
- */
- @Override
- public NetworkInfo getActiveNetworkInfo() {
- enforceAccessPermission();
- final int uid = mDeps.getCallingUid();
- final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid);
- if (nai == null) return null;
- final NetworkInfo networkInfo = getFilteredNetworkInfo(nai, uid, false);
- maybeLogBlockedNetworkInfo(networkInfo, uid);
- return networkInfo;
- }
-
- @Override
- public Network getActiveNetwork() {
- enforceAccessPermission();
- return getActiveNetworkForUidInternal(mDeps.getCallingUid(), false);
- }
-
- @Override
- public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) {
- PermissionUtils.enforceNetworkStackPermission(mContext);
- return getActiveNetworkForUidInternal(uid, ignoreBlocked);
- }
-
- private Network getActiveNetworkForUidInternal(final int uid, boolean ignoreBlocked) {
- final NetworkAgentInfo vpnNai = getVpnForUid(uid);
- if (vpnNai != null) {
- final NetworkCapabilities requiredCaps = createDefaultNetworkCapabilitiesForUid(uid);
- if (requiredCaps.satisfiedByNetworkCapabilities(vpnNai.networkCapabilities)) {
- return vpnNai.network;
- }
- }
-
- NetworkAgentInfo nai = getDefaultNetworkForUid(uid);
- if (nai == null || isNetworkWithCapabilitiesBlocked(nai.networkCapabilities, uid,
- ignoreBlocked)) {
- return null;
- }
- return nai.network;
- }
-
- @Override
- public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) {
- PermissionUtils.enforceNetworkStackPermission(mContext);
- final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid);
- if (nai == null) return null;
- return getFilteredNetworkInfo(nai, uid, ignoreBlocked);
- }
-
- /** Returns a NetworkInfo object for a network that doesn't exist. */
- private NetworkInfo makeFakeNetworkInfo(int networkType, int uid) {
- final NetworkInfo info = new NetworkInfo(networkType, 0 /* subtype */,
- getNetworkTypeName(networkType), "" /* subtypeName */);
- info.setIsAvailable(true);
- // For compatibility with legacy code, return BLOCKED instead of DISCONNECTED when
- // background data is restricted.
- final NetworkCapabilities nc = new NetworkCapabilities(); // Metered.
- final DetailedState state = isNetworkWithCapabilitiesBlocked(nc, uid, false)
- ? DetailedState.BLOCKED
- : DetailedState.DISCONNECTED;
- info.setDetailedState(state, null /* reason */, null /* extraInfo */);
- filterForLegacyLockdown(info);
- return info;
- }
-
- private NetworkInfo getFilteredNetworkInfoForType(int networkType, int uid) {
- if (!mLegacyTypeTracker.isTypeSupported(networkType)) {
- return null;
- }
- final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
- if (nai == null) {
- return makeFakeNetworkInfo(networkType, uid);
- }
- return filterNetworkInfo(nai.networkInfo, networkType, nai.networkCapabilities, uid,
- false);
- }
-
- @Override
- public NetworkInfo getNetworkInfo(int networkType) {
- enforceAccessPermission();
- final int uid = mDeps.getCallingUid();
- if (getVpnUnderlyingNetworks(uid) != null) {
- // A VPN is active, so we may need to return one of its underlying networks. This
- // information is not available in LegacyTypeTracker, so we have to get it from
- // getNetworkAgentInfoForUid.
- final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid);
- if (nai == null) return null;
- final NetworkInfo networkInfo = getFilteredNetworkInfo(nai, uid, false);
- if (networkInfo.getType() == networkType) {
- return networkInfo;
- }
- }
- return getFilteredNetworkInfoForType(networkType, uid);
- }
-
- @Override
- public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) {
- enforceAccessPermission();
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai == null) return null;
- return getFilteredNetworkInfo(nai, uid, ignoreBlocked);
- }
-
- @Override
- public NetworkInfo[] getAllNetworkInfo() {
- enforceAccessPermission();
- final ArrayList<NetworkInfo> result = new ArrayList<>();
- for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE;
- networkType++) {
- NetworkInfo info = getNetworkInfo(networkType);
- if (info != null) {
- result.add(info);
- }
- }
- return result.toArray(new NetworkInfo[result.size()]);
- }
-
- @Override
- public Network getNetworkForType(int networkType) {
- enforceAccessPermission();
- if (!mLegacyTypeTracker.isTypeSupported(networkType)) {
- return null;
- }
- final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
- if (nai == null) {
- return null;
- }
- final int uid = mDeps.getCallingUid();
- if (isNetworkWithCapabilitiesBlocked(nai.networkCapabilities, uid, false)) {
- return null;
- }
- return nai.network;
- }
-
- @Override
- public Network[] getAllNetworks() {
- enforceAccessPermission();
- synchronized (mNetworkForNetId) {
- final Network[] result = new Network[mNetworkForNetId.size()];
- for (int i = 0; i < mNetworkForNetId.size(); i++) {
- result[i] = mNetworkForNetId.valueAt(i).network;
- }
- return result;
- }
- }
-
- @Override
- public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
- int userId, String callingPackageName, @Nullable String callingAttributionTag) {
- // The basic principle is: if an app's traffic could possibly go over a
- // network, without the app doing anything multinetwork-specific,
- // (hence, by "default"), then include that network's capabilities in
- // the array.
- //
- // In the normal case, app traffic only goes over the system's default
- // network connection, so that's the only network returned.
- //
- // With a VPN in force, some app traffic may go into the VPN, and thus
- // over whatever underlying networks the VPN specifies, while other app
- // traffic may go over the system default network (e.g.: a split-tunnel
- // VPN, or an app disallowed by the VPN), so the set of networks
- // returned includes the VPN's underlying networks and the system
- // default.
- enforceAccessPermission();
-
- HashMap<Network, NetworkCapabilities> result = new HashMap<>();
-
- for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
- if (!nri.isBeingSatisfied()) {
- continue;
- }
- final NetworkAgentInfo nai = nri.getSatisfier();
- final NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
- if (null != nc
- && nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
- && !result.containsKey(nai.network)) {
- result.put(
- nai.network,
- createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, false /* includeLocationSensitiveInfo */,
- getCallingPid(), mDeps.getCallingUid(), callingPackageName,
- callingAttributionTag));
- }
- }
-
- // No need to check mLockdownEnabled. If it's true, getVpnUnderlyingNetworks returns null.
- final Network[] networks = getVpnUnderlyingNetworks(mDeps.getCallingUid());
- if (null != networks) {
- for (final Network network : networks) {
- final NetworkCapabilities nc = getNetworkCapabilitiesInternal(network);
- if (null != nc) {
- result.put(
- network,
- createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc,
- false /* includeLocationSensitiveInfo */,
- getCallingPid(), mDeps.getCallingUid(), callingPackageName,
- callingAttributionTag));
- }
- }
- }
-
- NetworkCapabilities[] out = new NetworkCapabilities[result.size()];
- out = result.values().toArray(out);
- return out;
- }
-
- @Override
- public boolean isNetworkSupported(int networkType) {
- enforceAccessPermission();
- return mLegacyTypeTracker.isTypeSupported(networkType);
- }
-
- /**
- * Return LinkProperties for the active (i.e., connected) default
- * network interface for the calling uid.
- * @return the ip properties for the active network, or {@code null} if
- * none is active
- */
- @Override
- public LinkProperties getActiveLinkProperties() {
- enforceAccessPermission();
- final int uid = mDeps.getCallingUid();
- NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid);
- if (nai == null) return null;
- return linkPropertiesRestrictedForCallerPermissions(nai.linkProperties,
- Binder.getCallingPid(), uid);
- }
-
- @Override
- public LinkProperties getLinkPropertiesForType(int networkType) {
- enforceAccessPermission();
- NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
- final LinkProperties lp = getLinkProperties(nai);
- if (lp == null) return null;
- return linkPropertiesRestrictedForCallerPermissions(
- lp, Binder.getCallingPid(), mDeps.getCallingUid());
- }
-
- // TODO - this should be ALL networks
- @Override
- public LinkProperties getLinkProperties(Network network) {
- enforceAccessPermission();
- final LinkProperties lp = getLinkProperties(getNetworkAgentInfoForNetwork(network));
- if (lp == null) return null;
- return linkPropertiesRestrictedForCallerPermissions(
- lp, Binder.getCallingPid(), mDeps.getCallingUid());
- }
-
- @Nullable
- private LinkProperties getLinkProperties(@Nullable NetworkAgentInfo nai) {
- if (nai == null) {
- return null;
- }
- synchronized (nai) {
- return nai.linkProperties;
- }
- }
-
- private NetworkCapabilities getNetworkCapabilitiesInternal(Network network) {
- return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
- }
-
- private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
- if (nai == null) return null;
- synchronized (nai) {
- return networkCapabilitiesRestrictedForCallerPermissions(
- nai.networkCapabilities, Binder.getCallingPid(), mDeps.getCallingUid());
- }
- }
-
- @Override
- public NetworkCapabilities getNetworkCapabilities(Network network, String callingPackageName,
- @Nullable String callingAttributionTag) {
- mAppOpsManager.checkPackage(mDeps.getCallingUid(), callingPackageName);
- enforceAccessPermission();
- return createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- getNetworkCapabilitiesInternal(network),
- false /* includeLocationSensitiveInfo */,
- getCallingPid(), mDeps.getCallingUid(), callingPackageName, callingAttributionTag);
- }
-
- @VisibleForTesting
- NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions(
- NetworkCapabilities nc, int callerPid, int callerUid) {
- final NetworkCapabilities newNc = new NetworkCapabilities(nc);
- if (!checkSettingsPermission(callerPid, callerUid)) {
- newNc.setUids(null);
- newNc.setSSID(null);
- }
- if (newNc.getNetworkSpecifier() != null) {
- newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
- }
- newNc.setAdministratorUids(new int[0]);
- if (!checkAnyPermissionOf(
- callerPid, callerUid, android.Manifest.permission.NETWORK_FACTORY)) {
- newNc.setSubscriptionIds(Collections.emptySet());
- }
-
- return newNc;
- }
-
- /**
- * Wrapper used to cache the permission check results performed for the corresponding
- * app. This avoid performing multiple permission checks for different fields in
- * NetworkCapabilities.
- * Note: This wrapper does not support any sort of invalidation and thus must not be
- * persistent or long-lived. It may only be used for the time necessary to
- * compute the redactions required by one particular NetworkCallback or
- * synchronous call.
- */
- private class RedactionPermissionChecker {
- private final int mCallingPid;
- private final int mCallingUid;
- @NonNull private final String mCallingPackageName;
- @Nullable private final String mCallingAttributionTag;
-
- private Boolean mHasLocationPermission = null;
- private Boolean mHasLocalMacAddressPermission = null;
- private Boolean mHasSettingsPermission = null;
-
- RedactionPermissionChecker(int callingPid, int callingUid,
- @NonNull String callingPackageName, @Nullable String callingAttributionTag) {
- mCallingPid = callingPid;
- mCallingUid = callingUid;
- mCallingPackageName = callingPackageName;
- mCallingAttributionTag = callingAttributionTag;
- }
-
- private boolean hasLocationPermissionInternal() {
- final long token = Binder.clearCallingIdentity();
- try {
- return mLocationPermissionChecker.checkLocationPermission(
- mCallingPackageName, mCallingAttributionTag, mCallingUid,
- null /* message */);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /**
- * Returns whether the app holds location permission or not (might return cached result
- * if the permission was already checked before).
- */
- public boolean hasLocationPermission() {
- if (mHasLocationPermission == null) {
- // If there is no cached result, perform the check now.
- mHasLocationPermission = hasLocationPermissionInternal();
- }
- return mHasLocationPermission;
- }
-
- /**
- * Returns whether the app holds local mac address permission or not (might return cached
- * result if the permission was already checked before).
- */
- public boolean hasLocalMacAddressPermission() {
- if (mHasLocalMacAddressPermission == null) {
- // If there is no cached result, perform the check now.
- mHasLocalMacAddressPermission =
- checkLocalMacAddressPermission(mCallingPid, mCallingUid);
- }
- return mHasLocalMacAddressPermission;
- }
-
- /**
- * Returns whether the app holds settings permission or not (might return cached
- * result if the permission was already checked before).
- */
- public boolean hasSettingsPermission() {
- if (mHasSettingsPermission == null) {
- // If there is no cached result, perform the check now.
- mHasSettingsPermission = checkSettingsPermission(mCallingPid, mCallingUid);
- }
- return mHasSettingsPermission;
- }
- }
-
- private static boolean shouldRedact(@NetworkCapabilities.RedactionType long redactions,
- @NetworkCapabilities.NetCapability long redaction) {
- return (redactions & redaction) != 0;
- }
-
- /**
- * Use the provided |applicableRedactions| to check the receiving app's
- * permissions and clear/set the corresponding bit in the returned bitmask. The bitmask
- * returned will be used to ensure the necessary redactions are performed by NetworkCapabilities
- * before being sent to the corresponding app.
- */
- private @NetworkCapabilities.RedactionType long retrieveRequiredRedactions(
- @NetworkCapabilities.RedactionType long applicableRedactions,
- @NonNull RedactionPermissionChecker redactionPermissionChecker,
- boolean includeLocationSensitiveInfo) {
- long redactions = applicableRedactions;
- if (shouldRedact(redactions, REDACT_FOR_ACCESS_FINE_LOCATION)) {
- if (includeLocationSensitiveInfo
- && redactionPermissionChecker.hasLocationPermission()) {
- redactions &= ~REDACT_FOR_ACCESS_FINE_LOCATION;
- }
- }
- if (shouldRedact(redactions, REDACT_FOR_LOCAL_MAC_ADDRESS)) {
- if (redactionPermissionChecker.hasLocalMacAddressPermission()) {
- redactions &= ~REDACT_FOR_LOCAL_MAC_ADDRESS;
- }
- }
- if (shouldRedact(redactions, REDACT_FOR_NETWORK_SETTINGS)) {
- if (redactionPermissionChecker.hasSettingsPermission()) {
- redactions &= ~REDACT_FOR_NETWORK_SETTINGS;
- }
- }
- return redactions;
- }
-
- @VisibleForTesting
- @Nullable
- NetworkCapabilities createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- @Nullable NetworkCapabilities nc, boolean includeLocationSensitiveInfo,
- int callingPid, int callingUid, @NonNull String callingPkgName,
- @Nullable String callingAttributionTag) {
- if (nc == null) {
- return null;
- }
- // Avoid doing location permission check if the transport info has no location sensitive
- // data.
- final RedactionPermissionChecker redactionPermissionChecker =
- new RedactionPermissionChecker(callingPid, callingUid, callingPkgName,
- callingAttributionTag);
- final long redactions = retrieveRequiredRedactions(
- nc.getApplicableRedactions(), redactionPermissionChecker,
- includeLocationSensitiveInfo);
- final NetworkCapabilities newNc = new NetworkCapabilities(nc, redactions);
- // Reset owner uid if not destined for the owner app.
- if (callingUid != nc.getOwnerUid()) {
- newNc.setOwnerUid(INVALID_UID);
- return newNc;
- }
- // Allow VPNs to see ownership of their own VPN networks - not location sensitive.
- if (nc.hasTransport(TRANSPORT_VPN)) {
- // Owner UIDs already checked above. No need to re-check.
- return newNc;
- }
- // If the calling does not want location sensitive data & target SDK >= S, then mask info.
- // Else include the owner UID iff the calling has location permission to provide backwards
- // compatibility for older apps.
- if (!includeLocationSensitiveInfo
- && isTargetSdkAtleast(
- Build.VERSION_CODES.S, callingUid, callingPkgName)) {
- newNc.setOwnerUid(INVALID_UID);
- return newNc;
- }
- // Reset owner uid if the app has no location permission.
- if (!redactionPermissionChecker.hasLocationPermission()) {
- newNc.setOwnerUid(INVALID_UID);
- }
- return newNc;
- }
-
- private LinkProperties linkPropertiesRestrictedForCallerPermissions(
- LinkProperties lp, int callerPid, int callerUid) {
- if (lp == null) return new LinkProperties();
-
- // Only do a permission check if sanitization is needed, to avoid unnecessary binder calls.
- final boolean needsSanitization =
- (lp.getCaptivePortalApiUrl() != null || lp.getCaptivePortalData() != null);
- if (!needsSanitization) {
- return new LinkProperties(lp);
- }
-
- if (checkSettingsPermission(callerPid, callerUid)) {
- return new LinkProperties(lp, true /* parcelSensitiveFields */);
- }
-
- final LinkProperties newLp = new LinkProperties(lp);
- // Sensitive fields would not be parceled anyway, but sanitize for consistency before the
- // object gets parceled.
- newLp.setCaptivePortalApiUrl(null);
- newLp.setCaptivePortalData(null);
- return newLp;
- }
-
- private void restrictRequestUidsForCallerAndSetRequestorInfo(NetworkCapabilities nc,
- int callerUid, String callerPackageName) {
- // There is no need to track the effective UID of the request here. If the caller
- // lacks the settings permission, the effective UID is the same as the calling ID.
- if (!checkSettingsPermission()) {
- // Unprivileged apps can only pass in null or their own UID.
- if (nc.getUids() == null) {
- // If the caller passes in null, the callback will also match networks that do not
- // apply to its UID, similarly to what it would see if it called getAllNetworks.
- // In this case, redact everything in the request immediately. This ensures that the
- // app is not able to get any redacted information by filing an unredacted request
- // and observing whether the request matches something.
- if (nc.getNetworkSpecifier() != null) {
- nc.setNetworkSpecifier(nc.getNetworkSpecifier().redact());
- }
- } else {
- nc.setSingleUid(callerUid);
- }
- }
- nc.setRequestorUidAndPackageName(callerUid, callerPackageName);
- nc.setAdministratorUids(new int[0]);
-
- // Clear owner UID; this can never come from an app.
- nc.setOwnerUid(INVALID_UID);
- }
-
- private void restrictBackgroundRequestForCaller(NetworkCapabilities nc) {
- if (!mPermissionMonitor.hasUseBackgroundNetworksPermission(mDeps.getCallingUid())) {
- nc.addCapability(NET_CAPABILITY_FOREGROUND);
- }
- }
-
- @Override
- public @RestrictBackgroundStatus int getRestrictBackgroundStatusByCaller() {
- enforceAccessPermission();
- final int callerUid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- return mPolicyManager.getRestrictBackgroundStatus(callerUid);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- // TODO: Consider delete this function or turn it into a no-op method.
- @Override
- public NetworkState[] getAllNetworkState() {
- // This contains IMSI details, so make sure the caller is privileged.
- PermissionUtils.enforceNetworkStackPermission(mContext);
-
- final ArrayList<NetworkState> result = new ArrayList<>();
- for (NetworkStateSnapshot snapshot : getAllNetworkStateSnapshots()) {
- // NetworkStateSnapshot doesn't contain NetworkInfo, so need to fetch it from the
- // NetworkAgentInfo.
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(snapshot.getNetwork());
- if (nai != null && nai.networkInfo.isConnected()) {
- result.add(new NetworkState(new NetworkInfo(nai.networkInfo),
- snapshot.getLinkProperties(), snapshot.getNetworkCapabilities(),
- snapshot.getNetwork(), snapshot.getSubscriberId()));
- }
- }
- return result.toArray(new NetworkState[result.size()]);
- }
-
- @Override
- @NonNull
- public List<NetworkStateSnapshot> getAllNetworkStateSnapshots() {
- // This contains IMSI details, so make sure the caller is privileged.
- enforceNetworkStackOrSettingsPermission();
-
- final ArrayList<NetworkStateSnapshot> result = new ArrayList<>();
- for (Network network : getAllNetworks()) {
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- // TODO: Consider include SUSPENDED networks, which should be considered as
- // temporary shortage of connectivity of a connected network.
- if (nai != null && nai.networkInfo.isConnected()) {
- // TODO (b/73321673) : NetworkStateSnapshot contains a copy of the
- // NetworkCapabilities, which may contain UIDs of apps to which the
- // network applies. Should the UIDs be cleared so as not to leak or
- // interfere ?
- result.add(nai.getNetworkStateSnapshot());
- }
- }
- return result;
- }
-
- @Override
- public boolean isActiveNetworkMetered() {
- enforceAccessPermission();
-
- final NetworkCapabilities caps = getNetworkCapabilitiesInternal(getActiveNetwork());
- if (caps != null) {
- return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- } else {
- // Always return the most conservative value
- return true;
- }
- }
-
- /**
- * Ensures that the system cannot call a particular method.
- */
- private boolean disallowedBecauseSystemCaller() {
- // TODO: start throwing a SecurityException when GnssLocationProvider stops calling
- // requestRouteToHost. In Q, GnssLocationProvider is changed to not call requestRouteToHost
- // for devices launched with Q and above. However, existing devices upgrading to Q and
- // above must continued to be supported for few more releases.
- if (isSystem(mDeps.getCallingUid()) && SystemProperties.getInt(
- "ro.product.first_api_level", 0) > Build.VERSION_CODES.P) {
- log("This method exists only for app backwards compatibility"
- + " and must not be called by system services.");
- return true;
- }
- return false;
- }
-
- /**
- * Ensure that a network route exists to deliver traffic to the specified
- * host via the specified network interface.
- * @param networkType the type of the network over which traffic to the
- * specified host is to be routed
- * @param hostAddress the IP address of the host to which the route is
- * desired
- * @return {@code true} on success, {@code false} on failure
- */
- @Override
- public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress,
- String callingPackageName, String callingAttributionTag) {
- if (disallowedBecauseSystemCaller()) {
- return false;
- }
- enforceChangePermission(callingPackageName, callingAttributionTag);
- if (mProtectedNetworks.contains(networkType)) {
- enforceConnectivityRestrictedNetworksPermission();
- }
-
- InetAddress addr;
- try {
- addr = InetAddress.getByAddress(hostAddress);
- } catch (UnknownHostException e) {
- if (DBG) log("requestRouteToHostAddress got " + e.toString());
- return false;
- }
-
- if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
- if (DBG) log("requestRouteToHostAddress on invalid network: " + networkType);
- return false;
- }
-
- NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
- if (nai == null) {
- if (mLegacyTypeTracker.isTypeSupported(networkType) == false) {
- if (DBG) log("requestRouteToHostAddress on unsupported network: " + networkType);
- } else {
- if (DBG) log("requestRouteToHostAddress on down network: " + networkType);
- }
- return false;
- }
-
- DetailedState netState;
- synchronized (nai) {
- netState = nai.networkInfo.getDetailedState();
- }
-
- if (netState != DetailedState.CONNECTED && netState != DetailedState.CAPTIVE_PORTAL_CHECK) {
- if (VDBG) {
- log("requestRouteToHostAddress on down network "
- + "(" + networkType + ") - dropped"
- + " netState=" + netState);
- }
- return false;
- }
-
- final int uid = mDeps.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- LinkProperties lp;
- int netId;
- synchronized (nai) {
- lp = nai.linkProperties;
- netId = nai.network.getNetId();
- }
- boolean ok = addLegacyRouteToHost(lp, addr, netId, uid);
- if (DBG) {
- log("requestRouteToHostAddress " + addr + nai.toShortString() + " ok=" + ok);
- }
- return ok;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- private boolean addLegacyRouteToHost(LinkProperties lp, InetAddress addr, int netId, int uid) {
- RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr);
- if (bestRoute == null) {
- bestRoute = RouteInfo.makeHostRoute(addr, lp.getInterfaceName());
- } else {
- String iface = bestRoute.getInterface();
- if (bestRoute.getGateway().equals(addr)) {
- // if there is no better route, add the implied hostroute for our gateway
- bestRoute = RouteInfo.makeHostRoute(addr, iface);
- } else {
- // if we will connect to this through another route, add a direct route
- // to it's gateway
- bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface);
- }
- }
- if (DBG) log("Adding legacy route " + bestRoute +
- " for UID/PID " + uid + "/" + Binder.getCallingPid());
-
- final String dst = bestRoute.getDestinationLinkAddress().toString();
- final String nextHop = bestRoute.hasGateway()
- ? bestRoute.getGateway().getHostAddress() : "";
- try {
- mNetd.networkAddLegacyRoute(netId, bestRoute.getInterface(), dst, nextHop , uid);
- } catch (RemoteException | ServiceSpecificException e) {
- if (DBG) loge("Exception trying to add a route: " + e);
- return false;
- }
- return true;
- }
-
- class DnsResolverUnsolicitedEventCallback extends
- IDnsResolverUnsolicitedEventListener.Stub {
- @Override
- public void onPrivateDnsValidationEvent(final PrivateDnsValidationEventParcel event) {
- try {
- mHandler.sendMessage(mHandler.obtainMessage(
- EVENT_PRIVATE_DNS_VALIDATION_UPDATE,
- new PrivateDnsValidationUpdate(event.netId,
- InetAddresses.parseNumericAddress(event.ipAddress),
- event.hostname, event.validation)));
- } catch (IllegalArgumentException e) {
- loge("Error parsing ip address in validation event");
- }
- }
-
- @Override
- public void onDnsHealthEvent(final DnsHealthEventParcel event) {
- NetworkAgentInfo nai = getNetworkAgentInfoForNetId(event.netId);
- // Netd event only allow registrants from system. Each NetworkMonitor thread is under
- // the caller thread of registerNetworkAgent. Thus, it's not allowed to register netd
- // event callback for certain nai. e.g. cellular. Register here to pass to
- // NetworkMonitor instead.
- // TODO: Move the Dns Event to NetworkMonitor. NetdEventListenerService only allow one
- // callback from each caller type. Need to re-factor NetdEventListenerService to allow
- // multiple NetworkMonitor registrants.
- if (nai != null && nai.satisfies(mDefaultRequest.mRequests.get(0))) {
- nai.networkMonitor().notifyDnsResponse(event.healthResult);
- }
- }
-
- @Override
- public void onNat64PrefixEvent(final Nat64PrefixEventParcel event) {
- mHandler.post(() -> handleNat64PrefixEvent(event.netId, event.prefixOperation,
- event.prefixAddress, event.prefixLength));
- }
-
- @Override
- public int getInterfaceVersion() {
- return this.VERSION;
- }
-
- @Override
- public String getInterfaceHash() {
- return this.HASH;
- }
- }
-
- @VisibleForTesting
- protected final DnsResolverUnsolicitedEventCallback mResolverUnsolEventCallback =
- new DnsResolverUnsolicitedEventCallback();
-
- private void registerDnsResolverUnsolicitedEventListener() {
- try {
- mDnsResolver.registerUnsolicitedEventListener(mResolverUnsolEventCallback);
- } catch (Exception e) {
- loge("Error registering DnsResolver unsolicited event callback: " + e);
- }
- }
-
- private final NetworkPolicyCallback mPolicyCallback = new NetworkPolicyCallback() {
- @Override
- public void onUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_BLOCKED_REASON_CHANGED,
- uid, blockedReasons));
- }
- };
-
- private void handleUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {
- maybeNotifyNetworkBlockedForNewState(uid, blockedReasons);
- setUidBlockedReasons(uid, blockedReasons);
- }
-
- private boolean checkAnyPermissionOf(String... permissions) {
- for (String permission : permissions) {
- if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
- return true;
- }
- }
- return false;
- }
-
- private boolean checkAnyPermissionOf(int pid, int uid, String... permissions) {
- for (String permission : permissions) {
- if (mContext.checkPermission(permission, pid, uid) == PERMISSION_GRANTED) {
- return true;
- }
- }
- return false;
- }
-
- private void enforceAnyPermissionOf(String... permissions) {
- if (!checkAnyPermissionOf(permissions)) {
- throw new SecurityException("Requires one of the following permissions: "
- + String.join(", ", permissions) + ".");
- }
- }
-
- private void enforceInternetPermission() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERNET,
- "ConnectivityService");
- }
-
- private void enforceAccessPermission() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.ACCESS_NETWORK_STATE,
- "ConnectivityService");
- }
-
- /**
- * Performs a strict and comprehensive check of whether a calling package is allowed to
- * change the state of network, as the condition differs for pre-M, M+, and
- * privileged/preinstalled apps. The caller is expected to have either the
- * CHANGE_NETWORK_STATE or the WRITE_SETTINGS permission declared. Either of these
- * permissions allow changing network state; WRITE_SETTINGS is a runtime permission and
- * can be revoked, but (except in M, excluding M MRs), CHANGE_NETWORK_STATE is a normal
- * permission and cannot be revoked. See http://b/23597341
- *
- * Note: if the check succeeds because the application holds WRITE_SETTINGS, the operation
- * of this app will be updated to the current time.
- */
- private void enforceChangePermission(String callingPkg, String callingAttributionTag) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE)
- == PackageManager.PERMISSION_GRANTED) {
- return;
- }
-
- if (callingPkg == null) {
- throw new SecurityException("Calling package name is null.");
- }
-
- final AppOpsManager appOpsMgr = mContext.getSystemService(AppOpsManager.class);
- final int uid = mDeps.getCallingUid();
- final int mode = appOpsMgr.noteOpNoThrow(AppOpsManager.OPSTR_WRITE_SETTINGS, uid,
- callingPkg, callingAttributionTag, null /* message */);
-
- if (mode == AppOpsManager.MODE_ALLOWED) {
- return;
- }
-
- if ((mode == AppOpsManager.MODE_DEFAULT) && (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.WRITE_SETTINGS) == PackageManager.PERMISSION_GRANTED)) {
- return;
- }
-
- throw new SecurityException(callingPkg + " was not granted either of these permissions:"
- + android.Manifest.permission.CHANGE_NETWORK_STATE + ","
- + android.Manifest.permission.WRITE_SETTINGS + ".");
- }
-
- private void enforceSettingsPermission() {
- enforceAnyPermissionOf(
- android.Manifest.permission.NETWORK_SETTINGS,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
- }
-
- private void enforceNetworkFactoryPermission() {
- enforceAnyPermissionOf(
- android.Manifest.permission.NETWORK_FACTORY,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
- }
-
- private void enforceNetworkFactoryOrSettingsPermission() {
- enforceAnyPermissionOf(
- android.Manifest.permission.NETWORK_SETTINGS,
- android.Manifest.permission.NETWORK_FACTORY,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
- }
-
- private void enforceNetworkFactoryOrTestNetworksPermission() {
- enforceAnyPermissionOf(
- android.Manifest.permission.MANAGE_TEST_NETWORKS,
- android.Manifest.permission.NETWORK_FACTORY,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
- }
-
- private boolean checkSettingsPermission() {
- return checkAnyPermissionOf(
- android.Manifest.permission.NETWORK_SETTINGS,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
- }
-
- private boolean checkSettingsPermission(int pid, int uid) {
- return PERMISSION_GRANTED == mContext.checkPermission(
- android.Manifest.permission.NETWORK_SETTINGS, pid, uid)
- || PERMISSION_GRANTED == mContext.checkPermission(
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, pid, uid);
- }
-
- private void enforceNetworkStackOrSettingsPermission() {
- enforceAnyPermissionOf(
- android.Manifest.permission.NETWORK_SETTINGS,
- android.Manifest.permission.NETWORK_STACK,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
- }
-
- private void enforceNetworkStackSettingsOrSetup() {
- enforceAnyPermissionOf(
- android.Manifest.permission.NETWORK_SETTINGS,
- android.Manifest.permission.NETWORK_SETUP_WIZARD,
- android.Manifest.permission.NETWORK_STACK,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
- }
-
- private void enforceAirplaneModePermission() {
- enforceAnyPermissionOf(
- android.Manifest.permission.NETWORK_AIRPLANE_MODE,
- android.Manifest.permission.NETWORK_SETTINGS,
- android.Manifest.permission.NETWORK_SETUP_WIZARD,
- android.Manifest.permission.NETWORK_STACK,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
- }
-
- private void enforceOemNetworkPreferencesPermission() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE,
- "ConnectivityService");
- }
-
- private boolean checkNetworkStackPermission() {
- return checkAnyPermissionOf(
- android.Manifest.permission.NETWORK_STACK,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
- }
-
- private boolean checkNetworkStackPermission(int pid, int uid) {
- return checkAnyPermissionOf(pid, uid,
- android.Manifest.permission.NETWORK_STACK,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
- }
-
- private boolean checkNetworkSignalStrengthWakeupPermission(int pid, int uid) {
- return checkAnyPermissionOf(pid, uid,
- android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_SETTINGS);
- }
-
- private void enforceConnectivityRestrictedNetworksPermission() {
- try {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS,
- "ConnectivityService");
- return;
- } catch (SecurityException e) { /* fallback to ConnectivityInternalPermission */ }
- // TODO: Remove this fallback check after all apps have declared
- // CONNECTIVITY_USE_RESTRICTED_NETWORKS.
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.CONNECTIVITY_INTERNAL,
- "ConnectivityService");
- }
-
- private void enforceKeepalivePermission() {
- mContext.enforceCallingOrSelfPermission(KeepaliveTracker.PERMISSION, "ConnectivityService");
- }
-
- private boolean checkLocalMacAddressPermission(int pid, int uid) {
- return PERMISSION_GRANTED == mContext.checkPermission(
- Manifest.permission.LOCAL_MAC_ADDRESS, pid, uid);
- }
-
- private void sendConnectedBroadcast(NetworkInfo info) {
- sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
- }
-
- private void sendInetConditionBroadcast(NetworkInfo info) {
- sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION);
- }
-
- private Intent makeGeneralIntent(NetworkInfo info, String bcastType) {
- Intent intent = new Intent(bcastType);
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info));
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
- if (info.isFailover()) {
- intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
- info.setFailover(false);
- }
- if (info.getReason() != null) {
- intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
- }
- if (info.getExtraInfo() != null) {
- intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO,
- info.getExtraInfo());
- }
- intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
- return intent;
- }
-
- private void sendGeneralBroadcast(NetworkInfo info, String bcastType) {
- sendStickyBroadcast(makeGeneralIntent(info, bcastType));
- }
-
- private void sendStickyBroadcast(Intent intent) {
- synchronized (this) {
- if (!mSystemReady
- && intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
- mInitialBroadcast = new Intent(intent);
- }
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- if (VDBG) {
- log("sendStickyBroadcast: action=" + intent.getAction());
- }
-
- Bundle options = null;
- final long ident = Binder.clearCallingIdentity();
- if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
- final NetworkInfo ni = intent.getParcelableExtra(
- ConnectivityManager.EXTRA_NETWORK_INFO);
- final BroadcastOptions opts = BroadcastOptions.makeBasic();
- opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.M);
- options = opts.toBundle();
- intent.addFlags(Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
- }
- try {
- mUserAllContext.sendStickyBroadcast(intent, options);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- }
-
- /**
- * Called by SystemServer through ConnectivityManager when the system is ready.
- */
- @Override
- public void systemReady() {
- if (mDeps.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Calling Uid is not system uid.");
- }
- systemReadyInternal();
- }
-
- /**
- * Called when ConnectivityService can initialize remaining components.
- */
- @VisibleForTesting
- public void systemReadyInternal() {
- // Since mApps in PermissionMonitor needs to be populated first to ensure that
- // listening network request which is sent by MultipathPolicyTracker won't be added
- // NET_CAPABILITY_FOREGROUND capability. Thus, MultipathPolicyTracker.start() must
- // be called after PermissionMonitor#startMonitoring().
- // Calling PermissionMonitor#startMonitoring() in systemReadyInternal() and the
- // MultipathPolicyTracker.start() is called in NetworkPolicyManagerService#systemReady()
- // to ensure the tracking will be initialized correctly.
- mPermissionMonitor.startMonitoring();
- mProxyTracker.loadGlobalProxy();
- registerDnsResolverUnsolicitedEventListener();
-
- synchronized (this) {
- mSystemReady = true;
- if (mInitialBroadcast != null) {
- mContext.sendStickyBroadcastAsUser(mInitialBroadcast, UserHandle.ALL);
- mInitialBroadcast = null;
- }
- }
-
- // Create network requests for always-on networks.
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS));
- }
-
- /**
- * Start listening for default data network activity state changes.
- */
- @Override
- public void registerNetworkActivityListener(@NonNull INetworkActivityListener l) {
- mNetworkActivityTracker.registerNetworkActivityListener(l);
- }
-
- /**
- * Stop listening for default data network activity state changes.
- */
- @Override
- public void unregisterNetworkActivityListener(@NonNull INetworkActivityListener l) {
- mNetworkActivityTracker.unregisterNetworkActivityListener(l);
- }
-
- /**
- * Check whether the default network radio is currently active.
- */
- @Override
- public boolean isDefaultNetworkActive() {
- return mNetworkActivityTracker.isDefaultNetworkActive();
- }
-
- /**
- * Reads the network specific MTU size from resources.
- * and set it on it's iface.
- */
- private void updateMtu(LinkProperties newLp, LinkProperties oldLp) {
- final String iface = newLp.getInterfaceName();
- final int mtu = newLp.getMtu();
- if (oldLp == null && mtu == 0) {
- // Silently ignore unset MTU value.
- return;
- }
- if (oldLp != null && newLp.isIdenticalMtu(oldLp)) {
- if (VDBG) log("identical MTU - not setting");
- return;
- }
- if (!LinkProperties.isValidMtu(mtu, newLp.hasGlobalIpv6Address())) {
- if (mtu != 0) loge("Unexpected mtu value: " + mtu + ", " + iface);
- return;
- }
-
- // Cannot set MTU without interface name
- if (TextUtils.isEmpty(iface)) {
- loge("Setting MTU size with null iface.");
- return;
- }
-
- try {
- if (VDBG || DDBG) log("Setting MTU size: " + iface + ", " + mtu);
- mNetd.interfaceSetMtu(iface, mtu);
- } catch (RemoteException | ServiceSpecificException e) {
- loge("exception in interfaceSetMtu()" + e);
- }
- }
-
- @VisibleForTesting
- protected static final String DEFAULT_TCP_BUFFER_SIZES = "4096,87380,110208,4096,16384,110208";
-
- private void updateTcpBufferSizes(String tcpBufferSizes) {
- String[] values = null;
- if (tcpBufferSizes != null) {
- values = tcpBufferSizes.split(",");
- }
-
- if (values == null || values.length != 6) {
- if (DBG) log("Invalid tcpBufferSizes string: " + tcpBufferSizes +", using defaults");
- tcpBufferSizes = DEFAULT_TCP_BUFFER_SIZES;
- values = tcpBufferSizes.split(",");
- }
-
- if (tcpBufferSizes.equals(mCurrentTcpBufferSizes)) return;
-
- try {
- if (VDBG || DDBG) log("Setting tx/rx TCP buffers to " + tcpBufferSizes);
-
- String rmemValues = String.join(" ", values[0], values[1], values[2]);
- String wmemValues = String.join(" ", values[3], values[4], values[5]);
- mNetd.setTcpRWmemorySize(rmemValues, wmemValues);
- mCurrentTcpBufferSizes = tcpBufferSizes;
- } catch (RemoteException | ServiceSpecificException e) {
- loge("Can't set TCP buffer sizes:" + e);
- }
- }
-
- @Override
- public int getRestoreDefaultNetworkDelay(int networkType) {
- String restoreDefaultNetworkDelayStr = mSystemProperties.get(
- NETWORK_RESTORE_DELAY_PROP_NAME);
- if(restoreDefaultNetworkDelayStr != null &&
- restoreDefaultNetworkDelayStr.length() != 0) {
- try {
- return Integer.parseInt(restoreDefaultNetworkDelayStr);
- } catch (NumberFormatException e) {
- }
- }
- // if the system property isn't set, use the value for the apn type
- int ret = RESTORE_DEFAULT_NETWORK_DELAY;
-
- if (mLegacyTypeTracker.isTypeSupported(networkType)) {
- ret = mLegacyTypeTracker.getRestoreTimerForType(networkType);
- }
- return ret;
- }
-
- private void dumpNetworkDiagnostics(IndentingPrintWriter pw) {
- final List<NetworkDiagnostics> netDiags = new ArrayList<NetworkDiagnostics>();
- final long DIAG_TIME_MS = 5000;
- for (NetworkAgentInfo nai : networksSortedById()) {
- PrivateDnsConfig privateDnsCfg = mDnsManager.getPrivateDnsConfig(nai.network);
- // Start gathering diagnostic information.
- netDiags.add(new NetworkDiagnostics(
- nai.network,
- new LinkProperties(nai.linkProperties), // Must be a copy.
- privateDnsCfg,
- DIAG_TIME_MS));
- }
-
- for (NetworkDiagnostics netDiag : netDiags) {
- pw.println();
- netDiag.waitForMeasurements();
- netDiag.dump(pw);
- }
- }
-
- @Override
- protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
- @Nullable String[] args) {
- if (!checkDumpPermission(mContext, TAG, writer)) return;
-
- mPriorityDumper.dump(fd, writer, args);
- }
-
- private boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
- if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump " + tag + " from from pid="
- + Binder.getCallingPid() + ", uid=" + mDeps.getCallingUid()
- + " due to missing android.permission.DUMP permission");
- return false;
- } else {
- return true;
- }
- }
-
- private void doDump(FileDescriptor fd, PrintWriter writer, String[] args) {
- final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
-
- if (CollectionUtils.contains(args, DIAG_ARG)) {
- dumpNetworkDiagnostics(pw);
- return;
- } else if (CollectionUtils.contains(args, NETWORK_ARG)) {
- dumpNetworks(pw);
- return;
- } else if (CollectionUtils.contains(args, REQUEST_ARG)) {
- dumpNetworkRequests(pw);
- return;
- }
-
- pw.print("NetworkProviders for:");
- for (NetworkProviderInfo npi : mNetworkProviderInfos.values()) {
- pw.print(" " + npi.name);
- }
- pw.println();
- pw.println();
-
- final NetworkAgentInfo defaultNai = getDefaultNetwork();
- pw.print("Active default network: ");
- if (defaultNai == null) {
- pw.println("none");
- } else {
- pw.println(defaultNai.network.getNetId());
- }
- pw.println();
-
- pw.print("Current per-app default networks: ");
- pw.increaseIndent();
- dumpPerAppNetworkPreferences(pw);
- pw.decreaseIndent();
- pw.println();
-
- pw.println("Current Networks:");
- pw.increaseIndent();
- dumpNetworks(pw);
- pw.decreaseIndent();
- pw.println();
-
- pw.println("Status for known UIDs:");
- pw.increaseIndent();
- final int size = mUidBlockedReasons.size();
- for (int i = 0; i < size; i++) {
- // Don't crash if the array is modified while dumping in bugreports.
- try {
- final int uid = mUidBlockedReasons.keyAt(i);
- final int blockedReasons = mUidBlockedReasons.valueAt(i);
- pw.println("UID=" + uid + " blockedReasons="
- + Integer.toHexString(blockedReasons));
- } catch (ArrayIndexOutOfBoundsException e) {
- pw.println(" ArrayIndexOutOfBoundsException");
- } catch (ConcurrentModificationException e) {
- pw.println(" ConcurrentModificationException");
- }
- }
- pw.println();
- pw.decreaseIndent();
-
- pw.println("Network Requests:");
- pw.increaseIndent();
- dumpNetworkRequests(pw);
- pw.decreaseIndent();
- pw.println();
-
- mLegacyTypeTracker.dump(pw);
-
- pw.println();
- mKeepaliveTracker.dump(pw);
-
- pw.println();
- dumpAvoidBadWifiSettings(pw);
-
- pw.println();
-
- if (!CollectionUtils.contains(args, SHORT_ARG)) {
- pw.println();
- pw.println("mNetworkRequestInfoLogs (most recent first):");
- pw.increaseIndent();
- mNetworkRequestInfoLogs.reverseDump(pw);
- pw.decreaseIndent();
-
- pw.println();
- pw.println("mNetworkInfoBlockingLogs (most recent first):");
- pw.increaseIndent();
- mNetworkInfoBlockingLogs.reverseDump(pw);
- pw.decreaseIndent();
-
- pw.println();
- pw.println("NetTransition WakeLock activity (most recent first):");
- pw.increaseIndent();
- pw.println("total acquisitions: " + mTotalWakelockAcquisitions);
- pw.println("total releases: " + mTotalWakelockReleases);
- pw.println("cumulative duration: " + (mTotalWakelockDurationMs / 1000) + "s");
- pw.println("longest duration: " + (mMaxWakelockDurationMs / 1000) + "s");
- if (mTotalWakelockAcquisitions > mTotalWakelockReleases) {
- long duration = SystemClock.elapsedRealtime() - mLastWakeLockAcquireTimestamp;
- pw.println("currently holding WakeLock for: " + (duration / 1000) + "s");
- }
- mWakelockLogs.reverseDump(pw);
-
- pw.println();
- pw.println("bandwidth update requests (by uid):");
- pw.increaseIndent();
- synchronized (mBandwidthRequests) {
- for (int i = 0; i < mBandwidthRequests.size(); i++) {
- pw.println("[" + mBandwidthRequests.keyAt(i)
- + "]: " + mBandwidthRequests.valueAt(i));
- }
- }
- pw.decreaseIndent();
- pw.decreaseIndent();
-
- pw.println();
- pw.println("mOemNetworkPreferencesLogs (most recent first):");
- pw.increaseIndent();
- mOemNetworkPreferencesLogs.reverseDump(pw);
- pw.decreaseIndent();
- }
-
- pw.println();
-
- pw.println();
- pw.println("Permission Monitor:");
- pw.increaseIndent();
- mPermissionMonitor.dump(pw);
- pw.decreaseIndent();
-
- pw.println();
- pw.println("Legacy network activity:");
- pw.increaseIndent();
- mNetworkActivityTracker.dump(pw);
- pw.decreaseIndent();
- }
-
- private void dumpNetworks(IndentingPrintWriter pw) {
- for (NetworkAgentInfo nai : networksSortedById()) {
- pw.println(nai.toString());
- pw.increaseIndent();
- pw.println(String.format(
- "Requests: REQUEST:%d LISTEN:%d BACKGROUND_REQUEST:%d total:%d",
- nai.numForegroundNetworkRequests(),
- nai.numNetworkRequests() - nai.numRequestNetworkRequests(),
- nai.numBackgroundNetworkRequests(),
- nai.numNetworkRequests()));
- pw.increaseIndent();
- for (int i = 0; i < nai.numNetworkRequests(); i++) {
- pw.println(nai.requestAt(i).toString());
- }
- pw.decreaseIndent();
- pw.println("Inactivity Timers:");
- pw.increaseIndent();
- nai.dumpInactivityTimers(pw);
- pw.decreaseIndent();
- pw.decreaseIndent();
- }
- }
-
- private void dumpPerAppNetworkPreferences(IndentingPrintWriter pw) {
- pw.println("Per-App Network Preference:");
- pw.increaseIndent();
- if (0 == mOemNetworkPreferences.getNetworkPreferences().size()) {
- pw.println("none");
- } else {
- pw.println(mOemNetworkPreferences.toString());
- }
- pw.decreaseIndent();
-
- for (final NetworkRequestInfo defaultRequest : mDefaultNetworkRequests) {
- if (mDefaultRequest == defaultRequest) {
- continue;
- }
-
- final boolean isActive = null != defaultRequest.getSatisfier();
- pw.println("Is per-app network active:");
- pw.increaseIndent();
- pw.println(isActive);
- if (isActive) {
- pw.println("Active network: " + defaultRequest.getSatisfier().network.netId);
- }
- pw.println("Tracked UIDs:");
- pw.increaseIndent();
- if (0 == defaultRequest.mRequests.size()) {
- pw.println("none, this should never occur.");
- } else {
- pw.println(defaultRequest.mRequests.get(0).networkCapabilities.getUidRanges());
- }
- pw.decreaseIndent();
- pw.decreaseIndent();
- }
- }
-
- private void dumpNetworkRequests(IndentingPrintWriter pw) {
- for (NetworkRequestInfo nri : requestsSortedById()) {
- pw.println(nri.toString());
- }
- }
-
- /**
- * Return an array of all current NetworkAgentInfos sorted by network id.
- */
- private NetworkAgentInfo[] networksSortedById() {
- NetworkAgentInfo[] networks = new NetworkAgentInfo[0];
- networks = mNetworkAgentInfos.toArray(networks);
- Arrays.sort(networks, Comparator.comparingInt(nai -> nai.network.getNetId()));
- return networks;
- }
-
- /**
- * Return an array of all current NetworkRequest sorted by request id.
- */
- @VisibleForTesting
- NetworkRequestInfo[] requestsSortedById() {
- NetworkRequestInfo[] requests = new NetworkRequestInfo[0];
- requests = getNrisFromGlobalRequests().toArray(requests);
- // Sort the array based off the NRI containing the min requestId in its requests.
- Arrays.sort(requests,
- Comparator.comparingInt(nri -> Collections.min(nri.mRequests,
- Comparator.comparingInt(req -> req.requestId)).requestId
- )
- );
- return requests;
- }
-
- private boolean isLiveNetworkAgent(NetworkAgentInfo nai, int what) {
- final NetworkAgentInfo officialNai = getNetworkAgentInfoForNetwork(nai.network);
- if (officialNai != null && officialNai.equals(nai)) return true;
- if (officialNai != null || VDBG) {
- loge(eventName(what) + " - isLiveNetworkAgent found mismatched netId: " + officialNai +
- " - " + nai);
- }
- return false;
- }
-
- // must be stateless - things change under us.
- private class NetworkStateTrackerHandler extends Handler {
- public NetworkStateTrackerHandler(Looper looper) {
- super(looper);
- }
-
- private void maybeHandleNetworkAgentMessage(Message msg) {
- final Pair<NetworkAgentInfo, Object> arg = (Pair<NetworkAgentInfo, Object>) msg.obj;
- final NetworkAgentInfo nai = arg.first;
- if (!mNetworkAgentInfos.contains(nai)) {
- if (VDBG) {
- log(String.format("%s from unknown NetworkAgent", eventName(msg.what)));
- }
- return;
- }
-
- switch (msg.what) {
- case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
- NetworkCapabilities networkCapabilities = (NetworkCapabilities) arg.second;
- if (networkCapabilities.hasConnectivityManagedCapability()) {
- Log.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
- }
- if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
- // Make sure the original object is not mutated. NetworkAgent normally
- // makes a copy of the capabilities when sending the message through
- // the Messenger, but if this ever changes, not making a defensive copy
- // here will give attack vectors to clients using this code path.
- networkCapabilities = new NetworkCapabilities(networkCapabilities);
- networkCapabilities.restrictCapabilitesForTestNetwork(nai.creatorUid);
- }
- processCapabilitiesFromAgent(nai, networkCapabilities);
- updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
- break;
- }
- case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: {
- LinkProperties newLp = (LinkProperties) arg.second;
- processLinkPropertiesFromAgent(nai, newLp);
- handleUpdateLinkProperties(nai, newLp);
- break;
- }
- case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {
- NetworkInfo info = (NetworkInfo) arg.second;
- updateNetworkInfo(nai, info);
- break;
- }
- case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: {
- updateNetworkScore(nai, (NetworkScore) arg.second);
- break;
- }
- case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: {
- if (nai.everConnected) {
- loge("ERROR: cannot call explicitlySelected on already-connected network");
- // Note that if the NAI had been connected, this would affect the
- // score, and therefore would require re-mixing the score and performing
- // a rematch.
- }
- nai.networkAgentConfig.explicitlySelected = toBool(msg.arg1);
- nai.networkAgentConfig.acceptUnvalidated = toBool(msg.arg1) && toBool(msg.arg2);
- // Mark the network as temporarily accepting partial connectivity so that it
- // will be validated (and possibly become default) even if it only provides
- // partial internet access. Note that if user connects to partial connectivity
- // and choose "don't ask again", then wifi disconnected by some reasons(maybe
- // out of wifi coverage) and if the same wifi is available again, the device
- // will auto connect to this wifi even though the wifi has "no internet".
- // TODO: Evaluate using a separate setting in IpMemoryStore.
- nai.networkAgentConfig.acceptPartialConnectivity = toBool(msg.arg2);
- break;
- }
- case NetworkAgent.EVENT_SOCKET_KEEPALIVE: {
- mKeepaliveTracker.handleEventSocketKeepalive(nai, msg.arg1, msg.arg2);
- break;
- }
- case NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED: {
- // TODO: prevent loops, e.g., if a network declares itself as underlying.
- if (!nai.supportsUnderlyingNetworks()) {
- Log.wtf(TAG, "Non-virtual networks cannot have underlying networks");
- break;
- }
-
- final List<Network> underlying = (List<Network>) arg.second;
-
- if (isLegacyLockdownNai(nai)
- && (underlying == null || underlying.size() != 1)) {
- Log.wtf(TAG, "Legacy lockdown VPN " + nai.toShortString()
- + " must have exactly one underlying network: " + underlying);
- }
-
- final Network[] oldUnderlying = nai.declaredUnderlyingNetworks;
- nai.declaredUnderlyingNetworks = (underlying != null)
- ? underlying.toArray(new Network[0]) : null;
-
- if (!Arrays.equals(oldUnderlying, nai.declaredUnderlyingNetworks)) {
- if (DBG) {
- log(nai.toShortString() + " changed underlying networks to "
- + Arrays.toString(nai.declaredUnderlyingNetworks));
- }
- updateCapabilitiesForNetwork(nai);
- notifyIfacesChangedForNetworkStats();
- }
- break;
- }
- case NetworkAgent.EVENT_TEARDOWN_DELAY_CHANGED: {
- if (msg.arg1 >= 0 && msg.arg1 <= NetworkAgent.MAX_TEARDOWN_DELAY_MS) {
- nai.teardownDelayMs = msg.arg1;
- } else {
- logwtf(nai.toShortString() + " set invalid teardown delay " + msg.arg1);
- }
- break;
- }
- case NetworkAgent.EVENT_LINGER_DURATION_CHANGED: {
- nai.setLingerDuration((int) arg.second);
- break;
- }
- }
- }
-
- private boolean maybeHandleNetworkMonitorMessage(Message msg) {
- switch (msg.what) {
- default:
- return false;
- case EVENT_PROBE_STATUS_CHANGED: {
- final Integer netId = (Integer) msg.obj;
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
- if (nai == null) {
- break;
- }
- final boolean probePrivateDnsCompleted =
- ((msg.arg1 & NETWORK_VALIDATION_PROBE_PRIVDNS) != 0);
- final boolean privateDnsBroken =
- ((msg.arg2 & NETWORK_VALIDATION_PROBE_PRIVDNS) == 0);
- if (probePrivateDnsCompleted) {
- if (nai.networkCapabilities.isPrivateDnsBroken() != privateDnsBroken) {
- nai.networkCapabilities.setPrivateDnsBroken(privateDnsBroken);
- updateCapabilitiesForNetwork(nai);
- }
- // Only show the notification when the private DNS is broken and the
- // PRIVATE_DNS_BROKEN notification hasn't shown since last valid.
- if (privateDnsBroken && !nai.networkAgentConfig.hasShownBroken) {
- showNetworkNotification(nai, NotificationType.PRIVATE_DNS_BROKEN);
- }
- nai.networkAgentConfig.hasShownBroken = privateDnsBroken;
- } else if (nai.networkCapabilities.isPrivateDnsBroken()) {
- // If probePrivateDnsCompleted is false but nai.networkCapabilities says
- // private DNS is broken, it means this network is being reevaluated.
- // Either probing private DNS is not necessary any more or it hasn't been
- // done yet. In either case, the networkCapabilities should be updated to
- // reflect the new status.
- nai.networkCapabilities.setPrivateDnsBroken(false);
- updateCapabilitiesForNetwork(nai);
- nai.networkAgentConfig.hasShownBroken = false;
- }
- break;
- }
- case EVENT_NETWORK_TESTED: {
- final NetworkTestedResults results = (NetworkTestedResults) msg.obj;
-
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(results.mNetId);
- if (nai == null) break;
-
- handleNetworkTested(nai, results.mTestResult,
- (results.mRedirectUrl == null) ? "" : results.mRedirectUrl);
- break;
- }
- case EVENT_PROVISIONING_NOTIFICATION: {
- final int netId = msg.arg2;
- final boolean visible = toBool(msg.arg1);
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
- // If captive portal status has changed, update capabilities or disconnect.
- if (nai != null && (visible != nai.lastCaptivePortalDetected)) {
- nai.lastCaptivePortalDetected = visible;
- nai.everCaptivePortalDetected |= visible;
- if (nai.lastCaptivePortalDetected &&
- ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID
- == getCaptivePortalMode()) {
- if (DBG) log("Avoiding captive portal network: " + nai.toShortString());
- nai.onPreventAutomaticReconnect();
- teardownUnneededNetwork(nai);
- break;
- }
- updateCapabilitiesForNetwork(nai);
- }
- if (!visible) {
- // Only clear SIGN_IN and NETWORK_SWITCH notifications here, or else other
- // notifications belong to the same network may be cleared unexpectedly.
- mNotifier.clearNotification(netId, NotificationType.SIGN_IN);
- mNotifier.clearNotification(netId, NotificationType.NETWORK_SWITCH);
- } else {
- if (nai == null) {
- loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor");
- break;
- }
- if (!nai.networkAgentConfig.provisioningNotificationDisabled) {
- mNotifier.showNotification(netId, NotificationType.SIGN_IN, nai, null,
- (PendingIntent) msg.obj,
- nai.networkAgentConfig.explicitlySelected);
- }
- }
- break;
- }
- case EVENT_PRIVATE_DNS_CONFIG_RESOLVED: {
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
- if (nai == null) break;
-
- updatePrivateDns(nai, (PrivateDnsConfig) msg.obj);
- break;
- }
- case EVENT_CAPPORT_DATA_CHANGED: {
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
- if (nai == null) break;
- handleCapportApiDataUpdate(nai, (CaptivePortalData) msg.obj);
- break;
- }
- }
- return true;
- }
-
- private void handleNetworkTested(
- @NonNull NetworkAgentInfo nai, int testResult, @NonNull String redirectUrl) {
- final boolean wasPartial = nai.partialConnectivity;
- nai.partialConnectivity = ((testResult & NETWORK_VALIDATION_RESULT_PARTIAL) != 0);
- final boolean partialConnectivityChanged =
- (wasPartial != nai.partialConnectivity);
-
- final boolean valid = ((testResult & NETWORK_VALIDATION_RESULT_VALID) != 0);
- final boolean wasValidated = nai.lastValidated;
- final boolean wasDefault = isDefaultNetwork(nai);
-
- if (DBG) {
- final String logMsg = !TextUtils.isEmpty(redirectUrl)
- ? " with redirect to " + redirectUrl
- : "";
- log(nai.toShortString() + " validation " + (valid ? "passed" : "failed") + logMsg);
- }
- if (valid != nai.lastValidated) {
- final int oldScore = nai.getCurrentScore();
- nai.lastValidated = valid;
- nai.everValidated |= valid;
- updateCapabilities(oldScore, nai, nai.networkCapabilities);
- if (valid) {
- handleFreshlyValidatedNetwork(nai);
- // Clear NO_INTERNET, PRIVATE_DNS_BROKEN, PARTIAL_CONNECTIVITY and
- // LOST_INTERNET notifications if network becomes valid.
- mNotifier.clearNotification(nai.network.getNetId(),
- NotificationType.NO_INTERNET);
- mNotifier.clearNotification(nai.network.getNetId(),
- NotificationType.LOST_INTERNET);
- mNotifier.clearNotification(nai.network.getNetId(),
- NotificationType.PARTIAL_CONNECTIVITY);
- mNotifier.clearNotification(nai.network.getNetId(),
- NotificationType.PRIVATE_DNS_BROKEN);
- // If network becomes valid, the hasShownBroken should be reset for
- // that network so that the notification will be fired when the private
- // DNS is broken again.
- nai.networkAgentConfig.hasShownBroken = false;
- }
- } else if (partialConnectivityChanged) {
- updateCapabilitiesForNetwork(nai);
- }
- updateInetCondition(nai);
- // Let the NetworkAgent know the state of its network
- // TODO: Evaluate to update partial connectivity to status to NetworkAgent.
- nai.onValidationStatusChanged(
- valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK,
- redirectUrl);
-
- // If NetworkMonitor detects partial connectivity before
- // EVENT_PROMPT_UNVALIDATED arrives, show the partial connectivity notification
- // immediately. Re-notify partial connectivity silently if no internet
- // notification already there.
- if (!wasPartial && nai.partialConnectivity) {
- // Remove delayed message if there is a pending message.
- mHandler.removeMessages(EVENT_PROMPT_UNVALIDATED, nai.network);
- handlePromptUnvalidated(nai.network);
- }
-
- if (wasValidated && !nai.lastValidated) {
- handleNetworkUnvalidated(nai);
- }
- }
-
- private int getCaptivePortalMode() {
- return Settings.Global.getInt(mContext.getContentResolver(),
- ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE,
- ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT);
- }
-
- private boolean maybeHandleNetworkAgentInfoMessage(Message msg) {
- switch (msg.what) {
- default:
- return false;
- case NetworkAgentInfo.EVENT_NETWORK_LINGER_COMPLETE: {
- NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj;
- if (nai != null && isLiveNetworkAgent(nai, msg.what)) {
- handleLingerComplete(nai);
- }
- break;
- }
- case NetworkAgentInfo.EVENT_AGENT_REGISTERED: {
- handleNetworkAgentRegistered(msg);
- break;
- }
- case NetworkAgentInfo.EVENT_AGENT_DISCONNECTED: {
- handleNetworkAgentDisconnected(msg);
- break;
- }
- }
- return true;
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (!maybeHandleNetworkMonitorMessage(msg)
- && !maybeHandleNetworkAgentInfoMessage(msg)) {
- maybeHandleNetworkAgentMessage(msg);
- }
- }
- }
-
- private class NetworkMonitorCallbacks extends INetworkMonitorCallbacks.Stub {
- private final int mNetId;
- private final AutodestructReference<NetworkAgentInfo> mNai;
-
- private NetworkMonitorCallbacks(NetworkAgentInfo nai) {
- mNetId = nai.network.getNetId();
- mNai = new AutodestructReference<>(nai);
- }
-
- @Override
- public void onNetworkMonitorCreated(INetworkMonitor networkMonitor) {
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT,
- new Pair<>(mNai.getAndDestroy(), networkMonitor)));
- }
-
- @Override
- public void notifyNetworkTested(int testResult, @Nullable String redirectUrl) {
- // Legacy version of notifyNetworkTestedWithExtras.
- // Would only be called if the system has a NetworkStack module older than the
- // framework, which does not happen in practice.
- Log.wtf(TAG, "Deprecated notifyNetworkTested called: no action taken");
- }
-
- @Override
- public void notifyNetworkTestedWithExtras(NetworkTestResultParcelable p) {
- // Notify mTrackerHandler and mConnectivityDiagnosticsHandler of the event. Both use
- // the same looper so messages will be processed in sequence.
- final Message msg = mTrackerHandler.obtainMessage(
- EVENT_NETWORK_TESTED,
- new NetworkTestedResults(
- mNetId, p.result, p.timestampMillis, p.redirectUrl));
- mTrackerHandler.sendMessage(msg);
-
- // Invoke ConnectivityReport generation for this Network test event.
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(mNetId);
- if (nai == null) return;
-
- final PersistableBundle extras = new PersistableBundle();
- extras.putInt(KEY_NETWORK_VALIDATION_RESULT, p.result);
- extras.putInt(KEY_NETWORK_PROBES_SUCCEEDED_BITMASK, p.probesSucceeded);
- extras.putInt(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK, p.probesAttempted);
-
- ConnectivityReportEvent reportEvent =
- new ConnectivityReportEvent(p.timestampMillis, nai, extras);
- final Message m = mConnectivityDiagnosticsHandler.obtainMessage(
- ConnectivityDiagnosticsHandler.EVENT_NETWORK_TESTED, reportEvent);
- mConnectivityDiagnosticsHandler.sendMessage(m);
- }
-
- @Override
- public void notifyPrivateDnsConfigResolved(PrivateDnsConfigParcel config) {
- mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
- EVENT_PRIVATE_DNS_CONFIG_RESOLVED,
- 0, mNetId, PrivateDnsConfig.fromParcel(config)));
- }
-
- @Override
- public void notifyProbeStatusChanged(int probesCompleted, int probesSucceeded) {
- mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
- EVENT_PROBE_STATUS_CHANGED,
- probesCompleted, probesSucceeded, new Integer(mNetId)));
- }
-
- @Override
- public void notifyCaptivePortalDataChanged(CaptivePortalData data) {
- mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
- EVENT_CAPPORT_DATA_CHANGED,
- 0, mNetId, data));
- }
-
- @Override
- public void showProvisioningNotification(String action, String packageName) {
- final Intent intent = new Intent(action);
- intent.setPackage(packageName);
-
- final PendingIntent pendingIntent;
- // Only the system server can register notifications with package "android"
- final long token = Binder.clearCallingIdentity();
- try {
- pendingIntent = PendingIntent.getBroadcast(
- mContext,
- 0 /* requestCode */,
- intent,
- PendingIntent.FLAG_IMMUTABLE);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
- EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_SHOW,
- mNetId, pendingIntent));
- }
-
- @Override
- public void hideProvisioningNotification() {
- mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
- EVENT_PROVISIONING_NOTIFICATION, PROVISIONING_NOTIFICATION_HIDE, mNetId));
- }
-
- @Override
- public void notifyDataStallSuspected(DataStallReportParcelable p) {
- ConnectivityService.this.notifyDataStallSuspected(p, mNetId);
- }
-
- @Override
- public int getInterfaceVersion() {
- return this.VERSION;
- }
-
- @Override
- public String getInterfaceHash() {
- return this.HASH;
- }
- }
-
- private void notifyDataStallSuspected(DataStallReportParcelable p, int netId) {
- log("Data stall detected with methods: " + p.detectionMethod);
-
- final PersistableBundle extras = new PersistableBundle();
- int detectionMethod = 0;
- if (hasDataStallDetectionMethod(p, DETECTION_METHOD_DNS_EVENTS)) {
- extras.putInt(KEY_DNS_CONSECUTIVE_TIMEOUTS, p.dnsConsecutiveTimeouts);
- detectionMethod |= DETECTION_METHOD_DNS_EVENTS;
- }
- if (hasDataStallDetectionMethod(p, DETECTION_METHOD_TCP_METRICS)) {
- extras.putInt(KEY_TCP_PACKET_FAIL_RATE, p.tcpPacketFailRate);
- extras.putInt(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS,
- p.tcpMetricsCollectionPeriodMillis);
- detectionMethod |= DETECTION_METHOD_TCP_METRICS;
- }
-
- final Message msg = mConnectivityDiagnosticsHandler.obtainMessage(
- ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED, detectionMethod, netId,
- new Pair<>(p.timestampMillis, extras));
-
- // NetworkStateTrackerHandler currently doesn't take any actions based on data
- // stalls so send the message directly to ConnectivityDiagnosticsHandler and avoid
- // the cost of going through two handlers.
- mConnectivityDiagnosticsHandler.sendMessage(msg);
- }
-
- private boolean hasDataStallDetectionMethod(DataStallReportParcelable p, int detectionMethod) {
- return (p.detectionMethod & detectionMethod) != 0;
- }
-
- private boolean networkRequiresPrivateDnsValidation(NetworkAgentInfo nai) {
- return isPrivateDnsValidationRequired(nai.networkCapabilities);
- }
-
- private void handleFreshlyValidatedNetwork(NetworkAgentInfo nai) {
- if (nai == null) return;
- // If the Private DNS mode is opportunistic, reprogram the DNS servers
- // in order to restart a validation pass from within netd.
- final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig();
- if (cfg.useTls && TextUtils.isEmpty(cfg.hostname)) {
- updateDnses(nai.linkProperties, null, nai.network.getNetId());
- }
- }
-
- private void handlePrivateDnsSettingsChanged() {
- final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig();
-
- for (NetworkAgentInfo nai : mNetworkAgentInfos) {
- handlePerNetworkPrivateDnsConfig(nai, cfg);
- if (networkRequiresPrivateDnsValidation(nai)) {
- handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
- }
- }
- }
-
- private void handlePerNetworkPrivateDnsConfig(NetworkAgentInfo nai, PrivateDnsConfig cfg) {
- // Private DNS only ever applies to networks that might provide
- // Internet access and therefore also require validation.
- if (!networkRequiresPrivateDnsValidation(nai)) return;
-
- // Notify the NetworkAgentInfo/NetworkMonitor in case NetworkMonitor needs to cancel or
- // schedule DNS resolutions. If a DNS resolution is required the
- // result will be sent back to us.
- nai.networkMonitor().notifyPrivateDnsChanged(cfg.toParcel());
-
- // With Private DNS bypass support, we can proceed to update the
- // Private DNS config immediately, even if we're in strict mode
- // and have not yet resolved the provider name into a set of IPs.
- updatePrivateDns(nai, cfg);
- }
-
- private void updatePrivateDns(NetworkAgentInfo nai, PrivateDnsConfig newCfg) {
- mDnsManager.updatePrivateDns(nai.network, newCfg);
- updateDnses(nai.linkProperties, null, nai.network.getNetId());
- }
-
- private void handlePrivateDnsValidationUpdate(PrivateDnsValidationUpdate update) {
- NetworkAgentInfo nai = getNetworkAgentInfoForNetId(update.netId);
- if (nai == null) {
- return;
- }
- mDnsManager.updatePrivateDnsValidation(update);
- handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
- }
-
- private void handleNat64PrefixEvent(int netId, int operation, String prefixAddress,
- int prefixLength) {
- NetworkAgentInfo nai = mNetworkForNetId.get(netId);
- if (nai == null) return;
-
- log(String.format("NAT64 prefix changed on netId %d: operation=%d, %s/%d",
- netId, operation, prefixAddress, prefixLength));
-
- IpPrefix prefix = null;
- if (operation == IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED) {
- try {
- prefix = new IpPrefix(InetAddresses.parseNumericAddress(prefixAddress),
- prefixLength);
- } catch (IllegalArgumentException e) {
- loge("Invalid NAT64 prefix " + prefixAddress + "/" + prefixLength);
- return;
- }
- }
-
- nai.clatd.setNat64PrefixFromDns(prefix);
- handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
- }
-
- private void handleCapportApiDataUpdate(@NonNull final NetworkAgentInfo nai,
- @Nullable final CaptivePortalData data) {
- nai.capportApiData = data;
- // CaptivePortalData will be merged into LinkProperties from NetworkAgentInfo
- handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
- }
-
- /**
- * Updates the inactivity state from the network requests inside the NAI.
- * @param nai the agent info to update
- * @param now the timestamp of the event causing this update
- * @return whether the network was inactive as a result of this update
- */
- private boolean updateInactivityState(@NonNull final NetworkAgentInfo nai, final long now) {
- // 1. Update the inactivity timer. If it's changed, reschedule or cancel the alarm.
- // 2. If the network was inactive and there are now requests, unset inactive.
- // 3. If this network is unneeded (which implies it is not lingering), and there is at least
- // one lingered request, set inactive.
- nai.updateInactivityTimer();
- if (nai.isInactive() && nai.numForegroundNetworkRequests() > 0) {
- if (DBG) log("Unsetting inactive " + nai.toShortString());
- nai.unsetInactive();
- logNetworkEvent(nai, NetworkEvent.NETWORK_UNLINGER);
- } else if (unneeded(nai, UnneededFor.LINGER) && nai.getInactivityExpiry() > 0) {
- if (DBG) {
- final int lingerTime = (int) (nai.getInactivityExpiry() - now);
- log("Setting inactive " + nai.toShortString() + " for " + lingerTime + "ms");
- }
- nai.setInactive();
- logNetworkEvent(nai, NetworkEvent.NETWORK_LINGER);
- return true;
- }
- return false;
- }
-
- private void handleNetworkAgentRegistered(Message msg) {
- final NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj;
- if (!mNetworkAgentInfos.contains(nai)) {
- return;
- }
-
- if (msg.arg1 == NetworkAgentInfo.ARG_AGENT_SUCCESS) {
- if (VDBG) log("NetworkAgent registered");
- } else {
- loge("Error connecting NetworkAgent");
- mNetworkAgentInfos.remove(nai);
- if (nai != null) {
- final boolean wasDefault = isDefaultNetwork(nai);
- synchronized (mNetworkForNetId) {
- mNetworkForNetId.remove(nai.network.getNetId());
- }
- mNetIdManager.releaseNetId(nai.network.getNetId());
- // Just in case.
- mLegacyTypeTracker.remove(nai, wasDefault);
- }
- }
- }
-
- private void handleNetworkAgentDisconnected(Message msg) {
- NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj;
- if (mNetworkAgentInfos.contains(nai)) {
- disconnectAndDestroyNetwork(nai);
- }
- }
-
- // Destroys a network, remove references to it from the internal state managed by
- // ConnectivityService, free its interfaces and clean up.
- // Must be called on the Handler thread.
- private void disconnectAndDestroyNetwork(NetworkAgentInfo nai) {
- ensureRunningOnConnectivityServiceThread();
- if (DBG) {
- log(nai.toShortString() + " disconnected, was satisfying " + nai.numNetworkRequests());
- }
- // Clear all notifications of this network.
- mNotifier.clearNotification(nai.network.getNetId());
- // A network agent has disconnected.
- // TODO - if we move the logic to the network agent (have them disconnect
- // because they lost all their requests or because their score isn't good)
- // then they would disconnect organically, report their new state and then
- // disconnect the channel.
- if (nai.networkInfo.isConnected()) {
- nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
- null, null);
- }
- final boolean wasDefault = isDefaultNetwork(nai);
- if (wasDefault) {
- mDefaultInetConditionPublished = 0;
- }
- notifyIfacesChangedForNetworkStats();
- // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
- // by other networks that are already connected. Perhaps that can be done by
- // sending all CALLBACK_LOST messages (for requests, not listens) at the end
- // of rematchAllNetworksAndRequests
- notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
- mKeepaliveTracker.handleStopAllKeepalives(nai, SocketKeepalive.ERROR_INVALID_NETWORK);
-
- mQosCallbackTracker.handleNetworkReleased(nai.network);
- for (String iface : nai.linkProperties.getAllInterfaceNames()) {
- // Disable wakeup packet monitoring for each interface.
- wakeupModifyInterface(iface, nai.networkCapabilities, false);
- }
- nai.networkMonitor().notifyNetworkDisconnected();
- mNetworkAgentInfos.remove(nai);
- nai.clatd.update();
- synchronized (mNetworkForNetId) {
- // Remove the NetworkAgent, but don't mark the netId as
- // available until we've told netd to delete it below.
- mNetworkForNetId.remove(nai.network.getNetId());
- }
- propagateUnderlyingNetworkCapabilities(nai.network);
- // Remove all previously satisfied requests.
- for (int i = 0; i < nai.numNetworkRequests(); i++) {
- final NetworkRequest request = nai.requestAt(i);
- final NetworkRequestInfo nri = mNetworkRequests.get(request);
- final NetworkAgentInfo currentNetwork = nri.getSatisfier();
- if (currentNetwork != null
- && currentNetwork.network.getNetId() == nai.network.getNetId()) {
- // uid rules for this network will be removed in destroyNativeNetwork(nai).
- // TODO : setting the satisfier is in fact the job of the rematch. Teach the
- // rematch not to keep disconnected agents instead of setting it here ; this
- // will also allow removing updating the offers below.
- nri.setSatisfier(null, null);
- for (final NetworkOfferInfo noi : mNetworkOffers) {
- informOffer(nri, noi.offer, mNetworkRanker);
- }
-
- if (mDefaultRequest == nri) {
- // TODO : make battery stats aware that since 2013 multiple interfaces may be
- // active at the same time. For now keep calling this with the default
- // network, because while incorrect this is the closest to the old (also
- // incorrect) behavior.
- mNetworkActivityTracker.updateDataActivityTracking(
- null /* newNetwork */, nai);
- ensureNetworkTransitionWakelock(nai.toShortString());
- }
- }
- }
- nai.clearInactivityState();
- // TODO: mLegacyTypeTracker.remove seems redundant given there's a full rematch right after.
- // Currently, deleting it breaks tests that check for the default network disconnecting.
- // Find out why, fix the rematch code, and delete this.
- mLegacyTypeTracker.remove(nai, wasDefault);
- rematchAllNetworksAndRequests();
- mLingerMonitor.noteDisconnect(nai);
-
- // Immediate teardown.
- if (nai.teardownDelayMs == 0) {
- destroyNetwork(nai);
- return;
- }
-
- // Delayed teardown.
- try {
- mNetd.networkSetPermissionForNetwork(nai.network.netId, INetd.PERMISSION_SYSTEM);
- } catch (RemoteException e) {
- Log.d(TAG, "Error marking network restricted during teardown: " + e);
- }
- mHandler.postDelayed(() -> destroyNetwork(nai), nai.teardownDelayMs);
- }
-
- private void destroyNetwork(NetworkAgentInfo nai) {
- if (nai.created) {
- // Tell netd to clean up the configuration for this network
- // (routing rules, DNS, etc).
- // This may be slow as it requires a lot of netd shelling out to ip and
- // ip[6]tables to flush routes and remove the incoming packet mark rule, so do it
- // after we've rematched networks with requests (which might change the default
- // network or service a new request from an app), so network traffic isn't interrupted
- // for an unnecessarily long time.
- destroyNativeNetwork(nai);
- mDnsManager.removeNetwork(nai.network);
- }
- mNetIdManager.releaseNetId(nai.network.getNetId());
- nai.onNetworkDestroyed();
- }
-
- private boolean createNativeNetwork(@NonNull NetworkAgentInfo nai) {
- try {
- // This should never fail. Specifying an already in use NetID will cause failure.
- final NativeNetworkConfig config;
- if (nai.isVPN()) {
- if (getVpnType(nai) == VpnManager.TYPE_VPN_NONE) {
- Log.wtf(TAG, "Unable to get VPN type from network " + nai.toShortString());
- return false;
- }
- config = new NativeNetworkConfig(nai.network.getNetId(), NativeNetworkType.VIRTUAL,
- INetd.PERMISSION_NONE,
- (nai.networkAgentConfig == null || !nai.networkAgentConfig.allowBypass),
- getVpnType(nai));
- } else {
- config = new NativeNetworkConfig(nai.network.getNetId(), NativeNetworkType.PHYSICAL,
- getNetworkPermission(nai.networkCapabilities), /*secure=*/ false,
- VpnManager.TYPE_VPN_NONE);
- }
- mNetd.networkCreate(config);
- mDnsResolver.createNetworkCache(nai.network.getNetId());
- mDnsManager.updateTransportsForNetwork(nai.network.getNetId(),
- nai.networkCapabilities.getTransportTypes());
- return true;
- } catch (RemoteException | ServiceSpecificException e) {
- loge("Error creating network " + nai.toShortString() + ": " + e.getMessage());
- return false;
- }
- }
-
- private void destroyNativeNetwork(@NonNull NetworkAgentInfo nai) {
- try {
- mNetd.networkDestroy(nai.network.getNetId());
- } catch (RemoteException | ServiceSpecificException e) {
- loge("Exception destroying network(networkDestroy): " + e);
- }
- try {
- mDnsResolver.destroyNetworkCache(nai.network.getNetId());
- } catch (RemoteException | ServiceSpecificException e) {
- loge("Exception destroying network: " + e);
- }
- }
-
- // If this method proves to be too slow then we can maintain a separate
- // pendingIntent => NetworkRequestInfo map.
- // This method assumes that every non-null PendingIntent maps to exactly 1 NetworkRequestInfo.
- private NetworkRequestInfo findExistingNetworkRequestInfo(PendingIntent pendingIntent) {
- for (Map.Entry<NetworkRequest, NetworkRequestInfo> entry : mNetworkRequests.entrySet()) {
- PendingIntent existingPendingIntent = entry.getValue().mPendingIntent;
- if (existingPendingIntent != null &&
- existingPendingIntent.intentFilterEquals(pendingIntent)) {
- return entry.getValue();
- }
- }
- return null;
- }
-
- private void handleRegisterNetworkRequestWithIntent(@NonNull final Message msg) {
- final NetworkRequestInfo nri = (NetworkRequestInfo) (msg.obj);
- // handleRegisterNetworkRequestWithIntent() doesn't apply to multilayer requests.
- ensureNotMultilayerRequest(nri, "handleRegisterNetworkRequestWithIntent");
- final NetworkRequestInfo existingRequest =
- findExistingNetworkRequestInfo(nri.mPendingIntent);
- if (existingRequest != null) { // remove the existing request.
- if (DBG) {
- log("Replacing " + existingRequest.mRequests.get(0) + " with "
- + nri.mRequests.get(0) + " because their intents matched.");
- }
- handleReleaseNetworkRequest(existingRequest.mRequests.get(0), mDeps.getCallingUid(),
- /* callOnUnavailable */ false);
- }
- handleRegisterNetworkRequest(nri);
- }
-
- private void handleRegisterNetworkRequest(@NonNull final NetworkRequestInfo nri) {
- handleRegisterNetworkRequests(Collections.singleton(nri));
- }
-
- private void handleRegisterNetworkRequests(@NonNull final Set<NetworkRequestInfo> nris) {
- ensureRunningOnConnectivityServiceThread();
- for (final NetworkRequestInfo nri : nris) {
- mNetworkRequestInfoLogs.log("REGISTER " + nri);
- for (final NetworkRequest req : nri.mRequests) {
- mNetworkRequests.put(req, nri);
- // TODO: Consider update signal strength for other types.
- if (req.isListen()) {
- for (final NetworkAgentInfo network : mNetworkAgentInfos) {
- if (req.networkCapabilities.hasSignalStrength()
- && network.satisfiesImmutableCapabilitiesOf(req)) {
- updateSignalStrengthThresholds(network, "REGISTER", req);
- }
- }
- }
- }
- // If this NRI has a satisfier already, it is replacing an older request that
- // has been removed. Track it.
- final NetworkRequest activeRequest = nri.getActiveRequest();
- if (null != activeRequest) {
- // If there is an active request, then for sure there is a satisfier.
- nri.getSatisfier().addRequest(activeRequest);
- }
- }
-
- rematchAllNetworksAndRequests();
-
- // Requests that have not been matched to a network will not have been sent to the
- // providers, because the old satisfier and the new satisfier are the same (null in this
- // case). Send these requests to the providers.
- for (final NetworkRequestInfo nri : nris) {
- for (final NetworkOfferInfo noi : mNetworkOffers) {
- informOffer(nri, noi.offer, mNetworkRanker);
- }
- }
- }
-
- private void handleReleaseNetworkRequestWithIntent(@NonNull final PendingIntent pendingIntent,
- final int callingUid) {
- final NetworkRequestInfo nri = findExistingNetworkRequestInfo(pendingIntent);
- if (nri != null) {
- // handleReleaseNetworkRequestWithIntent() paths don't apply to multilayer requests.
- ensureNotMultilayerRequest(nri, "handleReleaseNetworkRequestWithIntent");
- handleReleaseNetworkRequest(
- nri.mRequests.get(0),
- callingUid,
- /* callOnUnavailable */ false);
- }
- }
-
- // Determines whether the network is the best (or could become the best, if it validated), for
- // none of a particular type of NetworkRequests. The type of NetworkRequests considered depends
- // on the value of reason:
- //
- // - UnneededFor.TEARDOWN: non-listen NetworkRequests. If a network is unneeded for this reason,
- // then it should be torn down.
- // - UnneededFor.LINGER: foreground NetworkRequests. If a network is unneeded for this reason,
- // then it should be lingered.
- private boolean unneeded(NetworkAgentInfo nai, UnneededFor reason) {
- ensureRunningOnConnectivityServiceThread();
-
- if (!nai.everConnected || nai.isVPN() || nai.isInactive()
- || nai.getScore().getKeepConnectedReason() != NetworkScore.KEEP_CONNECTED_NONE) {
- return false;
- }
-
- final int numRequests;
- switch (reason) {
- case TEARDOWN:
- numRequests = nai.numRequestNetworkRequests();
- break;
- case LINGER:
- numRequests = nai.numForegroundNetworkRequests();
- break;
- default:
- Log.wtf(TAG, "Invalid reason. Cannot happen.");
- return true;
- }
-
- if (numRequests > 0) return false;
-
- for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (reason == UnneededFor.LINGER
- && !nri.isMultilayerRequest()
- && nri.mRequests.get(0).isBackgroundRequest()) {
- // Background requests don't affect lingering.
- continue;
- }
-
- if (isNetworkPotentialSatisfier(nai, nri)) {
- return false;
- }
- }
- return true;
- }
-
- private boolean isNetworkPotentialSatisfier(
- @NonNull final NetworkAgentInfo candidate, @NonNull final NetworkRequestInfo nri) {
- // listen requests won't keep up a network satisfying it. If this is not a multilayer
- // request, return immediately. For multilayer requests, check to see if any of the
- // multilayer requests may have a potential satisfier.
- if (!nri.isMultilayerRequest() && (nri.mRequests.get(0).isListen()
- || nri.mRequests.get(0).isListenForBest())) {
- return false;
- }
- for (final NetworkRequest req : nri.mRequests) {
- // This multilayer listen request is satisfied therefore no further requests need to be
- // evaluated deeming this network not a potential satisfier.
- if ((req.isListen() || req.isListenForBest()) && nri.getActiveRequest() == req) {
- return false;
- }
- // As non-multilayer listen requests have already returned, the below would only happen
- // for a multilayer request therefore continue to the next request if available.
- if (req.isListen() || req.isListenForBest()) {
- continue;
- }
- // If this Network is already the highest scoring Network for a request, or if
- // there is hope for it to become one if it validated, then it is needed.
- if (candidate.satisfies(req)) {
- // As soon as a network is found that satisfies a request, return. Specifically for
- // multilayer requests, returning as soon as a NetworkAgentInfo satisfies a request
- // is important so as to not evaluate lower priority requests further in
- // nri.mRequests.
- final NetworkAgentInfo champion = req.equals(nri.getActiveRequest())
- ? nri.getSatisfier() : null;
- // Note that this catches two important cases:
- // 1. Unvalidated cellular will not be reaped when unvalidated WiFi
- // is currently satisfying the request. This is desirable when
- // cellular ends up validating but WiFi does not.
- // 2. Unvalidated WiFi will not be reaped when validated cellular
- // is currently satisfying the request. This is desirable when
- // WiFi ends up validating and out scoring cellular.
- return mNetworkRanker.mightBeat(req, champion, candidate.getValidatedScoreable());
- }
- }
-
- return false;
- }
-
- private NetworkRequestInfo getNriForAppRequest(
- NetworkRequest request, int callingUid, String requestedOperation) {
- // Looking up the app passed param request in mRequests isn't possible since it may return
- // null for a request managed by a per-app default. Therefore use getNriForAppRequest() to
- // do the lookup since that will also find per-app default managed requests.
- // Additionally, this lookup needs to be relatively fast (hence the lookup optimization)
- // to avoid potential race conditions when validating a package->uid mapping when sending
- // the callback on the very low-chance that an application shuts down prior to the callback
- // being sent.
- final NetworkRequestInfo nri = mNetworkRequests.get(request) != null
- ? mNetworkRequests.get(request) : getNriForAppRequest(request);
-
- if (nri != null) {
- if (Process.SYSTEM_UID != callingUid && nri.mUid != callingUid) {
- log(String.format("UID %d attempted to %s for unowned request %s",
- callingUid, requestedOperation, nri));
- return null;
- }
- }
-
- return nri;
- }
-
- private void ensureNotMultilayerRequest(@NonNull final NetworkRequestInfo nri,
- final String callingMethod) {
- if (nri.isMultilayerRequest()) {
- throw new IllegalStateException(
- callingMethod + " does not support multilayer requests.");
- }
- }
-
- private void handleTimedOutNetworkRequest(@NonNull final NetworkRequestInfo nri) {
- ensureRunningOnConnectivityServiceThread();
- // handleTimedOutNetworkRequest() is part of the requestNetwork() flow which works off of a
- // single NetworkRequest and thus does not apply to multilayer requests.
- ensureNotMultilayerRequest(nri, "handleTimedOutNetworkRequest");
- if (mNetworkRequests.get(nri.mRequests.get(0)) == null) {
- return;
- }
- if (nri.isBeingSatisfied()) {
- return;
- }
- if (VDBG || (DBG && nri.mRequests.get(0).isRequest())) {
- log("releasing " + nri.mRequests.get(0) + " (timeout)");
- }
- handleRemoveNetworkRequest(nri);
- callCallbackForRequest(
- nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0);
- }
-
- private void handleReleaseNetworkRequest(@NonNull final NetworkRequest request,
- final int callingUid,
- final boolean callOnUnavailable) {
- final NetworkRequestInfo nri =
- getNriForAppRequest(request, callingUid, "release NetworkRequest");
- if (nri == null) {
- return;
- }
- if (VDBG || (DBG && request.isRequest())) {
- log("releasing " + request + " (release request)");
- }
- handleRemoveNetworkRequest(nri);
- if (callOnUnavailable) {
- callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0);
- }
- }
-
- private void handleRemoveNetworkRequest(@NonNull final NetworkRequestInfo nri) {
- ensureRunningOnConnectivityServiceThread();
- nri.unlinkDeathRecipient();
- for (final NetworkRequest req : nri.mRequests) {
- mNetworkRequests.remove(req);
- if (req.isListen()) {
- removeListenRequestFromNetworks(req);
- }
- }
- if (mDefaultNetworkRequests.remove(nri)) {
- // If this request was one of the defaults, then the UID rules need to be updated
- // WARNING : if the app(s) for which this network request is the default are doing
- // traffic, this will kill their connected sockets, even if an equivalent request
- // is going to be reinstated right away ; unconnected traffic will go on the default
- // until the new default is set, which will happen very soon.
- // TODO : The only way out of this is to diff old defaults and new defaults, and only
- // remove ranges for those requests that won't have a replacement
- final NetworkAgentInfo satisfier = nri.getSatisfier();
- if (null != satisfier) {
- try {
- mNetd.networkRemoveUidRanges(satisfier.network.getNetId(),
- toUidRangeStableParcels(nri.getUids()));
- } catch (RemoteException e) {
- loge("Exception setting network preference default network", e);
- }
- }
- }
- nri.decrementRequestCount();
- mNetworkRequestInfoLogs.log("RELEASE " + nri);
-
- if (null != nri.getActiveRequest()) {
- if (!nri.getActiveRequest().isListen()) {
- removeSatisfiedNetworkRequestFromNetwork(nri);
- } else {
- nri.setSatisfier(null, null);
- }
- }
-
- // For all outstanding offers, cancel any of the layers of this NRI that used to be
- // needed for this offer.
- for (final NetworkOfferInfo noi : mNetworkOffers) {
- for (final NetworkRequest req : nri.mRequests) {
- if (req.isRequest() && noi.offer.neededFor(req)) {
- noi.offer.onNetworkUnneeded(req);
- }
- }
- }
- }
-
- private void handleRemoveNetworkRequests(@NonNull final Set<NetworkRequestInfo> nris) {
- for (final NetworkRequestInfo nri : nris) {
- if (mDefaultRequest == nri) {
- // Make sure we never remove the default request.
- continue;
- }
- handleRemoveNetworkRequest(nri);
- }
- }
-
- private void removeListenRequestFromNetworks(@NonNull final NetworkRequest req) {
- // listens don't have a singular affected Network. Check all networks to see
- // if this listen request applies and remove it.
- for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
- nai.removeRequest(req.requestId);
- if (req.networkCapabilities.hasSignalStrength()
- && nai.satisfiesImmutableCapabilitiesOf(req)) {
- updateSignalStrengthThresholds(nai, "RELEASE", req);
- }
- }
- }
-
- /**
- * Remove a NetworkRequestInfo's satisfied request from its 'satisfier' (NetworkAgentInfo) and
- * manage the necessary upkeep (linger, teardown networks, etc.) when doing so.
- * @param nri the NetworkRequestInfo to disassociate from its current NetworkAgentInfo
- */
- private void removeSatisfiedNetworkRequestFromNetwork(@NonNull final NetworkRequestInfo nri) {
- boolean wasKept = false;
- final NetworkAgentInfo nai = nri.getSatisfier();
- if (nai != null) {
- final int requestLegacyType = nri.getActiveRequest().legacyType;
- final boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
- nai.removeRequest(nri.getActiveRequest().requestId);
- if (VDBG || DDBG) {
- log(" Removing from current network " + nai.toShortString()
- + ", leaving " + nai.numNetworkRequests() + " requests.");
- }
- // If there are still lingered requests on this network, don't tear it down,
- // but resume lingering instead.
- final long now = SystemClock.elapsedRealtime();
- if (updateInactivityState(nai, now)) {
- notifyNetworkLosing(nai, now);
- }
- if (unneeded(nai, UnneededFor.TEARDOWN)) {
- if (DBG) log("no live requests for " + nai.toShortString() + "; disconnecting");
- teardownUnneededNetwork(nai);
- } else {
- wasKept = true;
- }
- nri.setSatisfier(null, null);
- if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) {
- // Went from foreground to background.
- updateCapabilitiesForNetwork(nai);
- }
-
- // Maintain the illusion. When this request arrived, we might have pretended
- // that a network connected to serve it, even though the network was already
- // connected. Now that this request has gone away, we might have to pretend
- // that the network disconnected. LegacyTypeTracker will generate that
- // phantom disconnect for this type.
- if (requestLegacyType != TYPE_NONE) {
- boolean doRemove = true;
- if (wasKept) {
- // check if any of the remaining requests for this network are for the
- // same legacy type - if so, don't remove the nai
- for (int i = 0; i < nai.numNetworkRequests(); i++) {
- NetworkRequest otherRequest = nai.requestAt(i);
- if (otherRequest.legacyType == requestLegacyType
- && otherRequest.isRequest()) {
- if (DBG) log(" still have other legacy request - leaving");
- doRemove = false;
- }
- }
- }
-
- if (doRemove) {
- mLegacyTypeTracker.remove(requestLegacyType, nai, false);
- }
- }
- }
- }
-
- private PerUidCounter getRequestCounter(NetworkRequestInfo nri) {
- return checkAnyPermissionOf(
- nri.mPid, nri.mUid, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
- ? mSystemNetworkRequestCounter : mNetworkRequestCounter;
- }
-
- @Override
- public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
- enforceNetworkStackSettingsOrSetup();
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_ACCEPT_UNVALIDATED,
- encodeBool(accept), encodeBool(always), network));
- }
-
- @Override
- public void setAcceptPartialConnectivity(Network network, boolean accept, boolean always) {
- enforceNetworkStackSettingsOrSetup();
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_ACCEPT_PARTIAL_CONNECTIVITY,
- encodeBool(accept), encodeBool(always), network));
- }
-
- @Override
- public void setAvoidUnvalidated(Network network) {
- enforceNetworkStackSettingsOrSetup();
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_AVOID_UNVALIDATED, network));
- }
-
- private void handleSetAcceptUnvalidated(Network network, boolean accept, boolean always) {
- if (DBG) log("handleSetAcceptUnvalidated network=" + network +
- " accept=" + accept + " always=" + always);
-
- NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai == null) {
- // Nothing to do.
- return;
- }
-
- if (nai.everValidated) {
- // The network validated while the dialog box was up. Take no action.
- return;
- }
-
- if (!nai.networkAgentConfig.explicitlySelected) {
- Log.wtf(TAG, "BUG: setAcceptUnvalidated non non-explicitly selected network");
- }
-
- if (accept != nai.networkAgentConfig.acceptUnvalidated) {
- nai.networkAgentConfig.acceptUnvalidated = accept;
- // If network becomes partial connectivity and user already accepted to use this
- // network, we should respect the user's option and don't need to popup the
- // PARTIAL_CONNECTIVITY notification to user again.
- nai.networkAgentConfig.acceptPartialConnectivity = accept;
- nai.updateScoreForNetworkAgentUpdate();
- rematchAllNetworksAndRequests();
- }
-
- if (always) {
- nai.onSaveAcceptUnvalidated(accept);
- }
-
- if (!accept) {
- // Tell the NetworkAgent to not automatically reconnect to the network.
- nai.onPreventAutomaticReconnect();
- // Teardown the network.
- teardownUnneededNetwork(nai);
- }
-
- }
-
- private void handleSetAcceptPartialConnectivity(Network network, boolean accept,
- boolean always) {
- if (DBG) {
- log("handleSetAcceptPartialConnectivity network=" + network + " accept=" + accept
- + " always=" + always);
- }
-
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai == null) {
- // Nothing to do.
- return;
- }
-
- if (nai.lastValidated) {
- // The network validated while the dialog box was up. Take no action.
- return;
- }
-
- if (accept != nai.networkAgentConfig.acceptPartialConnectivity) {
- nai.networkAgentConfig.acceptPartialConnectivity = accept;
- }
-
- // TODO: Use the current design or save the user choice into IpMemoryStore.
- if (always) {
- nai.onSaveAcceptUnvalidated(accept);
- }
-
- if (!accept) {
- // Tell the NetworkAgent to not automatically reconnect to the network.
- nai.onPreventAutomaticReconnect();
- // Tear down the network.
- teardownUnneededNetwork(nai);
- } else {
- // Inform NetworkMonitor that partial connectivity is acceptable. This will likely
- // result in a partial connectivity result which will be processed by
- // maybeHandleNetworkMonitorMessage.
- //
- // TODO: NetworkMonitor does not refer to the "never ask again" bit. The bit is stored
- // per network. Therefore, NetworkMonitor may still do https probe.
- nai.networkMonitor().setAcceptPartialConnectivity();
- }
- }
-
- private void handleSetAvoidUnvalidated(Network network) {
- NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai == null || nai.lastValidated) {
- // Nothing to do. The network either disconnected or revalidated.
- return;
- }
- if (!nai.avoidUnvalidated) {
- nai.avoidUnvalidated = true;
- nai.updateScoreForNetworkAgentUpdate();
- rematchAllNetworksAndRequests();
- }
- }
-
- private void scheduleUnvalidatedPrompt(NetworkAgentInfo nai) {
- if (VDBG) log("scheduleUnvalidatedPrompt " + nai.network);
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(EVENT_PROMPT_UNVALIDATED, nai.network),
- PROMPT_UNVALIDATED_DELAY_MS);
- }
-
- @Override
- public void startCaptivePortalApp(Network network) {
- enforceNetworkStackOrSettingsPermission();
- mHandler.post(() -> {
- NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai == null) return;
- if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) return;
- nai.networkMonitor().launchCaptivePortalApp();
- });
- }
-
- /**
- * NetworkStack endpoint to start the captive portal app. The NetworkStack needs to use this
- * endpoint as it does not have INTERACT_ACROSS_USERS_FULL itself.
- * @param network Network on which the captive portal was detected.
- * @param appExtras Bundle to use as intent extras for the captive portal application.
- * Must be treated as opaque to avoid preventing the captive portal app to
- * update its arguments.
- */
- @Override
- public void startCaptivePortalAppInternal(Network network, Bundle appExtras) {
- mContext.enforceCallingOrSelfPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- "ConnectivityService");
-
- final Intent appIntent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN);
- appIntent.putExtras(appExtras);
- appIntent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL,
- new CaptivePortal(new CaptivePortalImpl(network).asBinder()));
- appIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
-
- final long token = Binder.clearCallingIdentity();
- try {
- mContext.startActivityAsUser(appIntent, UserHandle.CURRENT);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- private class CaptivePortalImpl extends ICaptivePortal.Stub {
- private final Network mNetwork;
-
- private CaptivePortalImpl(Network network) {
- mNetwork = network;
- }
-
- @Override
- public void appResponse(final int response) {
- if (response == CaptivePortal.APP_RETURN_WANTED_AS_IS) {
- enforceSettingsPermission();
- }
-
- final NetworkMonitorManager nm = getNetworkMonitorManager(mNetwork);
- if (nm == null) return;
- nm.notifyCaptivePortalAppFinished(response);
- }
-
- @Override
- public void appRequest(final int request) {
- final NetworkMonitorManager nm = getNetworkMonitorManager(mNetwork);
- if (nm == null) return;
-
- if (request == CaptivePortal.APP_REQUEST_REEVALUATION_REQUIRED) {
- checkNetworkStackPermission();
- nm.forceReevaluation(mDeps.getCallingUid());
- }
- }
-
- @Nullable
- private NetworkMonitorManager getNetworkMonitorManager(final Network network) {
- // getNetworkAgentInfoForNetwork is thread-safe
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai == null) return null;
-
- // nai.networkMonitor() is thread-safe
- return nai.networkMonitor();
- }
- }
-
- public boolean avoidBadWifi() {
- return mMultinetworkPolicyTracker.getAvoidBadWifi();
- }
-
- /**
- * Return whether the device should maintain continuous, working connectivity by switching away
- * from WiFi networks having no connectivity.
- * @see MultinetworkPolicyTracker#getAvoidBadWifi()
- */
- public boolean shouldAvoidBadWifi() {
- if (!checkNetworkStackPermission()) {
- throw new SecurityException("avoidBadWifi requires NETWORK_STACK permission");
- }
- return avoidBadWifi();
- }
-
- private void updateAvoidBadWifi() {
- for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
- nai.updateScoreForNetworkAgentUpdate();
- }
- rematchAllNetworksAndRequests();
- }
-
- // TODO: Evaluate whether this is of interest to other consumers of
- // MultinetworkPolicyTracker and worth moving out of here.
- private void dumpAvoidBadWifiSettings(IndentingPrintWriter pw) {
- final boolean configRestrict = mMultinetworkPolicyTracker.configRestrictsAvoidBadWifi();
- if (!configRestrict) {
- pw.println("Bad Wi-Fi avoidance: unrestricted");
- return;
- }
-
- pw.println("Bad Wi-Fi avoidance: " + avoidBadWifi());
- pw.increaseIndent();
- pw.println("Config restrict: " + configRestrict);
-
- final String value = mMultinetworkPolicyTracker.getAvoidBadWifiSetting();
- String description;
- // Can't use a switch statement because strings are legal case labels, but null is not.
- if ("0".equals(value)) {
- description = "get stuck";
- } else if (value == null) {
- description = "prompt";
- } else if ("1".equals(value)) {
- description = "avoid";
- } else {
- description = value + " (?)";
- }
- pw.println("User setting: " + description);
- pw.println("Network overrides:");
- pw.increaseIndent();
- for (NetworkAgentInfo nai : networksSortedById()) {
- if (nai.avoidUnvalidated) {
- pw.println(nai.toShortString());
- }
- }
- pw.decreaseIndent();
- pw.decreaseIndent();
- }
-
- // TODO: This method is copied from TetheringNotificationUpdater. Should have a utility class to
- // unify the method.
- private static @NonNull String getSettingsPackageName(@NonNull final PackageManager pm) {
- final Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS);
- final ComponentName settingsComponent = settingsIntent.resolveActivity(pm);
- return settingsComponent != null
- ? settingsComponent.getPackageName() : "com.android.settings";
- }
-
- private void showNetworkNotification(NetworkAgentInfo nai, NotificationType type) {
- final String action;
- final boolean highPriority;
- switch (type) {
- case NO_INTERNET:
- action = ConnectivityManager.ACTION_PROMPT_UNVALIDATED;
- // High priority because it is only displayed for explicitly selected networks.
- highPriority = true;
- break;
- case PRIVATE_DNS_BROKEN:
- action = Settings.ACTION_WIRELESS_SETTINGS;
- // High priority because we should let user know why there is no internet.
- highPriority = true;
- break;
- case LOST_INTERNET:
- action = ConnectivityManager.ACTION_PROMPT_LOST_VALIDATION;
- // High priority because it could help the user avoid unexpected data usage.
- highPriority = true;
- break;
- case PARTIAL_CONNECTIVITY:
- action = ConnectivityManager.ACTION_PROMPT_PARTIAL_CONNECTIVITY;
- // Don't bother the user with a high-priority notification if the network was not
- // explicitly selected by the user.
- highPriority = nai.networkAgentConfig.explicitlySelected;
- break;
- default:
- Log.wtf(TAG, "Unknown notification type " + type);
- return;
- }
-
- Intent intent = new Intent(action);
- if (type != NotificationType.PRIVATE_DNS_BROKEN) {
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK, nai.network);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- // Some OEMs have their own Settings package. Thus, need to get the current using
- // Settings package name instead of just use default name "com.android.settings".
- final String settingsPkgName = getSettingsPackageName(mContext.getPackageManager());
- intent.setClassName(settingsPkgName,
- settingsPkgName + ".wifi.WifiNoInternetDialog");
- }
-
- PendingIntent pendingIntent = PendingIntent.getActivity(
- mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
- 0 /* requestCode */,
- intent,
- PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
-
- mNotifier.showNotification(
- nai.network.getNetId(), type, nai, null, pendingIntent, highPriority);
- }
-
- private boolean shouldPromptUnvalidated(NetworkAgentInfo nai) {
- // Don't prompt if the network is validated, and don't prompt on captive portals
- // because we're already prompting the user to sign in.
- if (nai.everValidated || nai.everCaptivePortalDetected) {
- return false;
- }
-
- // If a network has partial connectivity, always prompt unless the user has already accepted
- // partial connectivity and selected don't ask again. This ensures that if the device
- // automatically connects to a network that has partial Internet access, the user will
- // always be able to use it, either because they've already chosen "don't ask again" or
- // because we have prompt them.
- if (nai.partialConnectivity && !nai.networkAgentConfig.acceptPartialConnectivity) {
- return true;
- }
-
- // If a network has no Internet access, only prompt if the network was explicitly selected
- // and if the user has not already told us to use the network regardless of whether it
- // validated or not.
- if (nai.networkAgentConfig.explicitlySelected
- && !nai.networkAgentConfig.acceptUnvalidated) {
- return true;
- }
-
- return false;
- }
-
- private void handlePromptUnvalidated(Network network) {
- if (VDBG || DDBG) log("handlePromptUnvalidated " + network);
- NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
-
- if (nai == null || !shouldPromptUnvalidated(nai)) {
- return;
- }
-
- // Stop automatically reconnecting to this network in the future. Automatically connecting
- // to a network that provides no or limited connectivity is not useful, because the user
- // cannot use that network except through the notification shown by this method, and the
- // notification is only shown if the network is explicitly selected by the user.
- nai.onPreventAutomaticReconnect();
-
- // TODO: Evaluate if it's needed to wait 8 seconds for triggering notification when
- // NetworkMonitor detects the network is partial connectivity. Need to change the design to
- // popup the notification immediately when the network is partial connectivity.
- if (nai.partialConnectivity) {
- showNetworkNotification(nai, NotificationType.PARTIAL_CONNECTIVITY);
- } else {
- showNetworkNotification(nai, NotificationType.NO_INTERNET);
- }
- }
-
- private void handleNetworkUnvalidated(NetworkAgentInfo nai) {
- NetworkCapabilities nc = nai.networkCapabilities;
- if (DBG) log("handleNetworkUnvalidated " + nai.toShortString() + " cap=" + nc);
-
- if (!nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
- return;
- }
-
- if (mMultinetworkPolicyTracker.shouldNotifyWifiUnvalidated()) {
- showNetworkNotification(nai, NotificationType.LOST_INTERNET);
- }
- }
-
- @Override
- public int getMultipathPreference(Network network) {
- enforceAccessPermission();
-
- NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai != null && nai.networkCapabilities
- .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)) {
- return ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED;
- }
-
- final NetworkPolicyManager netPolicyManager =
- mContext.getSystemService(NetworkPolicyManager.class);
-
- final long token = Binder.clearCallingIdentity();
- final int networkPreference;
- try {
- networkPreference = netPolicyManager.getMultipathPreference(network);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- if (networkPreference != 0) {
- return networkPreference;
- }
- return mMultinetworkPolicyTracker.getMeteredMultipathPreference();
- }
-
- @Override
- public NetworkRequest getDefaultRequest() {
- return mDefaultRequest.mRequests.get(0);
- }
-
- private class InternalHandler extends Handler {
- public InternalHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case EVENT_EXPIRE_NET_TRANSITION_WAKELOCK:
- case EVENT_CLEAR_NET_TRANSITION_WAKELOCK: {
- handleReleaseNetworkTransitionWakelock(msg.what);
- break;
- }
- case EVENT_APPLY_GLOBAL_HTTP_PROXY: {
- mProxyTracker.loadDeprecatedGlobalHttpProxy();
- break;
- }
- case EVENT_PROXY_HAS_CHANGED: {
- final Pair<Network, ProxyInfo> arg = (Pair<Network, ProxyInfo>) msg.obj;
- handleApplyDefaultProxy(arg.second);
- break;
- }
- case EVENT_REGISTER_NETWORK_PROVIDER: {
- handleRegisterNetworkProvider((NetworkProviderInfo) msg.obj);
- break;
- }
- case EVENT_UNREGISTER_NETWORK_PROVIDER: {
- handleUnregisterNetworkProvider((Messenger) msg.obj);
- break;
- }
- case EVENT_REGISTER_NETWORK_OFFER: {
- handleRegisterNetworkOffer((NetworkOffer) msg.obj);
- break;
- }
- case EVENT_UNREGISTER_NETWORK_OFFER: {
- final NetworkOfferInfo offer =
- findNetworkOfferInfoByCallback((INetworkOfferCallback) msg.obj);
- if (null != offer) {
- handleUnregisterNetworkOffer(offer);
- }
- break;
- }
- case EVENT_REGISTER_NETWORK_AGENT: {
- final Pair<NetworkAgentInfo, INetworkMonitor> arg =
- (Pair<NetworkAgentInfo, INetworkMonitor>) msg.obj;
- handleRegisterNetworkAgent(arg.first, arg.second);
- break;
- }
- case EVENT_REGISTER_NETWORK_REQUEST:
- case EVENT_REGISTER_NETWORK_LISTENER: {
- handleRegisterNetworkRequest((NetworkRequestInfo) msg.obj);
- break;
- }
- case EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT:
- case EVENT_REGISTER_NETWORK_LISTENER_WITH_INTENT: {
- handleRegisterNetworkRequestWithIntent(msg);
- break;
- }
- case EVENT_TIMEOUT_NETWORK_REQUEST: {
- NetworkRequestInfo nri = (NetworkRequestInfo) msg.obj;
- handleTimedOutNetworkRequest(nri);
- break;
- }
- case EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT: {
- handleReleaseNetworkRequestWithIntent((PendingIntent) msg.obj, msg.arg1);
- break;
- }
- case EVENT_RELEASE_NETWORK_REQUEST: {
- handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1,
- /* callOnUnavailable */ false);
- break;
- }
- case EVENT_SET_ACCEPT_UNVALIDATED: {
- Network network = (Network) msg.obj;
- handleSetAcceptUnvalidated(network, toBool(msg.arg1), toBool(msg.arg2));
- break;
- }
- case EVENT_SET_ACCEPT_PARTIAL_CONNECTIVITY: {
- Network network = (Network) msg.obj;
- handleSetAcceptPartialConnectivity(network, toBool(msg.arg1),
- toBool(msg.arg2));
- break;
- }
- case EVENT_SET_AVOID_UNVALIDATED: {
- handleSetAvoidUnvalidated((Network) msg.obj);
- break;
- }
- case EVENT_PROMPT_UNVALIDATED: {
- handlePromptUnvalidated((Network) msg.obj);
- break;
- }
- case EVENT_CONFIGURE_ALWAYS_ON_NETWORKS: {
- handleConfigureAlwaysOnNetworks();
- break;
- }
- // Sent by KeepaliveTracker to process an app request on the state machine thread.
- case NetworkAgent.CMD_START_SOCKET_KEEPALIVE: {
- mKeepaliveTracker.handleStartKeepalive(msg);
- break;
- }
- // Sent by KeepaliveTracker to process an app request on the state machine thread.
- case NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE: {
- NetworkAgentInfo nai = getNetworkAgentInfoForNetwork((Network) msg.obj);
- int slot = msg.arg1;
- int reason = msg.arg2;
- mKeepaliveTracker.handleStopKeepalive(nai, slot, reason);
- break;
- }
- case EVENT_REVALIDATE_NETWORK: {
- handleReportNetworkConnectivity((Network) msg.obj, msg.arg1, toBool(msg.arg2));
- break;
- }
- case EVENT_PRIVATE_DNS_SETTINGS_CHANGED:
- handlePrivateDnsSettingsChanged();
- break;
- case EVENT_PRIVATE_DNS_VALIDATION_UPDATE:
- handlePrivateDnsValidationUpdate(
- (PrivateDnsValidationUpdate) msg.obj);
- break;
- case EVENT_UID_BLOCKED_REASON_CHANGED:
- handleUidBlockedReasonChanged(msg.arg1, msg.arg2);
- break;
- case EVENT_SET_REQUIRE_VPN_FOR_UIDS:
- handleSetRequireVpnForUids(toBool(msg.arg1), (UidRange[]) msg.obj);
- break;
- case EVENT_SET_OEM_NETWORK_PREFERENCE: {
- final Pair<OemNetworkPreferences, IOnCompleteListener> arg =
- (Pair<OemNetworkPreferences, IOnCompleteListener>) msg.obj;
- handleSetOemNetworkPreference(arg.first, arg.second);
- break;
- }
- case EVENT_SET_PROFILE_NETWORK_PREFERENCE: {
- final Pair<ProfileNetworkPreferences.Preference, IOnCompleteListener> arg =
- (Pair<ProfileNetworkPreferences.Preference, IOnCompleteListener>)
- msg.obj;
- handleSetProfileNetworkPreference(arg.first, arg.second);
- break;
- }
- case EVENT_REPORT_NETWORK_ACTIVITY:
- mNetworkActivityTracker.handleReportNetworkActivity();
- break;
- }
- }
- }
-
- @Override
- @Deprecated
- public int getLastTetherError(String iface) {
- final TetheringManager tm = (TetheringManager) mContext.getSystemService(
- Context.TETHERING_SERVICE);
- return tm.getLastTetherError(iface);
- }
-
- @Override
- @Deprecated
- public String[] getTetherableIfaces() {
- final TetheringManager tm = (TetheringManager) mContext.getSystemService(
- Context.TETHERING_SERVICE);
- return tm.getTetherableIfaces();
- }
-
- @Override
- @Deprecated
- public String[] getTetheredIfaces() {
- final TetheringManager tm = (TetheringManager) mContext.getSystemService(
- Context.TETHERING_SERVICE);
- return tm.getTetheredIfaces();
- }
-
-
- @Override
- @Deprecated
- public String[] getTetheringErroredIfaces() {
- final TetheringManager tm = (TetheringManager) mContext.getSystemService(
- Context.TETHERING_SERVICE);
-
- return tm.getTetheringErroredIfaces();
- }
-
- @Override
- @Deprecated
- public String[] getTetherableUsbRegexs() {
- final TetheringManager tm = (TetheringManager) mContext.getSystemService(
- Context.TETHERING_SERVICE);
-
- return tm.getTetherableUsbRegexs();
- }
-
- @Override
- @Deprecated
- public String[] getTetherableWifiRegexs() {
- final TetheringManager tm = (TetheringManager) mContext.getSystemService(
- Context.TETHERING_SERVICE);
- return tm.getTetherableWifiRegexs();
- }
-
- // Called when we lose the default network and have no replacement yet.
- // This will automatically be cleared after X seconds or a new default network
- // becomes CONNECTED, whichever happens first. The timer is started by the
- // first caller and not restarted by subsequent callers.
- private void ensureNetworkTransitionWakelock(String forWhom) {
- synchronized (this) {
- if (mNetTransitionWakeLock.isHeld()) {
- return;
- }
- mNetTransitionWakeLock.acquire();
- mLastWakeLockAcquireTimestamp = SystemClock.elapsedRealtime();
- mTotalWakelockAcquisitions++;
- }
- mWakelockLogs.log("ACQUIRE for " + forWhom);
- Message msg = mHandler.obtainMessage(EVENT_EXPIRE_NET_TRANSITION_WAKELOCK);
- final int lockTimeout = mResources.get().getInteger(
- R.integer.config_networkTransitionTimeout);
- mHandler.sendMessageDelayed(msg, lockTimeout);
- }
-
- // Called when we gain a new default network to release the network transition wakelock in a
- // second, to allow a grace period for apps to reconnect over the new network. Pending expiry
- // message is cancelled.
- private void scheduleReleaseNetworkTransitionWakelock() {
- synchronized (this) {
- if (!mNetTransitionWakeLock.isHeld()) {
- return; // expiry message released the lock first.
- }
- }
- // Cancel self timeout on wakelock hold.
- mHandler.removeMessages(EVENT_EXPIRE_NET_TRANSITION_WAKELOCK);
- Message msg = mHandler.obtainMessage(EVENT_CLEAR_NET_TRANSITION_WAKELOCK);
- mHandler.sendMessageDelayed(msg, 1000);
- }
-
- // Called when either message of ensureNetworkTransitionWakelock or
- // scheduleReleaseNetworkTransitionWakelock is processed.
- private void handleReleaseNetworkTransitionWakelock(int eventId) {
- String event = eventName(eventId);
- synchronized (this) {
- if (!mNetTransitionWakeLock.isHeld()) {
- mWakelockLogs.log(String.format("RELEASE: already released (%s)", event));
- Log.w(TAG, "expected Net Transition WakeLock to be held");
- return;
- }
- mNetTransitionWakeLock.release();
- long lockDuration = SystemClock.elapsedRealtime() - mLastWakeLockAcquireTimestamp;
- mTotalWakelockDurationMs += lockDuration;
- mMaxWakelockDurationMs = Math.max(mMaxWakelockDurationMs, lockDuration);
- mTotalWakelockReleases++;
- }
- mWakelockLogs.log(String.format("RELEASE (%s)", event));
- }
-
- // 100 percent is full good, 0 is full bad.
- @Override
- public void reportInetCondition(int networkType, int percentage) {
- NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
- if (nai == null) return;
- reportNetworkConnectivity(nai.network, percentage > 50);
- }
-
- @Override
- public void reportNetworkConnectivity(Network network, boolean hasConnectivity) {
- enforceAccessPermission();
- enforceInternetPermission();
- final int uid = mDeps.getCallingUid();
- final int connectivityInfo = encodeBool(hasConnectivity);
-
- // Handle ConnectivityDiagnostics event before attempting to revalidate the network. This
- // forces an ordering of ConnectivityDiagnostics events in the case where hasConnectivity
- // does not match the known connectivity of the network - this causes NetworkMonitor to
- // revalidate the network and generate a ConnectivityDiagnostics ConnectivityReport event.
- final NetworkAgentInfo nai;
- if (network == null) {
- nai = getDefaultNetwork();
- } else {
- nai = getNetworkAgentInfoForNetwork(network);
- }
- if (nai != null) {
- mConnectivityDiagnosticsHandler.sendMessage(
- mConnectivityDiagnosticsHandler.obtainMessage(
- ConnectivityDiagnosticsHandler.EVENT_NETWORK_CONNECTIVITY_REPORTED,
- connectivityInfo, 0, nai));
- }
-
- mHandler.sendMessage(
- mHandler.obtainMessage(EVENT_REVALIDATE_NETWORK, uid, connectivityInfo, network));
- }
-
- private void handleReportNetworkConnectivity(
- Network network, int uid, boolean hasConnectivity) {
- final NetworkAgentInfo nai;
- if (network == null) {
- nai = getDefaultNetwork();
- } else {
- nai = getNetworkAgentInfoForNetwork(network);
- }
- if (nai == null || nai.networkInfo.getState() == NetworkInfo.State.DISCONNECTING ||
- nai.networkInfo.getState() == NetworkInfo.State.DISCONNECTED) {
- return;
- }
- // Revalidate if the app report does not match our current validated state.
- if (hasConnectivity == nai.lastValidated) {
- return;
- }
- if (DBG) {
- int netid = nai.network.getNetId();
- log("reportNetworkConnectivity(" + netid + ", " + hasConnectivity + ") by " + uid);
- }
- // Validating a network that has not yet connected could result in a call to
- // rematchNetworkAndRequests() which is not meant to work on such networks.
- if (!nai.everConnected) {
- return;
- }
- final NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
- if (isNetworkWithCapabilitiesBlocked(nc, uid, false)) {
- return;
- }
- nai.networkMonitor().forceReevaluation(uid);
- }
-
- // TODO: call into netd.
- private boolean queryUserAccess(int uid, Network network) {
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai == null) return false;
-
- // Any UID can use its default network.
- if (nai == getDefaultNetworkForUid(uid)) return true;
-
- // Privileged apps can use any network.
- if (mPermissionMonitor.hasRestrictedNetworksPermission(uid)) {
- return true;
- }
-
- // An unprivileged UID can use a VPN iff the VPN applies to it.
- if (nai.isVPN()) {
- return nai.networkCapabilities.appliesToUid(uid);
- }
-
- // An unprivileged UID can bypass the VPN that applies to it only if it can protect its
- // sockets, i.e., if it is the owner.
- final NetworkAgentInfo vpn = getVpnForUid(uid);
- if (vpn != null && !vpn.networkAgentConfig.allowBypass
- && uid != vpn.networkCapabilities.getOwnerUid()) {
- return false;
- }
-
- // The UID's permission must be at least sufficient for the network. Since the restricted
- // permission was already checked above, that just leaves background networks.
- if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_FOREGROUND)) {
- return mPermissionMonitor.hasUseBackgroundNetworksPermission(uid);
- }
-
- // Unrestricted network. Anyone gets to use it.
- return true;
- }
-
- /**
- * Returns information about the proxy a certain network is using. If given a null network, it
- * it will return the proxy for the bound network for the caller app or the default proxy if
- * none.
- *
- * @param network the network we want to get the proxy information for.
- * @return Proxy information if a network has a proxy configured, or otherwise null.
- */
- @Override
- public ProxyInfo getProxyForNetwork(Network network) {
- final ProxyInfo globalProxy = mProxyTracker.getGlobalProxy();
- if (globalProxy != null) return globalProxy;
- if (network == null) {
- // Get the network associated with the calling UID.
- final Network activeNetwork = getActiveNetworkForUidInternal(mDeps.getCallingUid(),
- true);
- if (activeNetwork == null) {
- return null;
- }
- return getLinkPropertiesProxyInfo(activeNetwork);
- } else if (mDeps.queryUserAccess(mDeps.getCallingUid(), network, this)) {
- // Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
- // caller may not have.
- return getLinkPropertiesProxyInfo(network);
- }
- // No proxy info available if the calling UID does not have network access.
- return null;
- }
-
-
- private ProxyInfo getLinkPropertiesProxyInfo(Network network) {
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai == null) return null;
- synchronized (nai) {
- final ProxyInfo linkHttpProxy = nai.linkProperties.getHttpProxy();
- return linkHttpProxy == null ? null : new ProxyInfo(linkHttpProxy);
- }
- }
-
- @Override
- public void setGlobalProxy(@Nullable final ProxyInfo proxyProperties) {
- PermissionUtils.enforceNetworkStackPermission(mContext);
- mProxyTracker.setGlobalProxy(proxyProperties);
- }
-
- @Override
- @Nullable
- public ProxyInfo getGlobalProxy() {
- return mProxyTracker.getGlobalProxy();
- }
-
- private void handleApplyDefaultProxy(ProxyInfo proxy) {
- if (proxy != null && TextUtils.isEmpty(proxy.getHost())
- && Uri.EMPTY.equals(proxy.getPacFileUrl())) {
- proxy = null;
- }
- mProxyTracker.setDefaultProxy(proxy);
- }
-
- // If the proxy has changed from oldLp to newLp, resend proxy broadcast. This method gets called
- // when any network changes proxy.
- // TODO: Remove usage of broadcast extras as they are deprecated and not applicable in a
- // multi-network world where an app might be bound to a non-default network.
- private void updateProxy(LinkProperties newLp, LinkProperties oldLp) {
- ProxyInfo newProxyInfo = newLp == null ? null : newLp.getHttpProxy();
- ProxyInfo oldProxyInfo = oldLp == null ? null : oldLp.getHttpProxy();
-
- if (!ProxyTracker.proxyInfoEqual(newProxyInfo, oldProxyInfo)) {
- mProxyTracker.sendProxyBroadcast();
- }
- }
-
- private static class SettingsObserver extends ContentObserver {
- final private HashMap<Uri, Integer> mUriEventMap;
- final private Context mContext;
- final private Handler mHandler;
-
- SettingsObserver(Context context, Handler handler) {
- super(null);
- mUriEventMap = new HashMap<>();
- mContext = context;
- mHandler = handler;
- }
-
- void observe(Uri uri, int what) {
- mUriEventMap.put(uri, what);
- final ContentResolver resolver = mContext.getContentResolver();
- resolver.registerContentObserver(uri, false, this);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- Log.wtf(TAG, "Should never be reached.");
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- final Integer what = mUriEventMap.get(uri);
- if (what != null) {
- mHandler.obtainMessage(what).sendToTarget();
- } else {
- loge("No matching event to send for URI=" + uri);
- }
- }
- }
-
- private static void log(String s) {
- Log.d(TAG, s);
- }
-
- private static void logw(String s) {
- Log.w(TAG, s);
- }
-
- private static void logwtf(String s) {
- Log.wtf(TAG, s);
- }
-
- private static void logwtf(String s, Throwable t) {
- Log.wtf(TAG, s, t);
- }
-
- private static void loge(String s) {
- Log.e(TAG, s);
- }
-
- private static void loge(String s, Throwable t) {
- Log.e(TAG, s, t);
- }
-
- /**
- * Return the information of all ongoing VPNs.
- *
- * <p>This method is used to update NetworkStatsService.
- *
- * <p>Must be called on the handler thread.
- */
- private UnderlyingNetworkInfo[] getAllVpnInfo() {
- ensureRunningOnConnectivityServiceThread();
- if (mLockdownEnabled) {
- return new UnderlyingNetworkInfo[0];
- }
- List<UnderlyingNetworkInfo> infoList = new ArrayList<>();
- for (NetworkAgentInfo nai : mNetworkAgentInfos) {
- UnderlyingNetworkInfo info = createVpnInfo(nai);
- if (info != null) {
- infoList.add(info);
- }
- }
- return infoList.toArray(new UnderlyingNetworkInfo[infoList.size()]);
- }
-
- /**
- * @return VPN information for accounting, or null if we can't retrieve all required
- * information, e.g underlying ifaces.
- */
- private UnderlyingNetworkInfo createVpnInfo(NetworkAgentInfo nai) {
- if (!nai.isVPN()) return null;
-
- Network[] underlyingNetworks = nai.declaredUnderlyingNetworks;
- // see VpnService.setUnderlyingNetworks()'s javadoc about how to interpret
- // the underlyingNetworks list.
- if (underlyingNetworks == null) {
- final NetworkAgentInfo defaultNai = getDefaultNetworkForUid(
- nai.networkCapabilities.getOwnerUid());
- if (defaultNai != null) {
- underlyingNetworks = new Network[] { defaultNai.network };
- }
- }
-
- if (CollectionUtils.isEmpty(underlyingNetworks)) return null;
-
- List<String> interfaces = new ArrayList<>();
- for (Network network : underlyingNetworks) {
- NetworkAgentInfo underlyingNai = getNetworkAgentInfoForNetwork(network);
- if (underlyingNai == null) continue;
- LinkProperties lp = underlyingNai.linkProperties;
- for (String iface : lp.getAllInterfaceNames()) {
- if (!TextUtils.isEmpty(iface)) {
- interfaces.add(iface);
- }
- }
- }
-
- if (interfaces.isEmpty()) return null;
-
- // Must be non-null or NetworkStatsService will crash.
- // Cannot happen in production code because Vpn only registers the NetworkAgent after the
- // tun or ipsec interface is created.
- // TODO: Remove this check.
- if (nai.linkProperties.getInterfaceName() == null) return null;
-
- return new UnderlyingNetworkInfo(nai.networkCapabilities.getOwnerUid(),
- nai.linkProperties.getInterfaceName(), interfaces);
- }
-
- // TODO This needs to be the default network that applies to the NAI.
- private Network[] underlyingNetworksOrDefault(final int ownerUid,
- Network[] underlyingNetworks) {
- final Network defaultNetwork = getNetwork(getDefaultNetworkForUid(ownerUid));
- if (underlyingNetworks == null && defaultNetwork != null) {
- // null underlying networks means to track the default.
- underlyingNetworks = new Network[] { defaultNetwork };
- }
- return underlyingNetworks;
- }
-
- // Returns true iff |network| is an underlying network of |nai|.
- private boolean hasUnderlyingNetwork(NetworkAgentInfo nai, Network network) {
- // TODO: support more than one level of underlying networks, either via a fixed-depth search
- // (e.g., 2 levels of underlying networks), or via loop detection, or....
- if (!nai.supportsUnderlyingNetworks()) return false;
- final Network[] underlying = underlyingNetworksOrDefault(
- nai.networkCapabilities.getOwnerUid(), nai.declaredUnderlyingNetworks);
- return CollectionUtils.contains(underlying, network);
- }
-
- /**
- * Recompute the capabilities for any networks that had a specific network as underlying.
- *
- * When underlying networks change, such networks may have to update capabilities to reflect
- * things like the metered bit, their transports, and so on. The capabilities are calculated
- * immediately. This method runs on the ConnectivityService thread.
- */
- private void propagateUnderlyingNetworkCapabilities(Network updatedNetwork) {
- ensureRunningOnConnectivityServiceThread();
- for (NetworkAgentInfo nai : mNetworkAgentInfos) {
- if (updatedNetwork == null || hasUnderlyingNetwork(nai, updatedNetwork)) {
- updateCapabilitiesForNetwork(nai);
- }
- }
- }
-
- private boolean isUidBlockedByVpn(int uid, List<UidRange> blockedUidRanges) {
- // Determine whether this UID is blocked because of always-on VPN lockdown. If a VPN applies
- // to the UID, then the UID is not blocked because always-on VPN lockdown applies only when
- // a VPN is not up.
- final NetworkAgentInfo vpnNai = getVpnForUid(uid);
- if (vpnNai != null && !vpnNai.networkAgentConfig.allowBypass) return false;
- for (UidRange range : blockedUidRanges) {
- if (range.contains(uid)) return true;
- }
- return false;
- }
-
- @Override
- public void setRequireVpnForUids(boolean requireVpn, UidRange[] ranges) {
- enforceNetworkStackOrSettingsPermission();
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_REQUIRE_VPN_FOR_UIDS,
- encodeBool(requireVpn), 0 /* arg2 */, ranges));
- }
-
- private void handleSetRequireVpnForUids(boolean requireVpn, UidRange[] ranges) {
- if (DBG) {
- Log.d(TAG, "Setting VPN " + (requireVpn ? "" : "not ") + "required for UIDs: "
- + Arrays.toString(ranges));
- }
- // Cannot use a Set since the list of UID ranges might contain duplicates.
- final List<UidRange> newVpnBlockedUidRanges = new ArrayList(mVpnBlockedUidRanges);
- for (int i = 0; i < ranges.length; i++) {
- if (requireVpn) {
- newVpnBlockedUidRanges.add(ranges[i]);
- } else {
- newVpnBlockedUidRanges.remove(ranges[i]);
- }
- }
-
- try {
- mNetd.networkRejectNonSecureVpn(requireVpn, toUidRangeStableParcels(ranges));
- } catch (RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "setRequireVpnForUids(" + requireVpn + ", "
- + Arrays.toString(ranges) + "): netd command failed: " + e);
- }
-
- for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
- final boolean curMetered = nai.networkCapabilities.isMetered();
- maybeNotifyNetworkBlocked(nai, curMetered, curMetered,
- mVpnBlockedUidRanges, newVpnBlockedUidRanges);
- }
-
- mVpnBlockedUidRanges = newVpnBlockedUidRanges;
- }
-
- @Override
- public void setLegacyLockdownVpnEnabled(boolean enabled) {
- enforceNetworkStackOrSettingsPermission();
- mHandler.post(() -> mLockdownEnabled = enabled);
- }
-
- private boolean isLegacyLockdownNai(NetworkAgentInfo nai) {
- return mLockdownEnabled
- && getVpnType(nai) == VpnManager.TYPE_VPN_LEGACY
- && nai.networkCapabilities.appliesToUid(Process.FIRST_APPLICATION_UID);
- }
-
- private NetworkAgentInfo getLegacyLockdownNai() {
- if (!mLockdownEnabled) {
- return null;
- }
- // The legacy lockdown VPN always only applies to userId 0.
- final NetworkAgentInfo nai = getVpnForUid(Process.FIRST_APPLICATION_UID);
- if (nai == null || !isLegacyLockdownNai(nai)) return null;
-
- // The legacy lockdown VPN must always have exactly one underlying network.
- // This code may run on any thread and declaredUnderlyingNetworks may change, so store it in
- // a local variable. There is no need to make a copy because its contents cannot change.
- final Network[] underlying = nai.declaredUnderlyingNetworks;
- if (underlying == null || underlying.length != 1) {
- return null;
- }
-
- // The legacy lockdown VPN always uses the default network.
- // If the VPN's underlying network is no longer the current default network, it means that
- // the default network has just switched, and the VPN is about to disconnect.
- // Report that the VPN is not connected, so the state of NetworkInfo objects overwritten
- // by filterForLegacyLockdown will be set to CONNECTING and not CONNECTED.
- final NetworkAgentInfo defaultNetwork = getDefaultNetwork();
- if (defaultNetwork == null || !defaultNetwork.network.equals(underlying[0])) {
- return null;
- }
-
- return nai;
- };
-
- // TODO: move all callers to filterForLegacyLockdown and delete this method.
- // This likely requires making sendLegacyNetworkBroadcast take a NetworkInfo object instead of
- // just a DetailedState object.
- private DetailedState getLegacyLockdownState(DetailedState origState) {
- if (origState != DetailedState.CONNECTED) {
- return origState;
- }
- return (mLockdownEnabled && getLegacyLockdownNai() == null)
- ? DetailedState.CONNECTING
- : DetailedState.CONNECTED;
- }
-
- private void filterForLegacyLockdown(NetworkInfo ni) {
- if (!mLockdownEnabled || !ni.isConnected()) return;
- // The legacy lockdown VPN replaces the state of every network in CONNECTED state with the
- // state of its VPN. This is to ensure that when an underlying network connects, apps will
- // not see a CONNECTIVITY_ACTION broadcast for a network in state CONNECTED until the VPN
- // comes up, at which point there is a new CONNECTIVITY_ACTION broadcast for the underlying
- // network, this time with a state of CONNECTED.
- //
- // Now that the legacy lockdown code lives in ConnectivityService, and no longer has access
- // to the internal state of the Vpn object, always replace the state with CONNECTING. This
- // is not too far off the truth, since an always-on VPN, when not connected, is always
- // trying to reconnect.
- if (getLegacyLockdownNai() == null) {
- ni.setDetailedState(DetailedState.CONNECTING, "", null);
- }
- }
-
- @Override
- public void setProvisioningNotificationVisible(boolean visible, int networkType,
- String action) {
- enforceSettingsPermission();
- if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
- return;
- }
- final long ident = Binder.clearCallingIdentity();
- try {
- // Concatenate the range of types onto the range of NetIDs.
- int id = NetIdManager.MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE);
- mNotifier.setProvNotificationVisible(visible, id, action);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
- public void setAirplaneMode(boolean enable) {
- enforceAirplaneModePermission();
- final long ident = Binder.clearCallingIdentity();
- try {
- final ContentResolver cr = mContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, encodeBool(enable));
- Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- intent.putExtra("state", enable);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- private void onUserAdded(@NonNull final UserHandle user) {
- mPermissionMonitor.onUserAdded(user);
- if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) {
- handleSetOemNetworkPreference(mOemNetworkPreferences, null);
- }
- }
-
- private void onUserRemoved(@NonNull final UserHandle user) {
- mPermissionMonitor.onUserRemoved(user);
- // If there was a network preference for this user, remove it.
- handleSetProfileNetworkPreference(new ProfileNetworkPreferences.Preference(user, null),
- null /* listener */);
- if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) {
- handleSetOemNetworkPreference(mOemNetworkPreferences, null);
- }
- }
-
- private void onPackageChanged(@NonNull final String packageName) {
- // This is necessary in case a package is added or removed, but also when it's replaced to
- // run as a new UID by its manifest rules. Also, if a separate package shares the same UID
- // as one in the preferences, then it should follow the same routing as that other package,
- // which means updating the rules is never to be needed in this case (whether it joins or
- // leaves a UID with a preference).
- if (isMappedInOemNetworkPreference(packageName)) {
- handleSetOemNetworkPreference(mOemNetworkPreferences, null);
- }
- }
-
- private final BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- ensureRunningOnConnectivityServiceThread();
- final String action = intent.getAction();
- final UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
-
- // User should be filled for below intents, check the existence.
- if (user == null) {
- Log.wtf(TAG, intent.getAction() + " broadcast without EXTRA_USER");
- return;
- }
-
- if (Intent.ACTION_USER_ADDED.equals(action)) {
- onUserAdded(user);
- } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
- onUserRemoved(user);
- } else {
- Log.wtf(TAG, "received unexpected intent: " + action);
- }
- }
- };
-
- private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- ensureRunningOnConnectivityServiceThread();
- switch (intent.getAction()) {
- case Intent.ACTION_PACKAGE_ADDED:
- case Intent.ACTION_PACKAGE_REMOVED:
- case Intent.ACTION_PACKAGE_REPLACED:
- onPackageChanged(intent.getData().getSchemeSpecificPart());
- break;
- default:
- Log.wtf(TAG, "received unexpected intent: " + intent.getAction());
- }
- }
- };
-
- private final HashMap<Messenger, NetworkProviderInfo> mNetworkProviderInfos = new HashMap<>();
- private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>();
-
- private static class NetworkProviderInfo {
- public final String name;
- public final Messenger messenger;
- private final IBinder.DeathRecipient mDeathRecipient;
- public final int providerId;
-
- NetworkProviderInfo(String name, Messenger messenger, int providerId,
- @NonNull IBinder.DeathRecipient deathRecipient) {
- this.name = name;
- this.messenger = messenger;
- this.providerId = providerId;
- mDeathRecipient = deathRecipient;
-
- if (mDeathRecipient == null) {
- throw new AssertionError("Must pass a deathRecipient");
- }
- }
-
- void connect(Context context, Handler handler) {
- try {
- messenger.getBinder().linkToDeath(mDeathRecipient, 0);
- } catch (RemoteException e) {
- mDeathRecipient.binderDied();
- }
- }
- }
-
- private void ensureAllNetworkRequestsHaveType(List<NetworkRequest> requests) {
- for (int i = 0; i < requests.size(); i++) {
- ensureNetworkRequestHasType(requests.get(i));
- }
- }
-
- private void ensureNetworkRequestHasType(NetworkRequest request) {
- if (request.type == NetworkRequest.Type.NONE) {
- throw new IllegalArgumentException(
- "All NetworkRequests in ConnectivityService must have a type");
- }
- }
-
- /**
- * Tracks info about the requester.
- * Also used to notice when the calling process dies so as to self-expire
- */
- @VisibleForTesting
- protected class NetworkRequestInfo implements IBinder.DeathRecipient {
- // The requests to be satisfied in priority order. Non-multilayer requests will only have a
- // single NetworkRequest in mRequests.
- final List<NetworkRequest> mRequests;
-
- // mSatisfier and mActiveRequest rely on one another therefore set them together.
- void setSatisfier(
- @Nullable final NetworkAgentInfo satisfier,
- @Nullable final NetworkRequest activeRequest) {
- mSatisfier = satisfier;
- mActiveRequest = activeRequest;
- }
-
- // The network currently satisfying this NRI. Only one request in an NRI can have a
- // satisfier. For non-multilayer requests, only non-listen requests can have a satisfier.
- @Nullable
- private NetworkAgentInfo mSatisfier;
- NetworkAgentInfo getSatisfier() {
- return mSatisfier;
- }
-
- // The request in mRequests assigned to a network agent. This is null if none of the
- // requests in mRequests can be satisfied. This member has the constraint of only being
- // accessible on the handler thread.
- @Nullable
- private NetworkRequest mActiveRequest;
- NetworkRequest getActiveRequest() {
- return mActiveRequest;
- }
-
- final PendingIntent mPendingIntent;
- boolean mPendingIntentSent;
- @Nullable
- final Messenger mMessenger;
-
- // Information about the caller that caused this object to be created.
- @Nullable
- private final IBinder mBinder;
- final int mPid;
- final int mUid;
- final @NetworkCallback.Flag int mCallbackFlags;
- @Nullable
- final String mCallingAttributionTag;
-
- // Counter keeping track of this NRI.
- final PerUidCounter mPerUidCounter;
-
- // Effective UID of this request. This is different from mUid when a privileged process
- // files a request on behalf of another UID. This UID is used to determine blocked status,
- // UID matching, and so on. mUid above is used for permission checks and to enforce the
- // maximum limit of registered callbacks per UID.
- final int mAsUid;
-
- // In order to preserve the mapping of NetworkRequest-to-callback when apps register
- // callbacks using a returned NetworkRequest, the original NetworkRequest needs to be
- // maintained for keying off of. This is only a concern when the original nri
- // mNetworkRequests changes which happens currently for apps that register callbacks to
- // track the default network. In those cases, the nri is updated to have mNetworkRequests
- // that match the per-app default nri that currently tracks the calling app's uid so that
- // callbacks are fired at the appropriate time. When the callbacks fire,
- // mNetworkRequestForCallback will be used so as to preserve the caller's mapping. When
- // callbacks are updated to key off of an nri vs NetworkRequest, this stops being an issue.
- // TODO b/177608132: make sure callbacks are indexed by NRIs and not NetworkRequest objects.
- @NonNull
- private final NetworkRequest mNetworkRequestForCallback;
- NetworkRequest getNetworkRequestForCallback() {
- return mNetworkRequestForCallback;
- }
-
- /**
- * Get the list of UIDs this nri applies to.
- */
- @NonNull
- private Set<UidRange> getUids() {
- // networkCapabilities.getUids() returns a defensive copy.
- // multilayer requests will all have the same uids so return the first one.
- final Set<UidRange> uids = mRequests.get(0).networkCapabilities.getUidRanges();
- return (null == uids) ? new ArraySet<>() : uids;
- }
-
- NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r,
- @Nullable final PendingIntent pi, @Nullable String callingAttributionTag) {
- this(asUid, Collections.singletonList(r), r, pi, callingAttributionTag);
- }
-
- NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r,
- @NonNull final NetworkRequest requestForCallback, @Nullable final PendingIntent pi,
- @Nullable String callingAttributionTag) {
- ensureAllNetworkRequestsHaveType(r);
- mRequests = initializeRequests(r);
- mNetworkRequestForCallback = requestForCallback;
- mPendingIntent = pi;
- mMessenger = null;
- mBinder = null;
- mPid = getCallingPid();
- mUid = mDeps.getCallingUid();
- mAsUid = asUid;
- mPerUidCounter = getRequestCounter(this);
- mPerUidCounter.incrementCountOrThrow(mUid);
- /**
- * Location sensitive data not included in pending intent. Only included in
- * {@link NetworkCallback}.
- */
- mCallbackFlags = NetworkCallback.FLAG_NONE;
- mCallingAttributionTag = callingAttributionTag;
- }
-
- NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r, @Nullable final Messenger m,
- @Nullable final IBinder binder,
- @NetworkCallback.Flag int callbackFlags,
- @Nullable String callingAttributionTag) {
- this(asUid, Collections.singletonList(r), r, m, binder, callbackFlags,
- callingAttributionTag);
- }
-
- NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r,
- @NonNull final NetworkRequest requestForCallback, @Nullable final Messenger m,
- @Nullable final IBinder binder,
- @NetworkCallback.Flag int callbackFlags,
- @Nullable String callingAttributionTag) {
- super();
- ensureAllNetworkRequestsHaveType(r);
- mRequests = initializeRequests(r);
- mNetworkRequestForCallback = requestForCallback;
- mMessenger = m;
- mBinder = binder;
- mPid = getCallingPid();
- mUid = mDeps.getCallingUid();
- mAsUid = asUid;
- mPendingIntent = null;
- mPerUidCounter = getRequestCounter(this);
- mPerUidCounter.incrementCountOrThrow(mUid);
- mCallbackFlags = callbackFlags;
- mCallingAttributionTag = callingAttributionTag;
- linkDeathRecipient();
- }
-
- NetworkRequestInfo(@NonNull final NetworkRequestInfo nri,
- @NonNull final List<NetworkRequest> r) {
- super();
- ensureAllNetworkRequestsHaveType(r);
- mRequests = initializeRequests(r);
- mNetworkRequestForCallback = nri.getNetworkRequestForCallback();
- final NetworkAgentInfo satisfier = nri.getSatisfier();
- if (null != satisfier) {
- // If the old NRI was satisfied by an NAI, then it may have had an active request.
- // The active request is necessary to figure out what callbacks to send, in
- // particular then a network updates its capabilities.
- // As this code creates a new NRI with a new set of requests, figure out which of
- // the list of requests should be the active request. It is always the first
- // request of the list that can be satisfied by the satisfier since the order of
- // requests is a priority order.
- // Note even in the presence of a satisfier there may not be an active request,
- // when the satisfier is the no-service network.
- NetworkRequest activeRequest = null;
- for (final NetworkRequest candidate : r) {
- if (candidate.canBeSatisfiedBy(satisfier.networkCapabilities)) {
- activeRequest = candidate;
- break;
- }
- }
- setSatisfier(satisfier, activeRequest);
- }
- mMessenger = nri.mMessenger;
- mBinder = nri.mBinder;
- mPid = nri.mPid;
- mUid = nri.mUid;
- mAsUid = nri.mAsUid;
- mPendingIntent = nri.mPendingIntent;
- mPerUidCounter = getRequestCounter(this);
- mPerUidCounter.incrementCountOrThrow(mUid);
- mCallbackFlags = nri.mCallbackFlags;
- mCallingAttributionTag = nri.mCallingAttributionTag;
- linkDeathRecipient();
- }
-
- NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r) {
- this(asUid, Collections.singletonList(r));
- }
-
- NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r) {
- this(asUid, r, r.get(0), null /* pi */, null /* callingAttributionTag */);
- }
-
- // True if this NRI is being satisfied. It also accounts for if the nri has its satisifer
- // set to the mNoServiceNetwork in which case mActiveRequest will be null thus returning
- // false.
- boolean isBeingSatisfied() {
- return (null != mSatisfier && null != mActiveRequest);
- }
-
- boolean isMultilayerRequest() {
- return mRequests.size() > 1;
- }
-
- private List<NetworkRequest> initializeRequests(List<NetworkRequest> r) {
- // Creating a defensive copy to prevent the sender from modifying the list being
- // reflected in the return value of this method.
- final List<NetworkRequest> tempRequests = new ArrayList<>(r);
- return Collections.unmodifiableList(tempRequests);
- }
-
- void decrementRequestCount() {
- mPerUidCounter.decrementCount(mUid);
- }
-
- void linkDeathRecipient() {
- if (null != mBinder) {
- try {
- mBinder.linkToDeath(this, 0);
- } catch (RemoteException e) {
- binderDied();
- }
- }
- }
-
- void unlinkDeathRecipient() {
- if (null != mBinder) {
- mBinder.unlinkToDeath(this, 0);
- }
- }
-
- @Override
- public void binderDied() {
- log("ConnectivityService NetworkRequestInfo binderDied(" +
- mRequests + ", " + mBinder + ")");
- releaseNetworkRequests(mRequests);
- }
-
- @Override
- public String toString() {
- final String asUidString = (mAsUid == mUid) ? "" : " asUid: " + mAsUid;
- return "uid/pid:" + mUid + "/" + mPid + asUidString + " activeRequest: "
- + (mActiveRequest == null ? null : mActiveRequest.requestId)
- + " callbackRequest: "
- + mNetworkRequestForCallback.requestId
- + " " + mRequests
- + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent)
- + " callback flags: " + mCallbackFlags;
- }
- }
-
- private void ensureRequestableCapabilities(NetworkCapabilities networkCapabilities) {
- final String badCapability = networkCapabilities.describeFirstNonRequestableCapability();
- if (badCapability != null) {
- throw new IllegalArgumentException("Cannot request network with " + badCapability);
- }
- }
-
- // This checks that the passed capabilities either do not request a
- // specific SSID/SignalStrength, or the calling app has permission to do so.
- private void ensureSufficientPermissionsForRequest(NetworkCapabilities nc,
- int callerPid, int callerUid, String callerPackageName) {
- if (null != nc.getSsid() && !checkSettingsPermission(callerPid, callerUid)) {
- throw new SecurityException("Insufficient permissions to request a specific SSID");
- }
-
- if (nc.hasSignalStrength()
- && !checkNetworkSignalStrengthWakeupPermission(callerPid, callerUid)) {
- throw new SecurityException(
- "Insufficient permissions to request a specific signal strength");
- }
- mAppOpsManager.checkPackage(callerUid, callerPackageName);
-
- if (!nc.getSubscriptionIds().isEmpty()) {
- enforceNetworkFactoryPermission();
- }
- }
-
- private int[] getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) {
- final SortedSet<Integer> thresholds = new TreeSet<>();
- synchronized (nai) {
- // mNetworkRequests may contain the same value multiple times in case of
- // multilayer requests. It won't matter in this case because the thresholds
- // will then be the same and be deduplicated as they enter the `thresholds` set.
- // TODO : have mNetworkRequests be a Set<NetworkRequestInfo> or the like.
- for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
- for (final NetworkRequest req : nri.mRequests) {
- if (req.networkCapabilities.hasSignalStrength()
- && nai.satisfiesImmutableCapabilitiesOf(req)) {
- thresholds.add(req.networkCapabilities.getSignalStrength());
- }
- }
- }
- }
- return CollectionUtils.toIntArray(new ArrayList<>(thresholds));
- }
-
- private void updateSignalStrengthThresholds(
- NetworkAgentInfo nai, String reason, NetworkRequest request) {
- final int[] thresholdsArray = getSignalStrengthThresholds(nai);
-
- if (VDBG || (DBG && !"CONNECT".equals(reason))) {
- String detail;
- if (request != null && request.networkCapabilities.hasSignalStrength()) {
- detail = reason + " " + request.networkCapabilities.getSignalStrength();
- } else {
- detail = reason;
- }
- log(String.format("updateSignalStrengthThresholds: %s, sending %s to %s",
- detail, Arrays.toString(thresholdsArray), nai.toShortString()));
- }
-
- nai.onSignalStrengthThresholdsUpdated(thresholdsArray);
- }
-
- private void ensureValidNetworkSpecifier(NetworkCapabilities nc) {
- if (nc == null) {
- return;
- }
- NetworkSpecifier ns = nc.getNetworkSpecifier();
- if (ns == null) {
- return;
- }
- if (ns instanceof MatchAllNetworkSpecifier) {
- throw new IllegalArgumentException("A MatchAllNetworkSpecifier is not permitted");
- }
- }
-
- private void ensureValid(NetworkCapabilities nc) {
- ensureValidNetworkSpecifier(nc);
- if (nc.isPrivateDnsBroken()) {
- throw new IllegalArgumentException("Can't request broken private DNS");
- }
- }
-
- private boolean isTargetSdkAtleast(int version, int callingUid,
- @NonNull String callingPackageName) {
- final UserHandle user = UserHandle.getUserHandleForUid(callingUid);
- final PackageManager pm =
- mContext.createContextAsUser(user, 0 /* flags */).getPackageManager();
- try {
- final int callingVersion = pm.getTargetSdkVersion(callingPackageName);
- if (callingVersion < version) return false;
- } catch (PackageManager.NameNotFoundException e) { }
- return true;
- }
-
- @Override
- public NetworkRequest requestNetwork(int asUid, NetworkCapabilities networkCapabilities,
- int reqTypeInt, Messenger messenger, int timeoutMs, IBinder binder,
- int legacyType, int callbackFlags, @NonNull String callingPackageName,
- @Nullable String callingAttributionTag) {
- if (legacyType != TYPE_NONE && !checkNetworkStackPermission()) {
- if (isTargetSdkAtleast(Build.VERSION_CODES.M, mDeps.getCallingUid(),
- callingPackageName)) {
- throw new SecurityException("Insufficient permissions to specify legacy type");
- }
- }
- final NetworkCapabilities defaultNc = mDefaultRequest.mRequests.get(0).networkCapabilities;
- final int callingUid = mDeps.getCallingUid();
- // Privileged callers can track the default network of another UID by passing in a UID.
- if (asUid != Process.INVALID_UID) {
- enforceSettingsPermission();
- } else {
- asUid = callingUid;
- }
- final NetworkRequest.Type reqType;
- try {
- reqType = NetworkRequest.Type.values()[reqTypeInt];
- } catch (ArrayIndexOutOfBoundsException e) {
- throw new IllegalArgumentException("Unsupported request type " + reqTypeInt);
- }
- switch (reqType) {
- case TRACK_DEFAULT:
- // If the request type is TRACK_DEFAULT, the passed {@code networkCapabilities}
- // is unused and will be replaced by ones appropriate for the UID (usually, the
- // calling app). This allows callers to keep track of the default network.
- networkCapabilities = copyDefaultNetworkCapabilitiesForUid(
- defaultNc, asUid, callingUid, callingPackageName);
- enforceAccessPermission();
- break;
- case TRACK_SYSTEM_DEFAULT:
- enforceSettingsPermission();
- networkCapabilities = new NetworkCapabilities(defaultNc);
- break;
- case BACKGROUND_REQUEST:
- enforceNetworkStackOrSettingsPermission();
- // Fall-through since other checks are the same with normal requests.
- case REQUEST:
- networkCapabilities = new NetworkCapabilities(networkCapabilities);
- enforceNetworkRequestPermissions(networkCapabilities, callingPackageName,
- callingAttributionTag);
- // TODO: this is incorrect. We mark the request as metered or not depending on
- // the state of the app when the request is filed, but we never change the
- // request if the app changes network state. http://b/29964605
- enforceMeteredApnPolicy(networkCapabilities);
- break;
- case LISTEN_FOR_BEST:
- enforceAccessPermission();
- networkCapabilities = new NetworkCapabilities(networkCapabilities);
- break;
- default:
- throw new IllegalArgumentException("Unsupported request type " + reqType);
- }
- ensureRequestableCapabilities(networkCapabilities);
- ensureSufficientPermissionsForRequest(networkCapabilities,
- Binder.getCallingPid(), callingUid, callingPackageName);
-
- // Enforce FOREGROUND if the caller does not have permission to use background network.
- if (reqType == LISTEN_FOR_BEST) {
- restrictBackgroundRequestForCaller(networkCapabilities);
- }
-
- // Set the UID range for this request to the single UID of the requester, unless the
- // requester has the permission to specify other UIDs.
- // This will overwrite any allowed UIDs in the requested capabilities. Though there
- // are no visible methods to set the UIDs, an app could use reflection to try and get
- // networks for other apps so it's essential that the UIDs are overwritten.
- // Also set the requester UID and package name in the request.
- restrictRequestUidsForCallerAndSetRequestorInfo(networkCapabilities,
- callingUid, callingPackageName);
-
- if (timeoutMs < 0) {
- throw new IllegalArgumentException("Bad timeout specified");
- }
- ensureValid(networkCapabilities);
-
- final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
- nextNetworkRequestId(), reqType);
- final NetworkRequestInfo nri = getNriToRegister(
- asUid, networkRequest, messenger, binder, callbackFlags,
- callingAttributionTag);
- if (DBG) log("requestNetwork for " + nri);
-
- // For TRACK_SYSTEM_DEFAULT callbacks, the capabilities have been modified since they were
- // copied from the default request above. (This is necessary to ensure, for example, that
- // the callback does not leak sensitive information to unprivileged apps.) Check that the
- // changes don't alter request matching.
- if (reqType == NetworkRequest.Type.TRACK_SYSTEM_DEFAULT &&
- (!networkCapabilities.equalRequestableCapabilities(defaultNc))) {
- throw new IllegalStateException(
- "TRACK_SYSTEM_DEFAULT capabilities don't match default request: "
- + networkCapabilities + " vs. " + defaultNc);
- }
-
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
- if (timeoutMs > 0) {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST,
- nri), timeoutMs);
- }
- return networkRequest;
- }
-
- /**
- * Return the nri to be used when registering a network request. Specifically, this is used with
- * requests registered to track the default request. If there is currently a per-app default
- * tracking the app requestor, then we need to create a version of this nri that mirrors that of
- * the tracking per-app default so that callbacks are sent to the app requestor appropriately.
- * @param asUid the uid on behalf of which to file the request. Different from requestorUid
- * when a privileged caller is tracking the default network for another uid.
- * @param nr the network request for the nri.
- * @param msgr the messenger for the nri.
- * @param binder the binder for the nri.
- * @param callingAttributionTag the calling attribution tag for the nri.
- * @return the nri to register.
- */
- private NetworkRequestInfo getNriToRegister(final int asUid, @NonNull final NetworkRequest nr,
- @Nullable final Messenger msgr, @Nullable final IBinder binder,
- @NetworkCallback.Flag int callbackFlags,
- @Nullable String callingAttributionTag) {
- final List<NetworkRequest> requests;
- if (NetworkRequest.Type.TRACK_DEFAULT == nr.type) {
- requests = copyDefaultNetworkRequestsForUid(
- asUid, nr.getRequestorUid(), nr.getRequestorPackageName());
- } else {
- requests = Collections.singletonList(nr);
- }
- return new NetworkRequestInfo(
- asUid, requests, nr, msgr, binder, callbackFlags, callingAttributionTag);
- }
-
- private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities,
- String callingPackageName, String callingAttributionTag) {
- if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) == false) {
- enforceConnectivityRestrictedNetworksPermission();
- } else {
- enforceChangePermission(callingPackageName, callingAttributionTag);
- }
- }
-
- @Override
- public boolean requestBandwidthUpdate(Network network) {
- enforceAccessPermission();
- NetworkAgentInfo nai = null;
- if (network == null) {
- return false;
- }
- synchronized (mNetworkForNetId) {
- nai = mNetworkForNetId.get(network.getNetId());
- }
- if (nai != null) {
- nai.onBandwidthUpdateRequested();
- synchronized (mBandwidthRequests) {
- final int uid = mDeps.getCallingUid();
- Integer uidReqs = mBandwidthRequests.get(uid);
- if (uidReqs == null) {
- uidReqs = 0;
- }
- mBandwidthRequests.put(uid, ++uidReqs);
- }
- return true;
- }
- return false;
- }
-
- private boolean isSystem(int uid) {
- return uid < Process.FIRST_APPLICATION_UID;
- }
-
- private void enforceMeteredApnPolicy(NetworkCapabilities networkCapabilities) {
- final int uid = mDeps.getCallingUid();
- if (isSystem(uid)) {
- // Exemption for system uid.
- return;
- }
- if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
- // Policy already enforced.
- return;
- }
- final long ident = Binder.clearCallingIdentity();
- try {
- if (mPolicyManager.isUidRestrictedOnMeteredNetworks(uid)) {
- // If UID is restricted, don't allow them to bring up metered APNs.
- networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override
- public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities,
- PendingIntent operation, @NonNull String callingPackageName,
- @Nullable String callingAttributionTag) {
- Objects.requireNonNull(operation, "PendingIntent cannot be null.");
- final int callingUid = mDeps.getCallingUid();
- networkCapabilities = new NetworkCapabilities(networkCapabilities);
- enforceNetworkRequestPermissions(networkCapabilities, callingPackageName,
- callingAttributionTag);
- enforceMeteredApnPolicy(networkCapabilities);
- ensureRequestableCapabilities(networkCapabilities);
- ensureSufficientPermissionsForRequest(networkCapabilities,
- Binder.getCallingPid(), callingUid, callingPackageName);
- ensureValidNetworkSpecifier(networkCapabilities);
- restrictRequestUidsForCallerAndSetRequestorInfo(networkCapabilities,
- callingUid, callingPackageName);
-
- NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
- nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
- NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, networkRequest, operation,
- callingAttributionTag);
- if (DBG) log("pendingRequest for " + nri);
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT,
- nri));
- return networkRequest;
- }
-
- private void releasePendingNetworkRequestWithDelay(PendingIntent operation) {
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT,
- mDeps.getCallingUid(), 0, operation), mReleasePendingIntentDelayMs);
- }
-
- @Override
- public void releasePendingNetworkRequest(PendingIntent operation) {
- Objects.requireNonNull(operation, "PendingIntent cannot be null.");
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT,
- mDeps.getCallingUid(), 0, operation));
- }
-
- // In order to implement the compatibility measure for pre-M apps that call
- // WifiManager.enableNetwork(..., true) without also binding to that network explicitly,
- // WifiManager registers a network listen for the purpose of calling setProcessDefaultNetwork.
- // This ensures it has permission to do so.
- private boolean hasWifiNetworkListenPermission(NetworkCapabilities nc) {
- if (nc == null) {
- return false;
- }
- int[] transportTypes = nc.getTransportTypes();
- if (transportTypes.length != 1 || transportTypes[0] != NetworkCapabilities.TRANSPORT_WIFI) {
- return false;
- }
- try {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.ACCESS_WIFI_STATE,
- "ConnectivityService");
- } catch (SecurityException e) {
- return false;
- }
- return true;
- }
-
- @Override
- public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,
- Messenger messenger, IBinder binder,
- @NetworkCallback.Flag int callbackFlags,
- @NonNull String callingPackageName, @NonNull String callingAttributionTag) {
- final int callingUid = mDeps.getCallingUid();
- if (!hasWifiNetworkListenPermission(networkCapabilities)) {
- enforceAccessPermission();
- }
-
- NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
- ensureSufficientPermissionsForRequest(networkCapabilities,
- Binder.getCallingPid(), callingUid, callingPackageName);
- restrictRequestUidsForCallerAndSetRequestorInfo(nc, callingUid, callingPackageName);
- // Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
- // make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
- // onLost and onAvailable callbacks when networks move in and out of the background.
- // There is no need to do this for requests because an app without CHANGE_NETWORK_STATE
- // can't request networks.
- restrictBackgroundRequestForCaller(nc);
- ensureValid(nc);
-
- NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
- NetworkRequest.Type.LISTEN);
- NetworkRequestInfo nri =
- new NetworkRequestInfo(callingUid, networkRequest, messenger, binder, callbackFlags,
- callingAttributionTag);
- if (VDBG) log("listenForNetwork for " + nri);
-
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
- return networkRequest;
- }
-
- @Override
- public void pendingListenForNetwork(NetworkCapabilities networkCapabilities,
- PendingIntent operation, @NonNull String callingPackageName,
- @Nullable String callingAttributionTag) {
- Objects.requireNonNull(operation, "PendingIntent cannot be null.");
- final int callingUid = mDeps.getCallingUid();
- if (!hasWifiNetworkListenPermission(networkCapabilities)) {
- enforceAccessPermission();
- }
- ensureValid(networkCapabilities);
- ensureSufficientPermissionsForRequest(networkCapabilities,
- Binder.getCallingPid(), callingUid, callingPackageName);
- final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
- restrictRequestUidsForCallerAndSetRequestorInfo(nc, callingUid, callingPackageName);
-
- NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
- NetworkRequest.Type.LISTEN);
- NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, networkRequest, operation,
- callingAttributionTag);
- if (VDBG) log("pendingListenForNetwork for " + nri);
-
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
- }
-
- /** Returns the next Network provider ID. */
- public final int nextNetworkProviderId() {
- return mNextNetworkProviderId.getAndIncrement();
- }
-
- private void releaseNetworkRequests(List<NetworkRequest> networkRequests) {
- for (int i = 0; i < networkRequests.size(); i++) {
- releaseNetworkRequest(networkRequests.get(i));
- }
- }
-
- @Override
- public void releaseNetworkRequest(NetworkRequest networkRequest) {
- ensureNetworkRequestHasType(networkRequest);
- mHandler.sendMessage(mHandler.obtainMessage(
- EVENT_RELEASE_NETWORK_REQUEST, mDeps.getCallingUid(), 0, networkRequest));
- }
-
- private void handleRegisterNetworkProvider(NetworkProviderInfo npi) {
- if (mNetworkProviderInfos.containsKey(npi.messenger)) {
- // Avoid creating duplicates. even if an app makes a direct AIDL call.
- // This will never happen if an app calls ConnectivityManager#registerNetworkProvider,
- // as that will throw if a duplicate provider is registered.
- loge("Attempt to register existing NetworkProviderInfo "
- + mNetworkProviderInfos.get(npi.messenger).name);
- return;
- }
-
- if (DBG) log("Got NetworkProvider Messenger for " + npi.name);
- mNetworkProviderInfos.put(npi.messenger, npi);
- npi.connect(mContext, mTrackerHandler);
- }
-
- @Override
- public int registerNetworkProvider(Messenger messenger, String name) {
- enforceNetworkFactoryOrSettingsPermission();
- Objects.requireNonNull(messenger, "messenger must be non-null");
- NetworkProviderInfo npi = new NetworkProviderInfo(name, messenger,
- nextNetworkProviderId(), () -> unregisterNetworkProvider(messenger));
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_PROVIDER, npi));
- return npi.providerId;
- }
-
- @Override
- public void unregisterNetworkProvider(Messenger messenger) {
- enforceNetworkFactoryOrSettingsPermission();
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_PROVIDER, messenger));
- }
-
- @Override
- public void offerNetwork(final int providerId,
- @NonNull final NetworkScore score, @NonNull final NetworkCapabilities caps,
- @NonNull final INetworkOfferCallback callback) {
- Objects.requireNonNull(score);
- Objects.requireNonNull(caps);
- Objects.requireNonNull(callback);
- final NetworkOffer offer = new NetworkOffer(
- FullScore.makeProspectiveScore(score, caps), caps, callback, providerId);
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_OFFER, offer));
- }
-
- @Override
- public void unofferNetwork(@NonNull final INetworkOfferCallback callback) {
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_OFFER, callback));
- }
-
- private void handleUnregisterNetworkProvider(Messenger messenger) {
- NetworkProviderInfo npi = mNetworkProviderInfos.remove(messenger);
- if (npi == null) {
- loge("Failed to find Messenger in unregisterNetworkProvider");
- return;
- }
- // Unregister all the offers from this provider
- final ArrayList<NetworkOfferInfo> toRemove = new ArrayList<>();
- for (final NetworkOfferInfo noi : mNetworkOffers) {
- if (noi.offer.providerId == npi.providerId) {
- // Can't call handleUnregisterNetworkOffer here because iteration is in progress
- toRemove.add(noi);
- }
- }
- for (final NetworkOfferInfo noi : toRemove) {
- handleUnregisterNetworkOffer(noi);
- }
- if (DBG) log("unregisterNetworkProvider for " + npi.name);
- }
-
- @Override
- public void declareNetworkRequestUnfulfillable(@NonNull final NetworkRequest request) {
- if (request.hasTransport(TRANSPORT_TEST)) {
- enforceNetworkFactoryOrTestNetworksPermission();
- } else {
- enforceNetworkFactoryPermission();
- }
- final NetworkRequestInfo nri = mNetworkRequests.get(request);
- if (nri != null) {
- // declareNetworkRequestUnfulfillable() paths don't apply to multilayer requests.
- ensureNotMultilayerRequest(nri, "declareNetworkRequestUnfulfillable");
- mHandler.post(() -> handleReleaseNetworkRequest(
- nri.mRequests.get(0), mDeps.getCallingUid(), true));
- }
- }
-
- // NOTE: Accessed on multiple threads, must be synchronized on itself.
- @GuardedBy("mNetworkForNetId")
- private final SparseArray<NetworkAgentInfo> mNetworkForNetId = new SparseArray<>();
- // NOTE: Accessed on multiple threads, synchronized with mNetworkForNetId.
- // An entry is first reserved with NetIdManager, prior to being added to mNetworkForNetId, so
- // there may not be a strict 1:1 correlation between the two.
- private final NetIdManager mNetIdManager;
-
- // NetworkAgentInfo keyed off its connecting messenger
- // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays
- // NOTE: Only should be accessed on ConnectivityServiceThread, except dump().
- private final ArraySet<NetworkAgentInfo> mNetworkAgentInfos = new ArraySet<>();
-
- // UID ranges for users that are currently blocked by VPNs.
- // This array is accessed and iterated on multiple threads without holding locks, so its
- // contents must never be mutated. When the ranges change, the array is replaced with a new one
- // (on the handler thread).
- private volatile List<UidRange> mVpnBlockedUidRanges = new ArrayList<>();
-
- // Must only be accessed on the handler thread
- @NonNull
- private final ArrayList<NetworkOfferInfo> mNetworkOffers = new ArrayList<>();
-
- @GuardedBy("mBlockedAppUids")
- private final HashSet<Integer> mBlockedAppUids = new HashSet<>();
-
- // Current OEM network preferences. This object must only be written to on the handler thread.
- // Since it is immutable and always non-null, other threads may read it if they only care
- // about seeing a consistent object but not that it is current.
- @NonNull
- private OemNetworkPreferences mOemNetworkPreferences =
- new OemNetworkPreferences.Builder().build();
- // Current per-profile network preferences. This object follows the same threading rules as
- // the OEM network preferences above.
- @NonNull
- private ProfileNetworkPreferences mProfileNetworkPreferences = new ProfileNetworkPreferences();
-
- // OemNetworkPreferences activity String log entries.
- private static final int MAX_OEM_NETWORK_PREFERENCE_LOGS = 20;
- @NonNull
- private final LocalLog mOemNetworkPreferencesLogs =
- new LocalLog(MAX_OEM_NETWORK_PREFERENCE_LOGS);
-
- /**
- * Determine whether a given package has a mapping in the current OemNetworkPreferences.
- * @param packageName the package name to check existence of a mapping for.
- * @return true if a mapping exists, false otherwise
- */
- private boolean isMappedInOemNetworkPreference(@NonNull final String packageName) {
- return mOemNetworkPreferences.getNetworkPreferences().containsKey(packageName);
- }
-
- // The always-on request for an Internet-capable network that apps without a specific default
- // fall back to.
- @VisibleForTesting
- @NonNull
- final NetworkRequestInfo mDefaultRequest;
- // Collection of NetworkRequestInfo's used for default networks.
- @VisibleForTesting
- @NonNull
- final ArraySet<NetworkRequestInfo> mDefaultNetworkRequests = new ArraySet<>();
-
- private boolean isPerAppDefaultRequest(@NonNull final NetworkRequestInfo nri) {
- return (mDefaultNetworkRequests.contains(nri) && mDefaultRequest != nri);
- }
-
- /**
- * Return the default network request currently tracking the given uid.
- * @param uid the uid to check.
- * @return the NetworkRequestInfo tracking the given uid.
- */
- @NonNull
- private NetworkRequestInfo getDefaultRequestTrackingUid(final int uid) {
- for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
- if (nri == mDefaultRequest) {
- continue;
- }
- // Checking the first request is sufficient as only multilayer requests will have more
- // than one request and for multilayer, all requests will track the same uids.
- if (nri.mRequests.get(0).networkCapabilities.appliesToUid(uid)) {
- return nri;
- }
- }
- return mDefaultRequest;
- }
-
- /**
- * Get a copy of the network requests of the default request that is currently tracking the
- * given uid.
- * @param asUid the uid on behalf of which to file the request. Different from requestorUid
- * when a privileged caller is tracking the default network for another uid.
- * @param requestorUid the uid to check the default for.
- * @param requestorPackageName the requestor's package name.
- * @return a copy of the default's NetworkRequest that is tracking the given uid.
- */
- @NonNull
- private List<NetworkRequest> copyDefaultNetworkRequestsForUid(
- final int asUid, final int requestorUid, @NonNull final String requestorPackageName) {
- return copyNetworkRequestsForUid(
- getDefaultRequestTrackingUid(asUid).mRequests,
- asUid, requestorUid, requestorPackageName);
- }
-
- /**
- * Copy the given nri's NetworkRequest collection.
- * @param requestsToCopy the NetworkRequest collection to be copied.
- * @param asUid the uid on behalf of which to file the request. Different from requestorUid
- * when a privileged caller is tracking the default network for another uid.
- * @param requestorUid the uid to set on the copied collection.
- * @param requestorPackageName the package name to set on the copied collection.
- * @return the copied NetworkRequest collection.
- */
- @NonNull
- private List<NetworkRequest> copyNetworkRequestsForUid(
- @NonNull final List<NetworkRequest> requestsToCopy, final int asUid,
- final int requestorUid, @NonNull final String requestorPackageName) {
- final List<NetworkRequest> requests = new ArrayList<>();
- for (final NetworkRequest nr : requestsToCopy) {
- requests.add(new NetworkRequest(copyDefaultNetworkCapabilitiesForUid(
- nr.networkCapabilities, asUid, requestorUid, requestorPackageName),
- nr.legacyType, nextNetworkRequestId(), nr.type));
- }
- return requests;
- }
-
- @NonNull
- private NetworkCapabilities copyDefaultNetworkCapabilitiesForUid(
- @NonNull final NetworkCapabilities netCapToCopy, final int asUid,
- final int requestorUid, @NonNull final String requestorPackageName) {
- // These capabilities are for a TRACK_DEFAULT callback, so:
- // 1. Remove NET_CAPABILITY_VPN, because it's (currently!) the only difference between
- // mDefaultRequest and a per-UID default request.
- // TODO: stop depending on the fact that these two unrelated things happen to be the same
- // 2. Always set the UIDs to asUid. restrictRequestUidsForCallerAndSetRequestorInfo will
- // not do this in the case of a privileged application.
- final NetworkCapabilities netCap = new NetworkCapabilities(netCapToCopy);
- netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
- netCap.setSingleUid(asUid);
- restrictRequestUidsForCallerAndSetRequestorInfo(
- netCap, requestorUid, requestorPackageName);
- return netCap;
- }
-
- /**
- * Get the nri that is currently being tracked for callbacks by per-app defaults.
- * @param nr the network request to check for equality against.
- * @return the nri if one exists, null otherwise.
- */
- @Nullable
- private NetworkRequestInfo getNriForAppRequest(@NonNull final NetworkRequest nr) {
- for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (nri.getNetworkRequestForCallback().equals(nr)) {
- return nri;
- }
- }
- return null;
- }
-
- /**
- * Check if an nri is currently being managed by per-app default networking.
- * @param nri the nri to check.
- * @return true if this nri is currently being managed by per-app default networking.
- */
- private boolean isPerAppTrackedNri(@NonNull final NetworkRequestInfo nri) {
- // nri.mRequests.get(0) is only different from the original request filed in
- // nri.getNetworkRequestForCallback() if nri.mRequests was changed by per-app default
- // functionality therefore if these two don't match, it means this particular nri is
- // currently being managed by a per-app default.
- return nri.getNetworkRequestForCallback() != nri.mRequests.get(0);
- }
-
- /**
- * Determine if an nri is a managed default request that disallows default networking.
- * @param nri the request to evaluate
- * @return true if device-default networking is disallowed
- */
- private boolean isDefaultBlocked(@NonNull final NetworkRequestInfo nri) {
- // Check if this nri is a managed default that supports the default network at its
- // lowest priority request.
- final NetworkRequest defaultNetworkRequest = mDefaultRequest.mRequests.get(0);
- final NetworkCapabilities lowestPriorityNetCap =
- nri.mRequests.get(nri.mRequests.size() - 1).networkCapabilities;
- return isPerAppDefaultRequest(nri)
- && !(defaultNetworkRequest.networkCapabilities.equalRequestableCapabilities(
- lowestPriorityNetCap));
- }
-
- // Request used to optionally keep mobile data active even when higher
- // priority networks like Wi-Fi are active.
- private final NetworkRequest mDefaultMobileDataRequest;
-
- // Request used to optionally keep wifi data active even when higher
- // priority networks like ethernet are active.
- private final NetworkRequest mDefaultWifiRequest;
-
- // Request used to optionally keep vehicle internal network always active
- private final NetworkRequest mDefaultVehicleRequest;
-
- // Sentinel NAI used to direct apps with default networks that should have no connectivity to a
- // network with no service. This NAI should never be matched against, nor should any public API
- // ever return the associated network. For this reason, this NAI is not in the list of available
- // NAIs. It is used in computeNetworkReassignment() to be set as the satisfier for non-device
- // default requests that don't support using the device default network which will ultimately
- // allow ConnectivityService to use this no-service network when calling makeDefaultForApps().
- @VisibleForTesting
- final NetworkAgentInfo mNoServiceNetwork;
-
- // The NetworkAgentInfo currently satisfying the default request, if any.
- private NetworkAgentInfo getDefaultNetwork() {
- return mDefaultRequest.mSatisfier;
- }
-
- private NetworkAgentInfo getDefaultNetworkForUid(final int uid) {
- for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
- // Currently, all network requests will have the same uids therefore checking the first
- // one is sufficient. If/when uids are tracked at the nri level, this can change.
- final Set<UidRange> uids = nri.mRequests.get(0).networkCapabilities.getUidRanges();
- if (null == uids) {
- continue;
- }
- for (final UidRange range : uids) {
- if (range.contains(uid)) {
- return nri.getSatisfier();
- }
- }
- }
- return getDefaultNetwork();
- }
-
- @Nullable
- private Network getNetwork(@Nullable NetworkAgentInfo nai) {
- return nai != null ? nai.network : null;
- }
-
- private void ensureRunningOnConnectivityServiceThread() {
- if (mHandler.getLooper().getThread() != Thread.currentThread()) {
- throw new IllegalStateException(
- "Not running on ConnectivityService thread: "
- + Thread.currentThread().getName());
- }
- }
-
- @VisibleForTesting
- protected boolean isDefaultNetwork(NetworkAgentInfo nai) {
- return nai == getDefaultNetwork();
- }
-
- /**
- * Register a new agent with ConnectivityService to handle a network.
- *
- * @param na a reference for ConnectivityService to contact the agent asynchronously.
- * @param networkInfo the initial info associated with this network. It can be updated later :
- * see {@link #updateNetworkInfo}.
- * @param linkProperties the initial link properties of this network. They can be updated
- * later : see {@link #updateLinkProperties}.
- * @param networkCapabilities the initial capabilites of this network. They can be updated
- * later : see {@link #updateCapabilities}.
- * @param initialScore the initial score of the network. See
- * {@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 Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo,
- LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
- @NonNull NetworkScore initialScore, NetworkAgentConfig networkAgentConfig,
- int providerId) {
- Objects.requireNonNull(networkInfo, "networkInfo must not be null");
- Objects.requireNonNull(linkProperties, "linkProperties must not be null");
- Objects.requireNonNull(networkCapabilities, "networkCapabilities must not be null");
- Objects.requireNonNull(initialScore, "initialScore must not be null");
- Objects.requireNonNull(networkAgentConfig, "networkAgentConfig must not be null");
- if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
- enforceAnyPermissionOf(Manifest.permission.MANAGE_TEST_NETWORKS);
- } else {
- enforceNetworkFactoryPermission();
- }
-
- final int uid = mDeps.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- return registerNetworkAgentInternal(na, networkInfo, linkProperties,
- networkCapabilities, initialScore, networkAgentConfig, providerId, uid);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- private Network registerNetworkAgentInternal(INetworkAgent na, NetworkInfo networkInfo,
- LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
- NetworkScore currentScore, NetworkAgentConfig networkAgentConfig, int providerId,
- int uid) {
- if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
- // Strictly, sanitizing here is unnecessary as the capabilities will be sanitized in
- // the call to mixInCapabilities below anyway, but sanitizing here means the NAI never
- // sees capabilities that may be malicious, which might prevent mistakes in the future.
- networkCapabilities = new NetworkCapabilities(networkCapabilities);
- networkCapabilities.restrictCapabilitesForTestNetwork(uid);
- }
-
- LinkProperties lp = new LinkProperties(linkProperties);
-
- final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
- final NetworkAgentInfo nai = new NetworkAgentInfo(na,
- new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
- currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
- this, mNetd, mDnsResolver, providerId, uid, mLingerDelayMs,
- mQosCallbackTracker, mDeps);
-
- // Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
- processCapabilitiesFromAgent(nai, nc);
- nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
- processLinkPropertiesFromAgent(nai, nai.linkProperties);
-
- final String extraInfo = networkInfo.getExtraInfo();
- final String name = TextUtils.isEmpty(extraInfo)
- ? nai.networkCapabilities.getSsid() : extraInfo;
- if (DBG) log("registerNetworkAgent " + nai);
- mDeps.getNetworkStack().makeNetworkMonitor(
- nai.network, name, new NetworkMonitorCallbacks(nai));
- // NetworkAgentInfo registration will finish when the NetworkMonitor is created.
- // If the network disconnects or sends any other event before that, messages are deferred by
- // NetworkAgent until nai.connect(), which will be called when finalizing the
- // registration.
- return nai.network;
- }
-
- private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) {
- nai.onNetworkMonitorCreated(networkMonitor);
- if (VDBG) log("Got NetworkAgent Messenger");
- mNetworkAgentInfos.add(nai);
- synchronized (mNetworkForNetId) {
- mNetworkForNetId.put(nai.network.getNetId(), nai);
- }
-
- try {
- networkMonitor.start();
- } catch (RemoteException e) {
- e.rethrowAsRuntimeException();
- }
- nai.notifyRegistered();
- NetworkInfo networkInfo = nai.networkInfo;
- updateNetworkInfo(nai, networkInfo);
- updateUids(nai, null, nai.networkCapabilities);
- }
-
- private class NetworkOfferInfo implements IBinder.DeathRecipient {
- @NonNull public final NetworkOffer offer;
-
- NetworkOfferInfo(@NonNull final NetworkOffer offer) {
- this.offer = offer;
- }
-
- @Override
- public void binderDied() {
- mHandler.post(() -> handleUnregisterNetworkOffer(this));
- }
- }
-
- private boolean isNetworkProviderWithIdRegistered(final int providerId) {
- for (final NetworkProviderInfo npi : mNetworkProviderInfos.values()) {
- if (npi.providerId == providerId) return true;
- }
- return false;
- }
-
- /**
- * Register or update a network offer.
- * @param newOffer The new offer. If the callback member is the same as an existing
- * offer, it is an update of that offer.
- */
- private void handleRegisterNetworkOffer(@NonNull final NetworkOffer newOffer) {
- ensureRunningOnConnectivityServiceThread();
- if (!isNetworkProviderWithIdRegistered(newOffer.providerId)) {
- // This may actually happen if a provider updates its score or registers and then
- // immediately unregisters. The offer would still be in the handler queue, but the
- // provider would have been removed.
- if (DBG) log("Received offer from an unregistered provider");
- return;
- }
- final NetworkOfferInfo existingOffer = findNetworkOfferInfoByCallback(newOffer.callback);
- if (null != existingOffer) {
- handleUnregisterNetworkOffer(existingOffer);
- newOffer.migrateFrom(existingOffer.offer);
- }
- final NetworkOfferInfo noi = new NetworkOfferInfo(newOffer);
- try {
- noi.offer.callback.asBinder().linkToDeath(noi, 0 /* flags */);
- } catch (RemoteException e) {
- noi.binderDied();
- return;
- }
- mNetworkOffers.add(noi);
- issueNetworkNeeds(noi);
- }
-
- private void handleUnregisterNetworkOffer(@NonNull final NetworkOfferInfo noi) {
- ensureRunningOnConnectivityServiceThread();
- mNetworkOffers.remove(noi);
- noi.offer.callback.asBinder().unlinkToDeath(noi, 0 /* flags */);
- }
-
- @Nullable private NetworkOfferInfo findNetworkOfferInfoByCallback(
- @NonNull final INetworkOfferCallback callback) {
- ensureRunningOnConnectivityServiceThread();
- for (final NetworkOfferInfo noi : mNetworkOffers) {
- if (noi.offer.callback.asBinder().equals(callback.asBinder())) return noi;
- }
- return null;
- }
-
- /**
- * Called when receiving LinkProperties directly from a NetworkAgent.
- * Stores into |nai| any data coming from the agent that might also be written to the network's
- * LinkProperties by ConnectivityService itself. This ensures that the data provided by the
- * agent is not lost when updateLinkProperties is called.
- * This method should never alter the agent's LinkProperties, only store data in |nai|.
- */
- private void processLinkPropertiesFromAgent(NetworkAgentInfo nai, LinkProperties lp) {
- lp.ensureDirectlyConnectedRoutes();
- nai.clatd.setNat64PrefixFromRa(lp.getNat64Prefix());
- nai.networkAgentPortalData = lp.getCaptivePortalData();
- }
-
- private void updateLinkProperties(NetworkAgentInfo networkAgent, @NonNull LinkProperties newLp,
- @NonNull LinkProperties oldLp) {
- int netId = networkAgent.network.getNetId();
-
- // The NetworkAgent does not know whether clatd is running on its network or not, or whether
- // a NAT64 prefix was discovered by the DNS resolver. Before we do anything else, make sure
- // the LinkProperties for the network are accurate.
- networkAgent.clatd.fixupLinkProperties(oldLp, newLp);
-
- updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities);
-
- // update filtering rules, need to happen after the interface update so netd knows about the
- // new interface (the interface name -> index map becomes initialized)
- updateVpnFiltering(newLp, oldLp, networkAgent);
-
- updateMtu(newLp, oldLp);
- // TODO - figure out what to do for clat
-// for (LinkProperties lp : newLp.getStackedLinks()) {
-// updateMtu(lp, null);
-// }
- if (isDefaultNetwork(networkAgent)) {
- updateTcpBufferSizes(newLp.getTcpBufferSizes());
- }
-
- updateRoutes(newLp, oldLp, netId);
- updateDnses(newLp, oldLp, netId);
- // Make sure LinkProperties represents the latest private DNS status.
- // This does not need to be done before updateDnses because the
- // LinkProperties are not the source of the private DNS configuration.
- // updateDnses will fetch the private DNS configuration from DnsManager.
- mDnsManager.updatePrivateDnsStatus(netId, newLp);
-
- if (isDefaultNetwork(networkAgent)) {
- handleApplyDefaultProxy(newLp.getHttpProxy());
- } else {
- updateProxy(newLp, oldLp);
- }
-
- updateWakeOnLan(newLp);
-
- // Captive portal data is obtained from NetworkMonitor and stored in NetworkAgentInfo.
- // It is not always contained in the LinkProperties sent from NetworkAgents, and if it
- // does, it needs to be merged here.
- newLp.setCaptivePortalData(mergeCaptivePortalData(networkAgent.networkAgentPortalData,
- networkAgent.capportApiData));
-
- // TODO - move this check to cover the whole function
- if (!Objects.equals(newLp, oldLp)) {
- synchronized (networkAgent) {
- networkAgent.linkProperties = newLp;
- }
- // Start or stop DNS64 detection and 464xlat according to network state.
- networkAgent.clatd.update();
- notifyIfacesChangedForNetworkStats();
- networkAgent.networkMonitor().notifyLinkPropertiesChanged(
- new LinkProperties(newLp, true /* parcelSensitiveFields */));
- if (networkAgent.everConnected) {
- notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
- }
- }
-
- mKeepaliveTracker.handleCheckKeepalivesStillValid(networkAgent);
- }
-
- /**
- * @param naData captive portal data from NetworkAgent
- * @param apiData captive portal data from capport API
- */
- @Nullable
- private CaptivePortalData mergeCaptivePortalData(CaptivePortalData naData,
- CaptivePortalData apiData) {
- if (naData == null || apiData == null) {
- return naData == null ? apiData : naData;
- }
- final CaptivePortalData.Builder captivePortalBuilder =
- new CaptivePortalData.Builder(naData);
-
- if (apiData.isCaptive()) {
- captivePortalBuilder.setCaptive(true);
- }
- if (apiData.isSessionExtendable()) {
- captivePortalBuilder.setSessionExtendable(true);
- }
- if (apiData.getExpiryTimeMillis() >= 0 || apiData.getByteLimit() >= 0) {
- // Expiry time, bytes remaining, refresh time all need to come from the same source,
- // otherwise data would be inconsistent. Prefer the capport API info if present,
- // as it can generally be refreshed more often.
- captivePortalBuilder.setExpiryTime(apiData.getExpiryTimeMillis());
- captivePortalBuilder.setBytesRemaining(apiData.getByteLimit());
- captivePortalBuilder.setRefreshTime(apiData.getRefreshTimeMillis());
- } else if (naData.getExpiryTimeMillis() < 0 && naData.getByteLimit() < 0) {
- // No source has time / bytes remaining information: surface the newest refresh time
- // for other fields
- captivePortalBuilder.setRefreshTime(
- Math.max(naData.getRefreshTimeMillis(), apiData.getRefreshTimeMillis()));
- }
-
- // Prioritize the user portal URL from the network agent if the source is authenticated.
- if (apiData.getUserPortalUrl() != null && naData.getUserPortalUrlSource()
- != CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) {
- captivePortalBuilder.setUserPortalUrl(apiData.getUserPortalUrl(),
- apiData.getUserPortalUrlSource());
- }
- // Prioritize the venue information URL from the network agent if the source is
- // authenticated.
- if (apiData.getVenueInfoUrl() != null && naData.getVenueInfoUrlSource()
- != CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) {
- captivePortalBuilder.setVenueInfoUrl(apiData.getVenueInfoUrl(),
- apiData.getVenueInfoUrlSource());
- }
- return captivePortalBuilder.build();
- }
-
- private void wakeupModifyInterface(String iface, NetworkCapabilities caps, boolean add) {
- // Marks are only available on WiFi interfaces. Checking for
- // marks on unsupported interfaces is harmless.
- if (!caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
- return;
- }
-
- int mark = mResources.get().getInteger(R.integer.config_networkWakeupPacketMark);
- int mask = mResources.get().getInteger(R.integer.config_networkWakeupPacketMask);
-
- // Mask/mark of zero will not detect anything interesting.
- // Don't install rules unless both values are nonzero.
- if (mark == 0 || mask == 0) {
- return;
- }
-
- final String prefix = "iface:" + iface;
- try {
- if (add) {
- mNetd.wakeupAddInterface(iface, prefix, mark, mask);
- } else {
- mNetd.wakeupDelInterface(iface, prefix, mark, mask);
- }
- } catch (Exception e) {
- loge("Exception modifying wakeup packet monitoring: " + e);
- }
-
- }
-
- private void updateInterfaces(final @Nullable LinkProperties newLp,
- final @Nullable LinkProperties oldLp, final int netId,
- final @NonNull NetworkCapabilities caps) {
- final CompareResult<String> interfaceDiff = new CompareResult<>(
- oldLp != null ? oldLp.getAllInterfaceNames() : null,
- newLp != null ? newLp.getAllInterfaceNames() : null);
- if (!interfaceDiff.added.isEmpty()) {
- for (final String iface : interfaceDiff.added) {
- try {
- if (DBG) log("Adding iface " + iface + " to network " + netId);
- mNetd.networkAddInterface(netId, iface);
- wakeupModifyInterface(iface, caps, true);
- mDeps.reportNetworkInterfaceForTransports(mContext, iface,
- caps.getTransportTypes());
- } catch (Exception e) {
- logw("Exception adding interface: " + e);
- }
- }
- }
- for (final String iface : interfaceDiff.removed) {
- try {
- if (DBG) log("Removing iface " + iface + " from network " + netId);
- wakeupModifyInterface(iface, caps, false);
- mNetd.networkRemoveInterface(netId, iface);
- } catch (Exception e) {
- loge("Exception removing interface: " + e);
- }
- }
- }
-
- // TODO: move to frameworks/libs/net.
- private RouteInfoParcel convertRouteInfo(RouteInfo route) {
- final String nextHop;
-
- switch (route.getType()) {
- case RouteInfo.RTN_UNICAST:
- if (route.hasGateway()) {
- nextHop = route.getGateway().getHostAddress();
- } else {
- nextHop = INetd.NEXTHOP_NONE;
- }
- break;
- case RouteInfo.RTN_UNREACHABLE:
- nextHop = INetd.NEXTHOP_UNREACHABLE;
- break;
- case RouteInfo.RTN_THROW:
- nextHop = INetd.NEXTHOP_THROW;
- break;
- default:
- nextHop = INetd.NEXTHOP_NONE;
- break;
- }
-
- final RouteInfoParcel rip = new RouteInfoParcel();
- rip.ifName = route.getInterface();
- rip.destination = route.getDestination().toString();
- rip.nextHop = nextHop;
- rip.mtu = route.getMtu();
-
- return rip;
- }
-
- /**
- * Have netd update routes from oldLp to newLp.
- * @return true if routes changed between oldLp and newLp
- */
- private boolean updateRoutes(LinkProperties newLp, LinkProperties oldLp, int netId) {
- // compare the route diff to determine which routes have been updated
- final CompareOrUpdateResult<RouteInfo.RouteKey, RouteInfo> routeDiff =
- new CompareOrUpdateResult<>(
- oldLp != null ? oldLp.getAllRoutes() : null,
- newLp != null ? newLp.getAllRoutes() : null,
- (r) -> r.getRouteKey());
-
- // add routes before removing old in case it helps with continuous connectivity
-
- // do this twice, adding non-next-hop routes first, then routes they are dependent on
- for (RouteInfo route : routeDiff.added) {
- if (route.hasGateway()) continue;
- if (VDBG || DDBG) log("Adding Route [" + route + "] to network " + netId);
- try {
- mNetd.networkAddRouteParcel(netId, convertRouteInfo(route));
- } catch (Exception e) {
- if ((route.getDestination().getAddress() instanceof Inet4Address) || VDBG) {
- loge("Exception in networkAddRouteParcel for non-gateway: " + e);
- }
- }
- }
- for (RouteInfo route : routeDiff.added) {
- if (!route.hasGateway()) continue;
- if (VDBG || DDBG) log("Adding Route [" + route + "] to network " + netId);
- try {
- mNetd.networkAddRouteParcel(netId, convertRouteInfo(route));
- } catch (Exception e) {
- if ((route.getGateway() instanceof Inet4Address) || VDBG) {
- loge("Exception in networkAddRouteParcel for gateway: " + e);
- }
- }
- }
-
- for (RouteInfo route : routeDiff.removed) {
- if (VDBG || DDBG) log("Removing Route [" + route + "] from network " + netId);
- try {
- mNetd.networkRemoveRouteParcel(netId, convertRouteInfo(route));
- } catch (Exception e) {
- loge("Exception in networkRemoveRouteParcel: " + e);
- }
- }
-
- for (RouteInfo route : routeDiff.updated) {
- if (VDBG || DDBG) log("Updating Route [" + route + "] from network " + netId);
- try {
- mNetd.networkUpdateRouteParcel(netId, convertRouteInfo(route));
- } catch (Exception e) {
- loge("Exception in networkUpdateRouteParcel: " + e);
- }
- }
- return !routeDiff.added.isEmpty() || !routeDiff.removed.isEmpty()
- || !routeDiff.updated.isEmpty();
- }
-
- private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId) {
- if (oldLp != null && newLp.isIdenticalDnses(oldLp)) {
- return; // no updating necessary
- }
-
- if (DBG) {
- final Collection<InetAddress> dnses = newLp.getDnsServers();
- log("Setting DNS servers for network " + netId + " to " + dnses);
- }
- try {
- mDnsManager.noteDnsServersForNetwork(netId, newLp);
- mDnsManager.flushVmDnsCache();
- } catch (Exception e) {
- loge("Exception in setDnsConfigurationForNetwork: " + e);
- }
- }
-
- private void updateVpnFiltering(LinkProperties newLp, LinkProperties oldLp,
- NetworkAgentInfo nai) {
- final String oldIface = oldLp != null ? oldLp.getInterfaceName() : null;
- final String newIface = newLp != null ? newLp.getInterfaceName() : null;
- final boolean wasFiltering = requiresVpnIsolation(nai, nai.networkCapabilities, oldLp);
- final boolean needsFiltering = requiresVpnIsolation(nai, nai.networkCapabilities, newLp);
-
- if (!wasFiltering && !needsFiltering) {
- // Nothing to do.
- return;
- }
-
- if (Objects.equals(oldIface, newIface) && (wasFiltering == needsFiltering)) {
- // Nothing changed.
- return;
- }
-
- final Set<UidRange> ranges = nai.networkCapabilities.getUidRanges();
- final int vpnAppUid = nai.networkCapabilities.getOwnerUid();
- // TODO: this create a window of opportunity for apps to receive traffic between the time
- // when the old rules are removed and the time when new rules are added. To fix this,
- // make eBPF support two allowlisted interfaces so here new rules can be added before the
- // old rules are being removed.
- if (wasFiltering) {
- mPermissionMonitor.onVpnUidRangesRemoved(oldIface, ranges, vpnAppUid);
- }
- if (needsFiltering) {
- mPermissionMonitor.onVpnUidRangesAdded(newIface, ranges, vpnAppUid);
- }
- }
-
- private void updateWakeOnLan(@NonNull LinkProperties lp) {
- if (mWolSupportedInterfaces == null) {
- mWolSupportedInterfaces = new ArraySet<>(mResources.get().getStringArray(
- R.array.config_wakeonlan_supported_interfaces));
- }
- lp.setWakeOnLanSupported(mWolSupportedInterfaces.contains(lp.getInterfaceName()));
- }
-
- private int getNetworkPermission(NetworkCapabilities nc) {
- if (!nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
- return INetd.PERMISSION_SYSTEM;
- }
- if (!nc.hasCapability(NET_CAPABILITY_FOREGROUND)) {
- return INetd.PERMISSION_NETWORK;
- }
- return INetd.PERMISSION_NONE;
- }
-
- private void updateNetworkPermissions(@NonNull final NetworkAgentInfo nai,
- @NonNull final NetworkCapabilities newNc) {
- final int oldPermission = getNetworkPermission(nai.networkCapabilities);
- final int newPermission = getNetworkPermission(newNc);
- if (oldPermission != newPermission && nai.created && !nai.isVPN()) {
- try {
- mNetd.networkSetPermissionForNetwork(nai.network.getNetId(), newPermission);
- } catch (RemoteException | ServiceSpecificException e) {
- loge("Exception in networkSetPermissionForNetwork: " + e);
- }
- }
- }
-
- /**
- * Called when receiving NetworkCapabilities directly from a NetworkAgent.
- * Stores into |nai| any data coming from the agent that might also be written to the network's
- * NetworkCapabilities by ConnectivityService itself. This ensures that the data provided by the
- * agent is not lost when updateCapabilities is called.
- * This method should never alter the agent's NetworkCapabilities, only store data in |nai|.
- */
- private void processCapabilitiesFromAgent(NetworkAgentInfo nai, NetworkCapabilities nc) {
- // Note: resetting the owner UID before storing the agent capabilities in NAI means that if
- // the agent attempts to change the owner UID, then nai.declaredCapabilities will not
- // actually be the same as the capabilities sent by the agent. Still, it is safer to reset
- // the owner UID here and behave as if the agent had never tried to change it.
- if (nai.networkCapabilities.getOwnerUid() != nc.getOwnerUid()) {
- Log.e(TAG, nai.toShortString() + ": ignoring attempt to change owner from "
- + nai.networkCapabilities.getOwnerUid() + " to " + nc.getOwnerUid());
- nc.setOwnerUid(nai.networkCapabilities.getOwnerUid());
- }
- nai.declaredCapabilities = new NetworkCapabilities(nc);
- }
-
- /** Modifies |newNc| based on the capabilities of |underlyingNetworks| and |agentCaps|. */
- @VisibleForTesting
- void applyUnderlyingCapabilities(@Nullable Network[] underlyingNetworks,
- @NonNull NetworkCapabilities agentCaps, @NonNull NetworkCapabilities newNc) {
- underlyingNetworks = underlyingNetworksOrDefault(
- agentCaps.getOwnerUid(), underlyingNetworks);
- long transportTypes = NetworkCapabilitiesUtils.packBits(agentCaps.getTransportTypes());
- int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
- int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
- // metered if any underlying is metered, or originally declared metered by the agent.
- boolean metered = !agentCaps.hasCapability(NET_CAPABILITY_NOT_METERED);
- boolean roaming = false; // roaming if any underlying is roaming
- boolean congested = false; // congested if any underlying is congested
- boolean suspended = true; // suspended if all underlying are suspended
-
- boolean hadUnderlyingNetworks = false;
- if (null != underlyingNetworks) {
- for (Network underlyingNetwork : underlyingNetworks) {
- final NetworkAgentInfo underlying =
- getNetworkAgentInfoForNetwork(underlyingNetwork);
- if (underlying == null) continue;
-
- final NetworkCapabilities underlyingCaps = underlying.networkCapabilities;
- hadUnderlyingNetworks = true;
- for (int underlyingType : underlyingCaps.getTransportTypes()) {
- transportTypes |= 1L << underlyingType;
- }
-
- // Merge capabilities of this underlying network. For bandwidth, assume the
- // worst case.
- downKbps = NetworkCapabilities.minBandwidth(downKbps,
- underlyingCaps.getLinkDownstreamBandwidthKbps());
- upKbps = NetworkCapabilities.minBandwidth(upKbps,
- underlyingCaps.getLinkUpstreamBandwidthKbps());
- // If this underlying network is metered, the VPN is metered (it may cost money
- // to send packets on this network).
- metered |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_METERED);
- // If this underlying network is roaming, the VPN is roaming (the billing structure
- // is different than the usual, local one).
- roaming |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING);
- // If this underlying network is congested, the VPN is congested (the current
- // condition of the network affects the performance of this network).
- congested |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_CONGESTED);
- // If this network is not suspended, the VPN is not suspended (the VPN
- // is able to transfer some data).
- suspended &= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
- }
- }
- if (!hadUnderlyingNetworks) {
- // No idea what the underlying networks are; assume reasonable defaults
- metered = true;
- roaming = false;
- congested = false;
- suspended = false;
- }
-
- newNc.setTransportTypes(NetworkCapabilitiesUtils.unpackBits(transportTypes));
- newNc.setLinkDownstreamBandwidthKbps(downKbps);
- newNc.setLinkUpstreamBandwidthKbps(upKbps);
- newNc.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
- newNc.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming);
- newNc.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested);
- newNc.setCapability(NET_CAPABILITY_NOT_SUSPENDED, !suspended);
- }
-
- /**
- * Augments the NetworkCapabilities passed in by a NetworkAgent with capabilities that are
- * maintained here that the NetworkAgent is not aware of (e.g., validated, captive portal,
- * and foreground status).
- */
- @NonNull
- private NetworkCapabilities mixInCapabilities(NetworkAgentInfo nai, NetworkCapabilities nc) {
- // Once a NetworkAgent is connected, complain if some immutable capabilities are removed.
- // Don't complain for VPNs since they're not driven by requests and there is no risk of
- // causing a connect/teardown loop.
- // TODO: remove this altogether and make it the responsibility of the NetworkProviders to
- // avoid connect/teardown loops.
- if (nai.everConnected &&
- !nai.isVPN() &&
- !nai.networkCapabilities.satisfiedByImmutableNetworkCapabilities(nc)) {
- // TODO: consider not complaining when a network agent degrades its capabilities if this
- // does not cause any request (that is not a listen) currently matching that agent to
- // stop being matched by the updated agent.
- String diff = nai.networkCapabilities.describeImmutableDifferences(nc);
- if (!TextUtils.isEmpty(diff)) {
- Log.wtf(TAG, "BUG: " + nai + " lost immutable capabilities:" + diff);
- }
- }
-
- // Don't modify caller's NetworkCapabilities.
- final NetworkCapabilities newNc = new NetworkCapabilities(nc);
- if (nai.lastValidated) {
- newNc.addCapability(NET_CAPABILITY_VALIDATED);
- } else {
- newNc.removeCapability(NET_CAPABILITY_VALIDATED);
- }
- if (nai.lastCaptivePortalDetected) {
- newNc.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
- } else {
- newNc.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
- }
- if (nai.isBackgroundNetwork()) {
- newNc.removeCapability(NET_CAPABILITY_FOREGROUND);
- } else {
- newNc.addCapability(NET_CAPABILITY_FOREGROUND);
- }
- if (nai.partialConnectivity) {
- newNc.addCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY);
- } else {
- newNc.removeCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY);
- }
- newNc.setPrivateDnsBroken(nai.networkCapabilities.isPrivateDnsBroken());
-
- // TODO : remove this once all factories are updated to send NOT_SUSPENDED and NOT_ROAMING
- if (!newNc.hasTransport(TRANSPORT_CELLULAR)) {
- newNc.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- newNc.addCapability(NET_CAPABILITY_NOT_ROAMING);
- }
-
- if (nai.supportsUnderlyingNetworks()) {
- applyUnderlyingCapabilities(nai.declaredUnderlyingNetworks, nai.declaredCapabilities,
- newNc);
- }
-
- return newNc;
- }
-
- private void updateNetworkInfoForRoamingAndSuspended(NetworkAgentInfo nai,
- NetworkCapabilities prevNc, NetworkCapabilities newNc) {
- final boolean prevSuspended = !prevNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
- final boolean suspended = !newNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
- final boolean prevRoaming = !prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
- final boolean roaming = !newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
- if (prevSuspended != suspended) {
- // TODO (b/73132094) : remove this call once the few users of onSuspended and
- // onResumed have been removed.
- notifyNetworkCallbacks(nai, suspended ? ConnectivityManager.CALLBACK_SUSPENDED
- : ConnectivityManager.CALLBACK_RESUMED);
- }
- if (prevSuspended != suspended || prevRoaming != roaming) {
- // updateNetworkInfo will mix in the suspended info from the capabilities and
- // take appropriate action for the network having possibly changed state.
- updateNetworkInfo(nai, nai.networkInfo);
- }
- }
-
- /**
- * Update the NetworkCapabilities for {@code nai} to {@code nc}. Specifically:
- *
- * 1. Calls mixInCapabilities to merge the passed-in NetworkCapabilities {@code nc} with the
- * capabilities we manage and store in {@code nai}, such as validated status and captive
- * portal status)
- * 2. Takes action on the result: changes network permissions, sends CAP_CHANGED callbacks, and
- * potentially triggers rematches.
- * 3. Directly informs other network stack components (NetworkStatsService, VPNs, etc. of the
- * change.)
- *
- * @param oldScore score of the network before any of the changes that prompted us
- * to call this function.
- * @param nai the network having its capabilities updated.
- * @param nc the new network capabilities.
- */
- private void updateCapabilities(final int oldScore, @NonNull final NetworkAgentInfo nai,
- @NonNull final NetworkCapabilities nc) {
- NetworkCapabilities newNc = mixInCapabilities(nai, nc);
- if (Objects.equals(nai.networkCapabilities, newNc)) return;
- updateNetworkPermissions(nai, newNc);
- final NetworkCapabilities prevNc = nai.getAndSetNetworkCapabilities(newNc);
-
- updateUids(nai, prevNc, newNc);
- nai.updateScoreForNetworkAgentUpdate();
-
- if (nai.getCurrentScore() == oldScore && newNc.equalRequestableCapabilities(prevNc)) {
- // If the requestable capabilities haven't changed, and the score hasn't changed, then
- // the change we're processing can't affect any requests, it can only affect the listens
- // on this network. We might have been called by rematchNetworkAndRequests when a
- // network changed foreground state.
- processListenRequests(nai);
- } else {
- // If the requestable capabilities have changed or the score changed, we can't have been
- // called by rematchNetworkAndRequests, so it's safe to start a rematch.
- rematchAllNetworksAndRequests();
- notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
- }
- updateNetworkInfoForRoamingAndSuspended(nai, prevNc, newNc);
-
- final boolean oldMetered = prevNc.isMetered();
- final boolean newMetered = newNc.isMetered();
- final boolean meteredChanged = oldMetered != newMetered;
-
- if (meteredChanged) {
- maybeNotifyNetworkBlocked(nai, oldMetered, newMetered,
- mVpnBlockedUidRanges, mVpnBlockedUidRanges);
- }
-
- final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING)
- != newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
-
- // Report changes that are interesting for network statistics tracking.
- if (meteredChanged || roamingChanged) {
- notifyIfacesChangedForNetworkStats();
- }
-
- // This network might have been underlying another network. Propagate its capabilities.
- propagateUnderlyingNetworkCapabilities(nai.network);
-
- if (!newNc.equalsTransportTypes(prevNc)) {
- mDnsManager.updateTransportsForNetwork(
- nai.network.getNetId(), newNc.getTransportTypes());
- }
- }
-
- /** Convenience method to update the capabilities for a given network. */
- private void updateCapabilitiesForNetwork(NetworkAgentInfo nai) {
- updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
- }
-
- /**
- * Returns whether VPN isolation (ingress interface filtering) should be applied on the given
- * network.
- *
- * Ingress interface filtering enforces that all apps under the given network can only receive
- * packets from the network's interface (and loopback). This is important for VPNs because
- * apps that cannot bypass a fully-routed VPN shouldn't be able to receive packets from any
- * non-VPN interfaces.
- *
- * As a result, this method should return true iff
- * 1. the network is an app VPN (not legacy VPN)
- * 2. the VPN does not allow bypass
- * 3. the VPN is fully-routed
- * 4. the VPN interface is non-null
- *
- * @see INetd#firewallAddUidInterfaceRules
- * @see INetd#firewallRemoveUidInterfaceRules
- */
- private boolean requiresVpnIsolation(@NonNull NetworkAgentInfo nai, NetworkCapabilities nc,
- LinkProperties lp) {
- if (nc == null || lp == null) return false;
- return nai.isVPN()
- && !nai.networkAgentConfig.allowBypass
- && nc.getOwnerUid() != Process.SYSTEM_UID
- && lp.getInterfaceName() != null
- && (lp.hasIpv4DefaultRoute() || lp.hasIpv4UnreachableDefaultRoute())
- && (lp.hasIpv6DefaultRoute() || lp.hasIpv6UnreachableDefaultRoute());
- }
-
- private static UidRangeParcel[] toUidRangeStableParcels(final @NonNull Set<UidRange> ranges) {
- final UidRangeParcel[] stableRanges = new UidRangeParcel[ranges.size()];
- int index = 0;
- for (UidRange range : ranges) {
- stableRanges[index] = new UidRangeParcel(range.start, range.stop);
- index++;
- }
- return stableRanges;
- }
-
- private static UidRangeParcel[] toUidRangeStableParcels(UidRange[] ranges) {
- final UidRangeParcel[] stableRanges = new UidRangeParcel[ranges.length];
- for (int i = 0; i < ranges.length; i++) {
- stableRanges[i] = new UidRangeParcel(ranges[i].start, ranges[i].stop);
- }
- return stableRanges;
- }
-
- private void maybeCloseSockets(NetworkAgentInfo nai, UidRangeParcel[] ranges,
- int[] exemptUids) {
- if (nai.isVPN() && !nai.networkAgentConfig.allowBypass) {
- try {
- mNetd.socketDestroy(ranges, exemptUids);
- } catch (Exception e) {
- loge("Exception in socket destroy: ", e);
- }
- }
- }
-
- private void updateUidRanges(boolean add, NetworkAgentInfo nai, Set<UidRange> uidRanges) {
- int[] exemptUids = new int[2];
- // TODO: Excluding VPN_UID is necessary in order to not to kill the TCP connection used
- // by PPTP. Fix this by making Vpn set the owner UID to VPN_UID instead of system when
- // starting a legacy VPN, and remove VPN_UID here. (b/176542831)
- exemptUids[0] = VPN_UID;
- exemptUids[1] = nai.networkCapabilities.getOwnerUid();
- UidRangeParcel[] ranges = toUidRangeStableParcels(uidRanges);
-
- maybeCloseSockets(nai, ranges, exemptUids);
- try {
- if (add) {
- mNetd.networkAddUidRanges(nai.network.netId, ranges);
- } else {
- mNetd.networkRemoveUidRanges(nai.network.netId, ranges);
- }
- } catch (Exception e) {
- loge("Exception while " + (add ? "adding" : "removing") + " uid ranges " + uidRanges +
- " on netId " + nai.network.netId + ". " + e);
- }
- maybeCloseSockets(nai, ranges, exemptUids);
- }
-
- private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
- NetworkCapabilities newNc) {
- Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUidRanges();
- Set<UidRange> newRanges = null == newNc ? null : newNc.getUidRanges();
- if (null == prevRanges) prevRanges = new ArraySet<>();
- if (null == newRanges) newRanges = new ArraySet<>();
- final Set<UidRange> prevRangesCopy = new ArraySet<>(prevRanges);
-
- prevRanges.removeAll(newRanges);
- newRanges.removeAll(prevRangesCopy);
-
- try {
- // When updating the VPN uid routing rules, add the new range first then remove the old
- // range. If old range were removed first, there would be a window between the old
- // range being removed and the new range being added, during which UIDs contained
- // in both ranges are not subject to any VPN routing rules. Adding new range before
- // removing old range works because, unlike the filtering rules below, it's possible to
- // add duplicate UID routing rules.
- // TODO: calculate the intersection of add & remove. Imagining that we are trying to
- // remove uid 3 from a set containing 1-5. Intersection of the prev and new sets is:
- // [1-5] & [1-2],[4-5] == [3]
- // Then we can do:
- // maybeCloseSockets([3])
- // mNetd.networkAddUidRanges([1-2],[4-5])
- // mNetd.networkRemoveUidRanges([1-5])
- // maybeCloseSockets([3])
- // This can prevent the sockets of uid 1-2, 4-5 from being closed. It also reduce the
- // number of binder calls from 6 to 4.
- if (!newRanges.isEmpty()) {
- updateUidRanges(true, nai, newRanges);
- }
- if (!prevRanges.isEmpty()) {
- updateUidRanges(false, nai, prevRanges);
- }
- final boolean wasFiltering = requiresVpnIsolation(nai, prevNc, nai.linkProperties);
- final boolean shouldFilter = requiresVpnIsolation(nai, newNc, nai.linkProperties);
- final String iface = nai.linkProperties.getInterfaceName();
- // For VPN uid interface filtering, old ranges need to be removed before new ranges can
- // be added, due to the range being expanded and stored as individual UIDs. For example
- // the UIDs might be updated from [0, 99999] to ([0, 10012], [10014, 99999]) which means
- // prevRanges = [0, 99999] while newRanges = [0, 10012], [10014, 99999]. If prevRanges
- // were added first and then newRanges got removed later, there would be only one uid
- // 10013 left. A consequence of removing old ranges before adding new ranges is that
- // there is now a window of opportunity when the UIDs are not subject to any filtering.
- // Note that this is in contrast with the (more robust) update of VPN routing rules
- // above, where the addition of new ranges happens before the removal of old ranges.
- // TODO Fix this window by computing an accurate diff on Set<UidRange>, so the old range
- // to be removed will never overlap with the new range to be added.
- if (wasFiltering && !prevRanges.isEmpty()) {
- mPermissionMonitor.onVpnUidRangesRemoved(iface, prevRanges, prevNc.getOwnerUid());
- }
- if (shouldFilter && !newRanges.isEmpty()) {
- mPermissionMonitor.onVpnUidRangesAdded(iface, newRanges, newNc.getOwnerUid());
- }
- } catch (Exception e) {
- // Never crash!
- loge("Exception in updateUids: ", e);
- }
- }
-
- public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
- ensureRunningOnConnectivityServiceThread();
-
- if (getNetworkAgentInfoForNetId(nai.network.getNetId()) != nai) {
- // Ignore updates for disconnected networks
- return;
- }
- if (VDBG || DDBG) {
- log("Update of LinkProperties for " + nai.toShortString()
- + "; created=" + nai.created
- + "; everConnected=" + nai.everConnected);
- }
- // TODO: eliminate this defensive copy after confirming that updateLinkProperties does not
- // modify its oldLp parameter.
- updateLinkProperties(nai, newLp, new LinkProperties(nai.linkProperties));
- }
-
- private void sendPendingIntentForRequest(NetworkRequestInfo nri, NetworkAgentInfo networkAgent,
- int notificationType) {
- if (notificationType == ConnectivityManager.CALLBACK_AVAILABLE && !nri.mPendingIntentSent) {
- Intent intent = new Intent();
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK, networkAgent.network);
- // If apps could file multi-layer requests with PendingIntents, they'd need to know
- // which of the layer is satisfied alongside with some ID for the request. Hence, if
- // such an API is ever implemented, there is no doubt the right request to send in
- // EXTRA_NETWORK_REQUEST is mActiveRequest, and whatever ID would be added would need to
- // be sent as a separate extra.
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK_REQUEST, nri.getActiveRequest());
- nri.mPendingIntentSent = true;
- sendIntent(nri.mPendingIntent, intent);
- }
- // else not handled
- }
-
- private void sendIntent(PendingIntent pendingIntent, Intent intent) {
- mPendingIntentWakeLock.acquire();
- try {
- if (DBG) log("Sending " + pendingIntent);
- pendingIntent.send(mContext, 0, intent, this /* onFinished */, null /* Handler */);
- } catch (PendingIntent.CanceledException e) {
- if (DBG) log(pendingIntent + " was not sent, it had been canceled.");
- mPendingIntentWakeLock.release();
- releasePendingNetworkRequest(pendingIntent);
- }
- // ...otherwise, mPendingIntentWakeLock.release() gets called by onSendFinished()
- }
-
- @Override
- public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
- String resultData, Bundle resultExtras) {
- if (DBG) log("Finished sending " + pendingIntent);
- mPendingIntentWakeLock.release();
- // Release with a delay so the receiving client has an opportunity to put in its
- // own request.
- releasePendingNetworkRequestWithDelay(pendingIntent);
- }
-
- private void callCallbackForRequest(@NonNull final NetworkRequestInfo nri,
- @NonNull final NetworkAgentInfo networkAgent, final int notificationType,
- final int arg1) {
- if (nri.mMessenger == null) {
- // Default request has no msgr. Also prevents callbacks from being invoked for
- // NetworkRequestInfos registered with ConnectivityDiagnostics requests. Those callbacks
- // are Type.LISTEN, but should not have NetworkCallbacks invoked.
- return;
- }
- Bundle bundle = new Bundle();
- // TODO b/177608132: make sure callbacks are indexed by NRIs and not NetworkRequest objects.
- // TODO: check if defensive copies of data is needed.
- final NetworkRequest nrForCallback = nri.getNetworkRequestForCallback();
- putParcelable(bundle, nrForCallback);
- Message msg = Message.obtain();
- if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL) {
- putParcelable(bundle, networkAgent.network);
- }
- final boolean includeLocationSensitiveInfo =
- (nri.mCallbackFlags & NetworkCallback.FLAG_INCLUDE_LOCATION_INFO) != 0;
- switch (notificationType) {
- case ConnectivityManager.CALLBACK_AVAILABLE: {
- final NetworkCapabilities nc =
- networkCapabilitiesRestrictedForCallerPermissions(
- networkAgent.networkCapabilities, nri.mPid, nri.mUid);
- putParcelable(
- bundle,
- createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- nc, includeLocationSensitiveInfo, nri.mPid, nri.mUid,
- nrForCallback.getRequestorPackageName(),
- nri.mCallingAttributionTag));
- putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
- networkAgent.linkProperties, nri.mPid, nri.mUid));
- // For this notification, arg1 contains the blocked status.
- msg.arg1 = arg1;
- break;
- }
- case ConnectivityManager.CALLBACK_LOSING: {
- msg.arg1 = arg1;
- break;
- }
- case ConnectivityManager.CALLBACK_CAP_CHANGED: {
- // networkAgent can't be null as it has been accessed a few lines above.
- final NetworkCapabilities netCap =
- networkCapabilitiesRestrictedForCallerPermissions(
- networkAgent.networkCapabilities, nri.mPid, nri.mUid);
- putParcelable(
- bundle,
- createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, includeLocationSensitiveInfo, nri.mPid, nri.mUid,
- nrForCallback.getRequestorPackageName(),
- nri.mCallingAttributionTag));
- break;
- }
- case ConnectivityManager.CALLBACK_IP_CHANGED: {
- putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
- networkAgent.linkProperties, nri.mPid, nri.mUid));
- break;
- }
- case ConnectivityManager.CALLBACK_BLK_CHANGED: {
- maybeLogBlockedStatusChanged(nri, networkAgent.network, arg1);
- msg.arg1 = arg1;
- break;
- }
- }
- msg.what = notificationType;
- msg.setData(bundle);
- try {
- if (VDBG) {
- String notification = ConnectivityManager.getCallbackName(notificationType);
- log("sending notification " + notification + " for " + nrForCallback);
- }
- nri.mMessenger.send(msg);
- } catch (RemoteException e) {
- // may occur naturally in the race of binder death.
- loge("RemoteException caught trying to send a callback msg for " + nrForCallback);
- }
- }
-
- private static <T extends Parcelable> void putParcelable(Bundle bundle, T t) {
- bundle.putParcelable(t.getClass().getSimpleName(), t);
- }
-
- private void teardownUnneededNetwork(NetworkAgentInfo nai) {
- if (nai.numRequestNetworkRequests() != 0) {
- for (int i = 0; i < nai.numNetworkRequests(); i++) {
- NetworkRequest nr = nai.requestAt(i);
- // Ignore listening and track default requests.
- if (!nr.isRequest()) continue;
- loge("Dead network still had at least " + nr);
- break;
- }
- }
- nai.disconnect();
- }
-
- private void handleLingerComplete(NetworkAgentInfo oldNetwork) {
- if (oldNetwork == null) {
- loge("Unknown NetworkAgentInfo in handleLingerComplete");
- return;
- }
- if (DBG) log("handleLingerComplete for " + oldNetwork.toShortString());
-
- // If we get here it means that the last linger timeout for this network expired. So there
- // must be no other active linger timers, and we must stop lingering.
- oldNetwork.clearInactivityState();
-
- if (unneeded(oldNetwork, UnneededFor.TEARDOWN)) {
- // Tear the network down.
- teardownUnneededNetwork(oldNetwork);
- } else {
- // Put the network in the background if it doesn't satisfy any foreground request.
- updateCapabilitiesForNetwork(oldNetwork);
- }
- }
-
- private void processDefaultNetworkChanges(@NonNull final NetworkReassignment changes) {
- boolean isDefaultChanged = false;
- for (final NetworkRequestInfo defaultRequestInfo : mDefaultNetworkRequests) {
- final NetworkReassignment.RequestReassignment reassignment =
- changes.getReassignment(defaultRequestInfo);
- if (null == reassignment) {
- continue;
- }
- // reassignment only contains those instances where the satisfying network changed.
- isDefaultChanged = true;
- // Notify system services of the new default.
- makeDefault(defaultRequestInfo, reassignment.mOldNetwork, reassignment.mNewNetwork);
- }
-
- if (isDefaultChanged) {
- // Hold a wakelock for a short time to help apps in migrating to a new default.
- scheduleReleaseNetworkTransitionWakelock();
- }
- }
-
- private void makeDefault(@NonNull final NetworkRequestInfo nri,
- @Nullable final NetworkAgentInfo oldDefaultNetwork,
- @Nullable final NetworkAgentInfo newDefaultNetwork) {
- if (DBG) {
- log("Switching to new default network for: " + nri + " using " + newDefaultNetwork);
- }
-
- // Fix up the NetworkCapabilities of any networks that have this network as underlying.
- if (newDefaultNetwork != null) {
- propagateUnderlyingNetworkCapabilities(newDefaultNetwork.network);
- }
-
- // Set an app level managed default and return since further processing only applies to the
- // default network.
- if (mDefaultRequest != nri) {
- makeDefaultForApps(nri, oldDefaultNetwork, newDefaultNetwork);
- return;
- }
-
- makeDefaultNetwork(newDefaultNetwork);
-
- if (oldDefaultNetwork != null) {
- mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
- }
- mNetworkActivityTracker.updateDataActivityTracking(newDefaultNetwork, oldDefaultNetwork);
- handleApplyDefaultProxy(null != newDefaultNetwork
- ? newDefaultNetwork.linkProperties.getHttpProxy() : null);
- updateTcpBufferSizes(null != newDefaultNetwork
- ? newDefaultNetwork.linkProperties.getTcpBufferSizes() : null);
- notifyIfacesChangedForNetworkStats();
- }
-
- private void makeDefaultForApps(@NonNull final NetworkRequestInfo nri,
- @Nullable final NetworkAgentInfo oldDefaultNetwork,
- @Nullable final NetworkAgentInfo newDefaultNetwork) {
- try {
- if (VDBG) {
- log("Setting default network for " + nri
- + " using UIDs " + nri.getUids()
- + " with old network " + (oldDefaultNetwork != null
- ? oldDefaultNetwork.network().getNetId() : "null")
- + " and new network " + (newDefaultNetwork != null
- ? newDefaultNetwork.network().getNetId() : "null"));
- }
- if (nri.getUids().isEmpty()) {
- throw new IllegalStateException("makeDefaultForApps called without specifying"
- + " any applications to set as the default." + nri);
- }
- if (null != newDefaultNetwork) {
- mNetd.networkAddUidRanges(
- newDefaultNetwork.network.getNetId(),
- toUidRangeStableParcels(nri.getUids()));
- }
- if (null != oldDefaultNetwork) {
- mNetd.networkRemoveUidRanges(
- oldDefaultNetwork.network.getNetId(),
- toUidRangeStableParcels(nri.getUids()));
- }
- } catch (RemoteException | ServiceSpecificException e) {
- loge("Exception setting app default network", e);
- }
- }
-
- private void makeDefaultNetwork(@Nullable final NetworkAgentInfo newDefaultNetwork) {
- try {
- if (null != newDefaultNetwork) {
- mNetd.networkSetDefault(newDefaultNetwork.network.getNetId());
- } else {
- mNetd.networkClearDefault();
- }
- } catch (RemoteException | ServiceSpecificException e) {
- loge("Exception setting default network :" + e);
- }
- }
-
- private void processListenRequests(@NonNull final NetworkAgentInfo nai) {
- // For consistency with previous behaviour, send onLost callbacks before onAvailable.
- processNewlyLostListenRequests(nai);
- notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
- processNewlySatisfiedListenRequests(nai);
- }
-
- private void processNewlyLostListenRequests(@NonNull final NetworkAgentInfo nai) {
- for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (nri.isMultilayerRequest()) {
- continue;
- }
- final NetworkRequest nr = nri.mRequests.get(0);
- if (!nr.isListen()) continue;
- if (nai.isSatisfyingRequest(nr.requestId) && !nai.satisfies(nr)) {
- nai.removeRequest(nr.requestId);
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_LOST, 0);
- }
- }
- }
-
- private void processNewlySatisfiedListenRequests(@NonNull final NetworkAgentInfo nai) {
- for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (nri.isMultilayerRequest()) {
- continue;
- }
- final NetworkRequest nr = nri.mRequests.get(0);
- if (!nr.isListen()) continue;
- if (nai.satisfies(nr) && !nai.isSatisfyingRequest(nr.requestId)) {
- nai.addRequest(nr);
- notifyNetworkAvailable(nai, nri);
- }
- }
- }
-
- // An accumulator class to gather the list of changes that result from a rematch.
- private static class NetworkReassignment {
- static class RequestReassignment {
- @NonNull public final NetworkRequestInfo mNetworkRequestInfo;
- @Nullable public final NetworkRequest mOldNetworkRequest;
- @Nullable public final NetworkRequest mNewNetworkRequest;
- @Nullable public final NetworkAgentInfo mOldNetwork;
- @Nullable public final NetworkAgentInfo mNewNetwork;
- RequestReassignment(@NonNull final NetworkRequestInfo networkRequestInfo,
- @Nullable final NetworkRequest oldNetworkRequest,
- @Nullable final NetworkRequest newNetworkRequest,
- @Nullable final NetworkAgentInfo oldNetwork,
- @Nullable final NetworkAgentInfo newNetwork) {
- mNetworkRequestInfo = networkRequestInfo;
- mOldNetworkRequest = oldNetworkRequest;
- mNewNetworkRequest = newNetworkRequest;
- mOldNetwork = oldNetwork;
- mNewNetwork = newNetwork;
- }
-
- public String toString() {
- final NetworkRequest requestToShow = null != mNewNetworkRequest
- ? mNewNetworkRequest : mNetworkRequestInfo.mRequests.get(0);
- return requestToShow.requestId + " : "
- + (null != mOldNetwork ? mOldNetwork.network.getNetId() : "null")
- + " → " + (null != mNewNetwork ? mNewNetwork.network.getNetId() : "null");
- }
- }
-
- @NonNull private final ArrayList<RequestReassignment> mReassignments = new ArrayList<>();
-
- @NonNull Iterable<RequestReassignment> getRequestReassignments() {
- return mReassignments;
- }
-
- void addRequestReassignment(@NonNull final RequestReassignment reassignment) {
- if (Build.isDebuggable()) {
- // The code is never supposed to add two reassignments of the same request. Make
- // sure this stays true, but without imposing this expensive check on all
- // reassignments on all user devices.
- for (final RequestReassignment existing : mReassignments) {
- if (existing.mNetworkRequestInfo.equals(reassignment.mNetworkRequestInfo)) {
- throw new IllegalStateException("Trying to reassign ["
- + reassignment + "] but already have ["
- + existing + "]");
- }
- }
- }
- mReassignments.add(reassignment);
- }
-
- // Will return null if this reassignment does not change the network assigned to
- // the passed request.
- @Nullable
- private RequestReassignment getReassignment(@NonNull final NetworkRequestInfo nri) {
- for (final RequestReassignment event : getRequestReassignments()) {
- if (nri == event.mNetworkRequestInfo) return event;
- }
- return null;
- }
-
- public String toString() {
- final StringJoiner sj = new StringJoiner(", " /* delimiter */,
- "NetReassign [" /* prefix */, "]" /* suffix */);
- if (mReassignments.isEmpty()) return sj.add("no changes").toString();
- for (final RequestReassignment rr : getRequestReassignments()) {
- sj.add(rr.toString());
- }
- return sj.toString();
- }
-
- public String debugString() {
- final StringBuilder sb = new StringBuilder();
- sb.append("NetworkReassignment :");
- if (mReassignments.isEmpty()) return sb.append(" no changes").toString();
- for (final RequestReassignment rr : getRequestReassignments()) {
- sb.append("\n ").append(rr);
- }
- return sb.append("\n").toString();
- }
- }
-
- private void updateSatisfiersForRematchRequest(@NonNull final NetworkRequestInfo nri,
- @Nullable final NetworkRequest previousRequest,
- @Nullable final NetworkRequest newRequest,
- @Nullable final NetworkAgentInfo previousSatisfier,
- @Nullable final NetworkAgentInfo newSatisfier,
- final long now) {
- if (null != newSatisfier && mNoServiceNetwork != newSatisfier) {
- if (VDBG) log("rematch for " + newSatisfier.toShortString());
- if (null != previousRequest && null != previousSatisfier) {
- if (VDBG || DDBG) {
- log(" accepting network in place of " + previousSatisfier.toShortString());
- }
- previousSatisfier.removeRequest(previousRequest.requestId);
- previousSatisfier.lingerRequest(previousRequest.requestId, now);
- } else {
- if (VDBG || DDBG) log(" accepting network in place of null");
- }
-
- // To prevent constantly CPU wake up for nascent timer, if a network comes up
- // and immediately satisfies a request then remove the timer. This will happen for
- // all networks except in the case of an underlying network for a VCN.
- if (newSatisfier.isNascent()) {
- newSatisfier.unlingerRequest(NetworkRequest.REQUEST_ID_NONE);
- newSatisfier.unsetInactive();
- }
-
- // if newSatisfier is not null, then newRequest may not be null.
- newSatisfier.unlingerRequest(newRequest.requestId);
- if (!newSatisfier.addRequest(newRequest)) {
- Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has "
- + newRequest);
- }
- } else if (null != previousRequest && null != previousSatisfier) {
- if (DBG) {
- log("Network " + previousSatisfier.toShortString() + " stopped satisfying"
- + " request " + previousRequest.requestId);
- }
- previousSatisfier.removeRequest(previousRequest.requestId);
- }
- nri.setSatisfier(newSatisfier, newRequest);
- }
-
- /**
- * This function is triggered when something can affect what network should satisfy what
- * request, and it computes the network reassignment from the passed collection of requests to
- * network match to the one that the system should now have. That data is encoded in an
- * object that is a list of changes, each of them having an NRI, and old satisfier, and a new
- * satisfier.
- *
- * After the reassignment is computed, it is applied to the state objects.
- *
- * @param networkRequests the nri objects to evaluate for possible network reassignment
- * @return NetworkReassignment listing of proposed network assignment changes
- */
- @NonNull
- private NetworkReassignment computeNetworkReassignment(
- @NonNull final Collection<NetworkRequestInfo> networkRequests) {
- final NetworkReassignment changes = new NetworkReassignment();
-
- // Gather the list of all relevant agents.
- final ArrayList<NetworkAgentInfo> nais = new ArrayList<>();
- for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
- if (!nai.everConnected) {
- continue;
- }
- nais.add(nai);
- }
-
- for (final NetworkRequestInfo nri : networkRequests) {
- // Non-multilayer listen requests can be ignored.
- if (!nri.isMultilayerRequest() && nri.mRequests.get(0).isListen()) {
- continue;
- }
- NetworkAgentInfo bestNetwork = null;
- NetworkRequest bestRequest = null;
- for (final NetworkRequest req : nri.mRequests) {
- bestNetwork = mNetworkRanker.getBestNetwork(req, nais, nri.getSatisfier());
- // Stop evaluating as the highest possible priority request is satisfied.
- if (null != bestNetwork) {
- bestRequest = req;
- break;
- }
- }
- if (null == bestNetwork && isDefaultBlocked(nri)) {
- // Remove default networking if disallowed for managed default requests.
- bestNetwork = mNoServiceNetwork;
- }
- if (nri.getSatisfier() != bestNetwork) {
- // bestNetwork may be null if no network can satisfy this request.
- changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
- nri, nri.mActiveRequest, bestRequest, nri.getSatisfier(), bestNetwork));
- }
- }
- return changes;
- }
-
- private Set<NetworkRequestInfo> getNrisFromGlobalRequests() {
- return new HashSet<>(mNetworkRequests.values());
- }
-
- /**
- * Attempt to rematch all Networks with all NetworkRequests. This may result in Networks
- * being disconnected.
- */
- private void rematchAllNetworksAndRequests() {
- rematchNetworksAndRequests(getNrisFromGlobalRequests());
- }
-
- /**
- * Attempt to rematch all Networks with given NetworkRequests. This may result in Networks
- * being disconnected.
- */
- private void rematchNetworksAndRequests(
- @NonNull final Set<NetworkRequestInfo> networkRequests) {
- ensureRunningOnConnectivityServiceThread();
- // TODO: This may be slow, and should be optimized.
- final long now = SystemClock.elapsedRealtime();
- final NetworkReassignment changes = computeNetworkReassignment(networkRequests);
- if (VDBG || DDBG) {
- log(changes.debugString());
- } else if (DBG) {
- log(changes.toString()); // Shorter form, only one line of log
- }
- applyNetworkReassignment(changes, now);
- issueNetworkNeeds();
- }
-
- private void applyNetworkReassignment(@NonNull final NetworkReassignment changes,
- final long now) {
- final Collection<NetworkAgentInfo> nais = mNetworkAgentInfos;
-
- // Since most of the time there are only 0 or 1 background networks, it would probably
- // be more efficient to just use an ArrayList here. TODO : measure performance
- final ArraySet<NetworkAgentInfo> oldBgNetworks = new ArraySet<>();
- for (final NetworkAgentInfo nai : nais) {
- if (nai.isBackgroundNetwork()) oldBgNetworks.add(nai);
- }
-
- // First, update the lists of satisfied requests in the network agents. This is necessary
- // because some code later depends on this state to be correct, most prominently computing
- // the linger status.
- for (final NetworkReassignment.RequestReassignment event :
- changes.getRequestReassignments()) {
- updateSatisfiersForRematchRequest(event.mNetworkRequestInfo,
- event.mOldNetworkRequest, event.mNewNetworkRequest,
- event.mOldNetwork, event.mNewNetwork,
- now);
- }
-
- // Process default network changes if applicable.
- processDefaultNetworkChanges(changes);
-
- // Notify requested networks are available after the default net is switched, but
- // before LegacyTypeTracker sends legacy broadcasts
- for (final NetworkReassignment.RequestReassignment event :
- changes.getRequestReassignments()) {
- if (null != event.mNewNetwork) {
- notifyNetworkAvailable(event.mNewNetwork, event.mNetworkRequestInfo);
- } else {
- callCallbackForRequest(event.mNetworkRequestInfo, event.mOldNetwork,
- ConnectivityManager.CALLBACK_LOST, 0);
- }
- }
-
- // Update the inactivity state before processing listen callbacks, because the background
- // computation depends on whether the network is inactive. Don't send the LOSING callbacks
- // just yet though, because they have to be sent after the listens are processed to keep
- // backward compatibility.
- final ArrayList<NetworkAgentInfo> inactiveNetworks = new ArrayList<>();
- for (final NetworkAgentInfo nai : nais) {
- // Rematching may have altered the inactivity state of some networks, so update all
- // inactivity timers. updateInactivityState reads the state from the network agent
- // and does nothing if the state has not changed : the source of truth is controlled
- // with NetworkAgentInfo#lingerRequest and NetworkAgentInfo#unlingerRequest, which
- // have been called while rematching the individual networks above.
- if (updateInactivityState(nai, now)) {
- inactiveNetworks.add(nai);
- }
- }
-
- for (final NetworkAgentInfo nai : nais) {
- if (!nai.everConnected) continue;
- final boolean oldBackground = oldBgNetworks.contains(nai);
- // Process listen requests and update capabilities if the background state has
- // changed for this network. For consistency with previous behavior, send onLost
- // callbacks before onAvailable.
- processNewlyLostListenRequests(nai);
- if (oldBackground != nai.isBackgroundNetwork()) {
- applyBackgroundChangeForRematch(nai);
- }
- processNewlySatisfiedListenRequests(nai);
- }
-
- for (final NetworkAgentInfo nai : inactiveNetworks) {
- // For nascent networks, if connecting with no foreground request, skip broadcasting
- // LOSING for backward compatibility. This is typical when mobile data connected while
- // wifi connected with mobile data always-on enabled.
- if (nai.isNascent()) continue;
- notifyNetworkLosing(nai, now);
- }
-
- updateLegacyTypeTrackerAndVpnLockdownForRematch(changes, nais);
-
- // Tear down all unneeded networks.
- for (NetworkAgentInfo nai : mNetworkAgentInfos) {
- if (unneeded(nai, UnneededFor.TEARDOWN)) {
- if (nai.getInactivityExpiry() > 0) {
- // This network has active linger timers and no requests, but is not
- // lingering. Linger it.
- //
- // One way (the only way?) this can happen if this network is unvalidated
- // and became unneeded due to another network improving its score to the
- // point where this network will no longer be able to satisfy any requests
- // even if it validates.
- if (updateInactivityState(nai, now)) {
- notifyNetworkLosing(nai, now);
- }
- } else {
- if (DBG) log("Reaping " + nai.toShortString());
- teardownUnneededNetwork(nai);
- }
- }
- }
- }
-
- /**
- * Apply a change in background state resulting from rematching networks with requests.
- *
- * During rematch, a network may change background states by starting to satisfy or stopping
- * to satisfy a foreground request. Listens don't count for this. When a network changes
- * background states, its capabilities need to be updated and callbacks fired for the
- * capability change.
- *
- * @param nai The network that changed background states
- */
- private void applyBackgroundChangeForRematch(@NonNull final NetworkAgentInfo nai) {
- final NetworkCapabilities newNc = mixInCapabilities(nai, nai.networkCapabilities);
- if (Objects.equals(nai.networkCapabilities, newNc)) return;
- updateNetworkPermissions(nai, newNc);
- nai.getAndSetNetworkCapabilities(newNc);
- notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
- }
-
- private void updateLegacyTypeTrackerAndVpnLockdownForRematch(
- @NonNull final NetworkReassignment changes,
- @NonNull final Collection<NetworkAgentInfo> nais) {
- final NetworkReassignment.RequestReassignment reassignmentOfDefault =
- changes.getReassignment(mDefaultRequest);
- final NetworkAgentInfo oldDefaultNetwork =
- null != reassignmentOfDefault ? reassignmentOfDefault.mOldNetwork : null;
- final NetworkAgentInfo newDefaultNetwork =
- null != reassignmentOfDefault ? reassignmentOfDefault.mNewNetwork : null;
-
- if (oldDefaultNetwork != newDefaultNetwork) {
- // Maintain the illusion : since the legacy API only understands one network at a time,
- // if the default network changed, apps should see a disconnected broadcast for the
- // old default network before they see a connected broadcast for the new one.
- if (oldDefaultNetwork != null) {
- mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
- oldDefaultNetwork, true);
- }
- if (newDefaultNetwork != null) {
- // The new default network can be newly null if and only if the old default
- // network doesn't satisfy the default request any more because it lost a
- // capability.
- mDefaultInetConditionPublished = newDefaultNetwork.lastValidated ? 100 : 0;
- mLegacyTypeTracker.add(
- newDefaultNetwork.networkInfo.getType(), newDefaultNetwork);
- }
- }
-
- // Now that all the callbacks have been sent, send the legacy network broadcasts
- // as needed. This is necessary so that legacy requests correctly bind dns
- // requests to this network. The legacy users are listening for this broadcast
- // and will generally do a dns request so they can ensureRouteToHost and if
- // they do that before the callbacks happen they'll use the default network.
- //
- // TODO: Is there still a race here? The legacy broadcast will be sent after sending
- // callbacks, but if apps can receive the broadcast before the callback, they still might
- // have an inconsistent view of networking.
- //
- // This *does* introduce a race where if the user uses the new api
- // (notification callbacks) and then uses the old api (getNetworkInfo(type))
- // they may get old info. Reverse this after the old startUsing api is removed.
- // This is on top of the multiple intent sequencing referenced in the todo above.
- for (NetworkAgentInfo nai : nais) {
- if (nai.everConnected) {
- addNetworkToLegacyTypeTracker(nai);
- }
- }
- }
-
- private void issueNetworkNeeds() {
- ensureRunningOnConnectivityServiceThread();
- for (final NetworkOfferInfo noi : mNetworkOffers) {
- issueNetworkNeeds(noi);
- }
- }
-
- private void issueNetworkNeeds(@NonNull final NetworkOfferInfo noi) {
- ensureRunningOnConnectivityServiceThread();
- for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
- informOffer(nri, noi.offer, mNetworkRanker);
- }
- }
-
- /**
- * Inform a NetworkOffer about any new situation of a request.
- *
- * This function handles updates to offers. A number of events may happen that require
- * updating the registrant for this offer about the situation :
- * • The offer itself was updated. This may lead the offer to no longer being able
- * to satisfy a request or beat a satisfier (and therefore be no longer needed),
- * or conversely being strengthened enough to beat the satisfier (and therefore
- * start being needed)
- * • The network satisfying a request changed (including cases where the request
- * starts or stops being satisfied). The new network may be a stronger or weaker
- * match than the old one, possibly affecting whether the offer is needed.
- * • The network satisfying a request updated their score. This may lead the offer
- * to no longer be able to beat it if the current satisfier got better, or
- * conversely start being a good choice if the current satisfier got weaker.
- *
- * @param nri The request
- * @param offer The offer. This may be an updated offer.
- */
- private static void informOffer(@NonNull NetworkRequestInfo nri,
- @NonNull final NetworkOffer offer, @NonNull final NetworkRanker networkRanker) {
- final NetworkRequest activeRequest = nri.isBeingSatisfied() ? nri.getActiveRequest() : null;
- final NetworkAgentInfo satisfier = null != activeRequest ? nri.getSatisfier() : null;
-
- // Multi-layer requests have a currently active request, the one being satisfied.
- // Since the system will try to bring up a better network than is currently satisfying
- // the request, NetworkProviders need to be told the offers matching the requests *above*
- // the currently satisfied one are needed, that the ones *below* the satisfied one are
- // not needed, and the offer is needed for the active request iff the offer can beat
- // the satisfier.
- // For non-multilayer requests, the logic above gracefully degenerates to only the
- // last case.
- // To achieve this, the loop below will proceed in three steps. In a first phase, inform
- // providers that the offer is needed for this request, until the active request is found.
- // In a second phase, deal with the currently active request. In a third phase, inform
- // the providers that offer is unneeded for the remaining requests.
-
- // First phase : inform providers of all requests above the active request.
- int i;
- for (i = 0; nri.mRequests.size() > i; ++i) {
- final NetworkRequest request = nri.mRequests.get(i);
- if (activeRequest == request) break; // Found the active request : go to phase 2
- if (!request.isRequest()) continue; // Listens/track defaults are never sent to offers
- // Since this request is higher-priority than the one currently satisfied, if the
- // offer can satisfy it, the provider should try and bring up the network for sure ;
- // no need to even ask the ranker – an offer that can satisfy is always better than
- // no network. Hence tell the provider so unless it already knew.
- if (request.canBeSatisfiedBy(offer.caps) && !offer.neededFor(request)) {
- offer.onNetworkNeeded(request);
- }
- }
-
- // Second phase : deal with the active request (if any)
- if (null != activeRequest && activeRequest.isRequest()) {
- final boolean oldNeeded = offer.neededFor(activeRequest);
- // An offer is needed if it is currently served by this provider or if this offer
- // can beat the current satisfier.
- final boolean currentlyServing = satisfier != null
- && satisfier.factorySerialNumber == offer.providerId;
- final boolean newNeeded = (currentlyServing
- || (activeRequest.canBeSatisfiedBy(offer.caps)
- && networkRanker.mightBeat(activeRequest, satisfier, offer)));
- if (newNeeded != oldNeeded) {
- if (newNeeded) {
- offer.onNetworkNeeded(activeRequest);
- } else {
- // The offer used to be able to beat the satisfier. Now it can't.
- offer.onNetworkUnneeded(activeRequest);
- }
- }
- }
-
- // Third phase : inform the providers that the offer isn't needed for any request
- // below the active one.
- for (++i /* skip the active request */; nri.mRequests.size() > i; ++i) {
- final NetworkRequest request = nri.mRequests.get(i);
- if (!request.isRequest()) continue; // Listens/track defaults are never sent to offers
- // Since this request is lower-priority than the one currently satisfied, if the
- // offer can satisfy it, the provider should not try and bring up the network.
- // Hence tell the provider so unless it already knew.
- if (offer.neededFor(request)) {
- offer.onNetworkUnneeded(request);
- }
- }
- }
-
- private void addNetworkToLegacyTypeTracker(@NonNull final NetworkAgentInfo nai) {
- for (int i = 0; i < nai.numNetworkRequests(); i++) {
- NetworkRequest nr = nai.requestAt(i);
- if (nr.legacyType != TYPE_NONE && nr.isRequest()) {
- // legacy type tracker filters out repeat adds
- mLegacyTypeTracker.add(nr.legacyType, nai);
- }
- }
-
- // A VPN generally won't get added to the legacy tracker in the "for (nri)" loop above,
- // because usually there are no NetworkRequests it satisfies (e.g., mDefaultRequest
- // wants the NOT_VPN capability, so it will never be satisfied by a VPN). So, add the
- // newNetwork to the tracker explicitly (it's a no-op if it has already been added).
- if (nai.isVPN()) {
- mLegacyTypeTracker.add(TYPE_VPN, nai);
- }
- }
-
- private void updateInetCondition(NetworkAgentInfo nai) {
- // Don't bother updating until we've graduated to validated at least once.
- if (!nai.everValidated) return;
- // For now only update icons for the default connection.
- // TODO: Update WiFi and cellular icons separately. b/17237507
- if (!isDefaultNetwork(nai)) return;
-
- int newInetCondition = nai.lastValidated ? 100 : 0;
- // Don't repeat publish.
- if (newInetCondition == mDefaultInetConditionPublished) return;
-
- mDefaultInetConditionPublished = newInetCondition;
- sendInetConditionBroadcast(nai.networkInfo);
- }
-
- @NonNull
- private NetworkInfo mixInInfo(@NonNull final NetworkAgentInfo nai, @NonNull NetworkInfo info) {
- final NetworkInfo newInfo = new NetworkInfo(info);
- // The suspended and roaming bits are managed in NetworkCapabilities.
- final boolean suspended =
- !nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
- if (suspended && info.getDetailedState() == NetworkInfo.DetailedState.CONNECTED) {
- // Only override the state with SUSPENDED if the network is currently in CONNECTED
- // state. This is because the network could have been suspended before connecting,
- // or it could be disconnecting while being suspended, and in both these cases
- // the state should not be overridden. Note that the only detailed state that
- // maps to State.CONNECTED is DetailedState.CONNECTED, so there is also no need to
- // worry about multiple different substates of CONNECTED.
- newInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, info.getReason(),
- info.getExtraInfo());
- } else if (!suspended && info.getDetailedState() == NetworkInfo.DetailedState.SUSPENDED) {
- // SUSPENDED state is currently only overridden from CONNECTED state. In the case the
- // network agent is created, then goes to suspended, then goes out of suspended without
- // ever setting connected. Check if network agent is ever connected to update the state.
- newInfo.setDetailedState(nai.everConnected
- ? NetworkInfo.DetailedState.CONNECTED
- : NetworkInfo.DetailedState.CONNECTING,
- info.getReason(),
- info.getExtraInfo());
- }
- newInfo.setRoaming(!nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- return newInfo;
- }
-
- private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo info) {
- final NetworkInfo newInfo = mixInInfo(networkAgent, info);
-
- final NetworkInfo.State state = newInfo.getState();
- NetworkInfo oldInfo = null;
- synchronized (networkAgent) {
- oldInfo = networkAgent.networkInfo;
- networkAgent.networkInfo = newInfo;
- }
-
- if (DBG) {
- log(networkAgent.toShortString() + " EVENT_NETWORK_INFO_CHANGED, going from "
- + oldInfo.getState() + " to " + state);
- }
-
- if (!networkAgent.created
- && (state == NetworkInfo.State.CONNECTED
- || (state == NetworkInfo.State.CONNECTING && networkAgent.isVPN()))) {
-
- // A network that has just connected has zero requests and is thus a foreground network.
- networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
-
- if (!createNativeNetwork(networkAgent)) return;
- if (networkAgent.supportsUnderlyingNetworks()) {
- // Initialize the network's capabilities to their starting values according to the
- // underlying networks. This ensures that the capabilities are correct before
- // anything happens to the network.
- updateCapabilitiesForNetwork(networkAgent);
- }
- networkAgent.created = true;
- networkAgent.onNetworkCreated();
- }
-
- if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) {
- networkAgent.everConnected = true;
-
- // NetworkCapabilities need to be set before sending the private DNS config to
- // NetworkMonitor, otherwise NetworkMonitor cannot determine if validation is required.
- networkAgent.getAndSetNetworkCapabilities(networkAgent.networkCapabilities);
-
- handlePerNetworkPrivateDnsConfig(networkAgent, mDnsManager.getPrivateDnsConfig());
- updateLinkProperties(networkAgent, new LinkProperties(networkAgent.linkProperties),
- null);
-
- // Until parceled LinkProperties are sent directly to NetworkMonitor, the connect
- // command must be sent after updating LinkProperties to maximize chances of
- // NetworkMonitor seeing the correct LinkProperties when starting.
- // TODO: pass LinkProperties to the NetworkMonitor in the notifyNetworkConnected call.
- if (networkAgent.networkAgentConfig.acceptPartialConnectivity) {
- networkAgent.networkMonitor().setAcceptPartialConnectivity();
- }
- networkAgent.networkMonitor().notifyNetworkConnected(
- new LinkProperties(networkAgent.linkProperties,
- true /* parcelSensitiveFields */),
- networkAgent.networkCapabilities);
- scheduleUnvalidatedPrompt(networkAgent);
-
- // Whether a particular NetworkRequest listen should cause signal strength thresholds to
- // be communicated to a particular NetworkAgent depends only on the network's immutable,
- // capabilities, so it only needs to be done once on initial connect, not every time the
- // network's capabilities change. Note that we do this before rematching the network,
- // so we could decide to tear it down immediately afterwards. That's fine though - on
- // disconnection NetworkAgents should stop any signal strength monitoring they have been
- // doing.
- updateSignalStrengthThresholds(networkAgent, "CONNECT", null);
-
- // Before first rematching networks, put an inactivity timer without any request, this
- // allows {@code updateInactivityState} to update the state accordingly and prevent
- // tearing down for any {@code unneeded} evaluation in this period.
- // Note that the timer will not be rescheduled since the expiry time is
- // fixed after connection regardless of the network satisfying other requests or not.
- // But it will be removed as soon as the network satisfies a request for the first time.
- networkAgent.lingerRequest(NetworkRequest.REQUEST_ID_NONE,
- SystemClock.elapsedRealtime(), mNascentDelayMs);
- networkAgent.setInactive();
-
- // Consider network even though it is not yet validated.
- rematchAllNetworksAndRequests();
-
- // This has to happen after matching the requests, because callbacks are just requests.
- notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);
- } else if (state == NetworkInfo.State.DISCONNECTED) {
- networkAgent.disconnect();
- if (networkAgent.isVPN()) {
- updateUids(networkAgent, networkAgent.networkCapabilities, null);
- }
- disconnectAndDestroyNetwork(networkAgent);
- if (networkAgent.isVPN()) {
- // As the active or bound network changes for apps, broadcast the default proxy, as
- // apps may need to update their proxy data. This is called after disconnecting from
- // VPN to make sure we do not broadcast the old proxy data.
- // TODO(b/122649188): send the broadcast only to VPN users.
- mProxyTracker.sendProxyBroadcast();
- }
- } else if (networkAgent.created && (oldInfo.getState() == NetworkInfo.State.SUSPENDED ||
- state == NetworkInfo.State.SUSPENDED)) {
- mLegacyTypeTracker.update(networkAgent);
- }
- }
-
- private void updateNetworkScore(@NonNull final NetworkAgentInfo nai, final NetworkScore score) {
- if (VDBG || DDBG) log("updateNetworkScore for " + nai.toShortString() + " to " + score);
- nai.setScore(score);
- rematchAllNetworksAndRequests();
- }
-
- // Notify only this one new request of the current state. Transfer all the
- // current state by calling NetworkCapabilities and LinkProperties callbacks
- // so that callers can be guaranteed to have as close to atomicity in state
- // transfer as can be supported by this current API.
- protected void notifyNetworkAvailable(NetworkAgentInfo nai, NetworkRequestInfo nri) {
- mHandler.removeMessages(EVENT_TIMEOUT_NETWORK_REQUEST, nri);
- if (nri.mPendingIntent != null) {
- sendPendingIntentForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE);
- // Attempt no subsequent state pushes where intents are involved.
- return;
- }
-
- final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE);
- final boolean metered = nai.networkCapabilities.isMetered();
- final boolean vpnBlocked = isUidBlockedByVpn(nri.mAsUid, mVpnBlockedUidRanges);
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE,
- getBlockedState(blockedReasons, metered, vpnBlocked));
- }
-
- // Notify the requests on this NAI that the network is now lingered.
- private void notifyNetworkLosing(@NonNull final NetworkAgentInfo nai, final long now) {
- final int lingerTime = (int) (nai.getInactivityExpiry() - now);
- notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime);
- }
-
- private static int getBlockedState(int reasons, boolean metered, boolean vpnBlocked) {
- if (!metered) reasons &= ~BLOCKED_METERED_REASON_MASK;
- return vpnBlocked
- ? reasons | BLOCKED_REASON_LOCKDOWN_VPN
- : reasons & ~BLOCKED_REASON_LOCKDOWN_VPN;
- }
-
- private void setUidBlockedReasons(int uid, @BlockedReason int blockedReasons) {
- if (blockedReasons == BLOCKED_REASON_NONE) {
- mUidBlockedReasons.delete(uid);
- } else {
- mUidBlockedReasons.put(uid, blockedReasons);
- }
- }
-
- /**
- * Notify of the blocked state apps with a registered callback matching a given NAI.
- *
- * Unlike other callbacks, blocked status is different between each individual uid. So for
- * any given nai, all requests need to be considered according to the uid who filed it.
- *
- * @param nai The target NetworkAgentInfo.
- * @param oldMetered True if the previous network capabilities were metered.
- * @param newMetered True if the current network capabilities are metered.
- * @param oldBlockedUidRanges list of UID ranges previously blocked by lockdown VPN.
- * @param newBlockedUidRanges list of UID ranges blocked by lockdown VPN.
- */
- private void maybeNotifyNetworkBlocked(NetworkAgentInfo nai, boolean oldMetered,
- boolean newMetered, List<UidRange> oldBlockedUidRanges,
- List<UidRange> newBlockedUidRanges) {
-
- for (int i = 0; i < nai.numNetworkRequests(); i++) {
- NetworkRequest nr = nai.requestAt(i);
- NetworkRequestInfo nri = mNetworkRequests.get(nr);
-
- final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE);
- final boolean oldVpnBlocked = isUidBlockedByVpn(nri.mAsUid, oldBlockedUidRanges);
- final boolean newVpnBlocked = (oldBlockedUidRanges != newBlockedUidRanges)
- ? isUidBlockedByVpn(nri.mAsUid, newBlockedUidRanges)
- : oldVpnBlocked;
-
- final int oldBlockedState = getBlockedState(blockedReasons, oldMetered, oldVpnBlocked);
- final int newBlockedState = getBlockedState(blockedReasons, newMetered, newVpnBlocked);
- if (oldBlockedState != newBlockedState) {
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
- newBlockedState);
- }
- }
- }
-
- /**
- * Notify apps with a given UID of the new blocked state according to new uid state.
- * @param uid The uid for which the rules changed.
- * @param blockedReasons The reasons for why an uid is blocked.
- */
- private void maybeNotifyNetworkBlockedForNewState(int uid, @BlockedReason int blockedReasons) {
- for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
- final boolean metered = nai.networkCapabilities.isMetered();
- final boolean vpnBlocked = isUidBlockedByVpn(uid, mVpnBlockedUidRanges);
-
- final int oldBlockedState = getBlockedState(
- mUidBlockedReasons.get(uid, BLOCKED_REASON_NONE), metered, vpnBlocked);
- final int newBlockedState = getBlockedState(blockedReasons, metered, vpnBlocked);
- if (oldBlockedState == newBlockedState) {
- continue;
- }
- for (int i = 0; i < nai.numNetworkRequests(); i++) {
- NetworkRequest nr = nai.requestAt(i);
- NetworkRequestInfo nri = mNetworkRequests.get(nr);
- if (nri != null && nri.mAsUid == uid) {
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
- newBlockedState);
- }
- }
- }
- }
-
- @VisibleForTesting
- protected void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, DetailedState state, int type) {
- // The NetworkInfo we actually send out has no bearing on the real
- // state of affairs. For example, if the default connection is mobile,
- // and a request for HIPRI has just gone away, we need to pretend that
- // HIPRI has just disconnected. So we need to set the type to HIPRI and
- // the state to DISCONNECTED, even though the network is of type MOBILE
- // and is still connected.
- NetworkInfo info = new NetworkInfo(nai.networkInfo);
- info.setType(type);
- filterForLegacyLockdown(info);
- if (state != DetailedState.DISCONNECTED) {
- info.setDetailedState(state, null, info.getExtraInfo());
- sendConnectedBroadcast(info);
- } else {
- info.setDetailedState(state, info.getReason(), info.getExtraInfo());
- Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
- intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
- if (info.isFailover()) {
- intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true);
- nai.networkInfo.setFailover(false);
- }
- if (info.getReason() != null) {
- intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason());
- }
- if (info.getExtraInfo() != null) {
- intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
- }
- NetworkAgentInfo newDefaultAgent = null;
- if (nai.isSatisfyingRequest(mDefaultRequest.mRequests.get(0).requestId)) {
- newDefaultAgent = mDefaultRequest.getSatisfier();
- if (newDefaultAgent != null) {
- intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO,
- newDefaultAgent.networkInfo);
- } else {
- intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
- }
- }
- intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION,
- mDefaultInetConditionPublished);
- sendStickyBroadcast(intent);
- if (newDefaultAgent != null) {
- sendConnectedBroadcast(newDefaultAgent.networkInfo);
- }
- }
- }
-
- protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType, int arg1) {
- if (VDBG || DDBG) {
- String notification = ConnectivityManager.getCallbackName(notifyType);
- log("notifyType " + notification + " for " + networkAgent.toShortString());
- }
- for (int i = 0; i < networkAgent.numNetworkRequests(); i++) {
- NetworkRequest nr = networkAgent.requestAt(i);
- NetworkRequestInfo nri = mNetworkRequests.get(nr);
- if (VDBG) log(" sending notification for " + nr);
- if (nri.mPendingIntent == null) {
- callCallbackForRequest(nri, networkAgent, notifyType, arg1);
- } else {
- sendPendingIntentForRequest(nri, networkAgent, notifyType);
- }
- }
- }
-
- protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType) {
- notifyNetworkCallbacks(networkAgent, notifyType, 0);
- }
-
- /**
- * Returns the list of all interfaces that could be used by network traffic that does not
- * explicitly specify a network. This includes the default network, but also all VPNs that are
- * currently connected.
- *
- * Must be called on the handler thread.
- */
- @NonNull
- private ArrayList<Network> getDefaultNetworks() {
- ensureRunningOnConnectivityServiceThread();
- final ArrayList<Network> defaultNetworks = new ArrayList<>();
- final Set<Integer> activeNetIds = new ArraySet<>();
- for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
- if (nri.isBeingSatisfied()) {
- activeNetIds.add(nri.getSatisfier().network().netId);
- }
- }
- for (NetworkAgentInfo nai : mNetworkAgentInfos) {
- if (nai.everConnected && (activeNetIds.contains(nai.network().netId) || nai.isVPN())) {
- defaultNetworks.add(nai.network);
- }
- }
- return defaultNetworks;
- }
-
- /**
- * Notify NetworkStatsService that the set of active ifaces has changed, or that one of the
- * active iface's tracked properties has changed.
- */
- private void notifyIfacesChangedForNetworkStats() {
- ensureRunningOnConnectivityServiceThread();
- String activeIface = null;
- LinkProperties activeLinkProperties = getActiveLinkProperties();
- if (activeLinkProperties != null) {
- activeIface = activeLinkProperties.getInterfaceName();
- }
-
- final UnderlyingNetworkInfo[] underlyingNetworkInfos = getAllVpnInfo();
- try {
- final ArrayList<NetworkStateSnapshot> snapshots = new ArrayList<>();
- for (final NetworkStateSnapshot snapshot : getAllNetworkStateSnapshots()) {
- snapshots.add(snapshot);
- }
- mStatsManager.notifyNetworkStatus(getDefaultNetworks(),
- snapshots, activeIface, Arrays.asList(underlyingNetworkInfos));
- } catch (Exception ignored) {
- }
- }
-
- @Override
- public String getCaptivePortalServerUrl() {
- enforceNetworkStackOrSettingsPermission();
- String settingUrl = mResources.get().getString(
- R.string.config_networkCaptivePortalServerUrl);
-
- if (!TextUtils.isEmpty(settingUrl)) {
- return settingUrl;
- }
-
- settingUrl = Settings.Global.getString(mContext.getContentResolver(),
- ConnectivitySettingsManager.CAPTIVE_PORTAL_HTTP_URL);
- if (!TextUtils.isEmpty(settingUrl)) {
- return settingUrl;
- }
-
- return DEFAULT_CAPTIVE_PORTAL_HTTP_URL;
- }
-
- @Override
- public void startNattKeepalive(Network network, int intervalSeconds,
- ISocketKeepaliveCallback cb, String srcAddr, int srcPort, String dstAddr) {
- enforceKeepalivePermission();
- mKeepaliveTracker.startNattKeepalive(
- getNetworkAgentInfoForNetwork(network), null /* fd */,
- intervalSeconds, cb,
- srcAddr, srcPort, dstAddr, NattSocketKeepalive.NATT_PORT);
- }
-
- @Override
- public void startNattKeepaliveWithFd(Network network, ParcelFileDescriptor pfd, int resourceId,
- int intervalSeconds, ISocketKeepaliveCallback cb, String srcAddr,
- String dstAddr) {
- try {
- final FileDescriptor fd = pfd.getFileDescriptor();
- mKeepaliveTracker.startNattKeepalive(
- getNetworkAgentInfoForNetwork(network), fd, resourceId,
- intervalSeconds, cb,
- srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT);
- } finally {
- // FileDescriptors coming from AIDL calls must be manually closed to prevent leaks.
- // startNattKeepalive calls Os.dup(fd) before returning, so we can close immediately.
- if (pfd != null && Binder.getCallingPid() != Process.myPid()) {
- IoUtils.closeQuietly(pfd);
- }
- }
- }
-
- @Override
- public void startTcpKeepalive(Network network, ParcelFileDescriptor pfd, int intervalSeconds,
- ISocketKeepaliveCallback cb) {
- try {
- enforceKeepalivePermission();
- final FileDescriptor fd = pfd.getFileDescriptor();
- mKeepaliveTracker.startTcpKeepalive(
- getNetworkAgentInfoForNetwork(network), fd, intervalSeconds, cb);
- } finally {
- // FileDescriptors coming from AIDL calls must be manually closed to prevent leaks.
- // startTcpKeepalive calls Os.dup(fd) before returning, so we can close immediately.
- if (pfd != null && Binder.getCallingPid() != Process.myPid()) {
- IoUtils.closeQuietly(pfd);
- }
- }
- }
-
- @Override
- public void stopKeepalive(Network network, int slot) {
- mHandler.sendMessage(mHandler.obtainMessage(
- NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE, slot, SocketKeepalive.SUCCESS, network));
- }
-
- @Override
- public void factoryReset() {
- enforceSettingsPermission();
-
- if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
- return;
- }
-
- final long token = Binder.clearCallingIdentity();
- try {
- final IpMemoryStore ipMemoryStore = IpMemoryStore.getMemoryStore(mContext);
- ipMemoryStore.factoryReset();
- } finally {
- Binder.restoreCallingIdentity(token);
- }
-
- // Turn airplane mode off
- setAirplaneMode(false);
-
- // restore private DNS settings to default mode (opportunistic)
- if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS)) {
- ConnectivitySettingsManager.setPrivateDnsMode(mContext, PRIVATE_DNS_MODE_OPPORTUNISTIC);
- }
-
- Settings.Global.putString(mContext.getContentResolver(),
- ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, null);
- }
-
- @Override
- public byte[] getNetworkWatchlistConfigHash() {
- NetworkWatchlistManager nwm = mContext.getSystemService(NetworkWatchlistManager.class);
- if (nwm == null) {
- loge("Unable to get NetworkWatchlistManager");
- return null;
- }
- // Redirect it to network watchlist service to access watchlist file and calculate hash.
- return nwm.getWatchlistConfigHash();
- }
-
- private void logNetworkEvent(NetworkAgentInfo nai, int evtype) {
- int[] transports = nai.networkCapabilities.getTransportTypes();
- mMetricsLog.log(nai.network.getNetId(), transports, new NetworkEvent(evtype));
- }
-
- private static boolean toBool(int encodedBoolean) {
- return encodedBoolean != 0; // Only 0 means false.
- }
-
- private static int encodeBool(boolean b) {
- return b ? 1 : 0;
- }
-
- @Override
- public int handleShellCommand(@NonNull ParcelFileDescriptor in,
- @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
- @NonNull String[] args) {
- return new ShellCmd().exec(this, in.getFileDescriptor(), out.getFileDescriptor(),
- err.getFileDescriptor(), args);
- }
-
- private class ShellCmd extends BasicShellCommandHandler {
- @Override
- public int onCommand(String cmd) {
- if (cmd == null) {
- return handleDefaultCommands(cmd);
- }
- final PrintWriter pw = getOutPrintWriter();
- try {
- switch (cmd) {
- case "airplane-mode":
- final String action = getNextArg();
- if ("enable".equals(action)) {
- setAirplaneMode(true);
- return 0;
- } else if ("disable".equals(action)) {
- setAirplaneMode(false);
- return 0;
- } else if (action == null) {
- final ContentResolver cr = mContext.getContentResolver();
- final int enabled = Settings.Global.getInt(cr,
- Settings.Global.AIRPLANE_MODE_ON);
- pw.println(enabled == 0 ? "disabled" : "enabled");
- return 0;
- } else {
- onHelp();
- return -1;
- }
- default:
- return handleDefaultCommands(cmd);
- }
- } catch (Exception e) {
- pw.println(e);
- }
- return -1;
- }
-
- @Override
- public void onHelp() {
- PrintWriter pw = getOutPrintWriter();
- pw.println("Connectivity service commands:");
- pw.println(" help");
- pw.println(" Print this help text.");
- pw.println(" airplane-mode [enable|disable]");
- pw.println(" Turn airplane mode on or off.");
- pw.println(" airplane-mode");
- pw.println(" Get airplane mode.");
- }
- }
-
- private int getVpnType(@Nullable NetworkAgentInfo vpn) {
- if (vpn == null) return VpnManager.TYPE_VPN_NONE;
- final TransportInfo ti = vpn.networkCapabilities.getTransportInfo();
- if (!(ti instanceof VpnTransportInfo)) return VpnManager.TYPE_VPN_NONE;
- return ((VpnTransportInfo) ti).getType();
- }
-
- /**
- * @param connectionInfo the connection to resolve.
- * @return {@code uid} if the connection is found and the app has permission to observe it
- * (e.g., if it is associated with the calling VPN app's tunnel) or {@code INVALID_UID} if the
- * connection is not found.
- */
- public int getConnectionOwnerUid(ConnectionInfo connectionInfo) {
- if (connectionInfo.protocol != IPPROTO_TCP && connectionInfo.protocol != IPPROTO_UDP) {
- throw new IllegalArgumentException("Unsupported protocol " + connectionInfo.protocol);
- }
-
- final int uid = mDeps.getConnectionOwnerUid(connectionInfo.protocol,
- connectionInfo.local, connectionInfo.remote);
-
- if (uid == INVALID_UID) return uid; // Not found.
-
- // Connection owner UIDs are visible only to the network stack and to the VpnService-based
- // VPN, if any, that applies to the UID that owns the connection.
- if (checkNetworkStackPermission()) return uid;
-
- final NetworkAgentInfo vpn = getVpnForUid(uid);
- if (vpn == null || getVpnType(vpn) != VpnManager.TYPE_VPN_SERVICE
- || vpn.networkCapabilities.getOwnerUid() != mDeps.getCallingUid()) {
- return INVALID_UID;
- }
-
- return uid;
- }
-
- /**
- * Returns a IBinder to a TestNetworkService. Will be lazily created as needed.
- *
- * <p>The TestNetworkService must be run in the system server due to TUN creation.
- */
- @Override
- public IBinder startOrGetTestNetworkService() {
- synchronized (mTNSLock) {
- TestNetworkService.enforceTestNetworkPermissions(mContext);
-
- if (mTNS == null) {
- mTNS = new TestNetworkService(mContext);
- }
-
- return mTNS;
- }
- }
-
- /**
- * Handler used for managing all Connectivity Diagnostics related functions.
- *
- * @see android.net.ConnectivityDiagnosticsManager
- *
- * TODO(b/147816404): Explore moving ConnectivityDiagnosticsHandler to a separate file
- */
- @VisibleForTesting
- class ConnectivityDiagnosticsHandler extends Handler {
- private final String mTag = ConnectivityDiagnosticsHandler.class.getSimpleName();
-
- /**
- * Used to handle ConnectivityDiagnosticsCallback registration events from {@link
- * android.net.ConnectivityDiagnosticsManager}.
- * obj = ConnectivityDiagnosticsCallbackInfo with IConnectivityDiagnosticsCallback and
- * NetworkRequestInfo to be registered
- */
- private static final int EVENT_REGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK = 1;
-
- /**
- * Used to handle ConnectivityDiagnosticsCallback unregister events from {@link
- * android.net.ConnectivityDiagnosticsManager}.
- * obj = the IConnectivityDiagnosticsCallback to be unregistered
- * arg1 = the uid of the caller
- */
- private static final int EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK = 2;
-
- /**
- * Event for {@link NetworkStateTrackerHandler} to trigger ConnectivityReport callbacks
- * after processing {@link #EVENT_NETWORK_TESTED} events.
- * obj = {@link ConnectivityReportEvent} representing ConnectivityReport info reported from
- * NetworkMonitor.
- * data = PersistableBundle of extras passed from NetworkMonitor.
- *
- * <p>See {@link ConnectivityService#EVENT_NETWORK_TESTED}.
- */
- private static final int EVENT_NETWORK_TESTED = ConnectivityService.EVENT_NETWORK_TESTED;
-
- /**
- * Event for NetworkMonitor to inform ConnectivityService that a potential data stall has
- * been detected on the network.
- * obj = Long the timestamp (in millis) for when the suspected data stall was detected.
- * arg1 = {@link DataStallReport#DetectionMethod} indicating the detection method.
- * arg2 = NetID.
- * data = PersistableBundle of extras passed from NetworkMonitor.
- */
- private static final int EVENT_DATA_STALL_SUSPECTED = 4;
-
- /**
- * Event for ConnectivityDiagnosticsHandler to handle network connectivity being reported to
- * the platform. This event will invoke {@link
- * IConnectivityDiagnosticsCallback#onNetworkConnectivityReported} for permissioned
- * callbacks.
- * obj = Network that was reported on
- * arg1 = boolint for the quality reported
- */
- private static final int EVENT_NETWORK_CONNECTIVITY_REPORTED = 5;
-
- private ConnectivityDiagnosticsHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case EVENT_REGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK: {
- handleRegisterConnectivityDiagnosticsCallback(
- (ConnectivityDiagnosticsCallbackInfo) msg.obj);
- break;
- }
- case EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK: {
- handleUnregisterConnectivityDiagnosticsCallback(
- (IConnectivityDiagnosticsCallback) msg.obj, msg.arg1);
- break;
- }
- case EVENT_NETWORK_TESTED: {
- final ConnectivityReportEvent reportEvent =
- (ConnectivityReportEvent) msg.obj;
-
- handleNetworkTestedWithExtras(reportEvent, reportEvent.mExtras);
- break;
- }
- case EVENT_DATA_STALL_SUSPECTED: {
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
- final Pair<Long, PersistableBundle> arg =
- (Pair<Long, PersistableBundle>) msg.obj;
- if (nai == null) break;
-
- handleDataStallSuspected(nai, arg.first, msg.arg1, arg.second);
- break;
- }
- case EVENT_NETWORK_CONNECTIVITY_REPORTED: {
- handleNetworkConnectivityReported((NetworkAgentInfo) msg.obj, toBool(msg.arg1));
- break;
- }
- default: {
- Log.e(mTag, "Unrecognized event in ConnectivityDiagnostics: " + msg.what);
- }
- }
- }
- }
-
- /** Class used for cleaning up IConnectivityDiagnosticsCallback instances after their death. */
- @VisibleForTesting
- class ConnectivityDiagnosticsCallbackInfo implements Binder.DeathRecipient {
- @NonNull private final IConnectivityDiagnosticsCallback mCb;
- @NonNull private final NetworkRequestInfo mRequestInfo;
- @NonNull private final String mCallingPackageName;
-
- @VisibleForTesting
- ConnectivityDiagnosticsCallbackInfo(
- @NonNull IConnectivityDiagnosticsCallback cb,
- @NonNull NetworkRequestInfo nri,
- @NonNull String callingPackageName) {
- mCb = cb;
- mRequestInfo = nri;
- mCallingPackageName = callingPackageName;
- }
-
- @Override
- public void binderDied() {
- log("ConnectivityDiagnosticsCallback IBinder died.");
- unregisterConnectivityDiagnosticsCallback(mCb);
- }
- }
-
- /**
- * Class used for sending information from {@link
- * NetworkMonitorCallbacks#notifyNetworkTestedWithExtras} to the handler for processing it.
- */
- private static class NetworkTestedResults {
- private final int mNetId;
- private final int mTestResult;
- private final long mTimestampMillis;
- @Nullable private final String mRedirectUrl;
-
- private NetworkTestedResults(
- int netId, int testResult, long timestampMillis, @Nullable String redirectUrl) {
- mNetId = netId;
- mTestResult = testResult;
- mTimestampMillis = timestampMillis;
- mRedirectUrl = redirectUrl;
- }
- }
-
- /**
- * Class used for sending information from {@link NetworkStateTrackerHandler} to {@link
- * ConnectivityDiagnosticsHandler}.
- */
- private static class ConnectivityReportEvent {
- private final long mTimestampMillis;
- @NonNull private final NetworkAgentInfo mNai;
- private final PersistableBundle mExtras;
-
- private ConnectivityReportEvent(long timestampMillis, @NonNull NetworkAgentInfo nai,
- PersistableBundle p) {
- mTimestampMillis = timestampMillis;
- mNai = nai;
- mExtras = p;
- }
- }
-
- private void handleRegisterConnectivityDiagnosticsCallback(
- @NonNull ConnectivityDiagnosticsCallbackInfo cbInfo) {
- ensureRunningOnConnectivityServiceThread();
-
- final IConnectivityDiagnosticsCallback cb = cbInfo.mCb;
- final IBinder iCb = cb.asBinder();
- final NetworkRequestInfo nri = cbInfo.mRequestInfo;
-
- // Connectivity Diagnostics are meant to be used with a single network request. It would be
- // confusing for these networks to change when an NRI is satisfied in another layer.
- if (nri.isMultilayerRequest()) {
- throw new IllegalArgumentException("Connectivity Diagnostics do not support multilayer "
- + "network requests.");
- }
-
- // This means that the client registered the same callback multiple times. Do
- // not override the previous entry, and exit silently.
- if (mConnectivityDiagnosticsCallbacks.containsKey(iCb)) {
- if (VDBG) log("Diagnostics callback is already registered");
-
- // Decrement the reference count for this NetworkRequestInfo. The reference count is
- // incremented when the NetworkRequestInfo is created as part of
- // enforceRequestCountLimit().
- nri.decrementRequestCount();
- return;
- }
-
- mConnectivityDiagnosticsCallbacks.put(iCb, cbInfo);
-
- try {
- iCb.linkToDeath(cbInfo, 0);
- } catch (RemoteException e) {
- cbInfo.binderDied();
- return;
- }
-
- // Once registered, provide ConnectivityReports for matching Networks
- final List<NetworkAgentInfo> matchingNetworks = new ArrayList<>();
- synchronized (mNetworkForNetId) {
- for (int i = 0; i < mNetworkForNetId.size(); i++) {
- final NetworkAgentInfo nai = mNetworkForNetId.valueAt(i);
- // Connectivity Diagnostics rejects multilayer requests at registration hence get(0)
- if (nai.satisfies(nri.mRequests.get(0))) {
- matchingNetworks.add(nai);
- }
- }
- }
- for (final NetworkAgentInfo nai : matchingNetworks) {
- final ConnectivityReport report = nai.getConnectivityReport();
- if (report == null) {
- continue;
- }
- if (!checkConnectivityDiagnosticsPermissions(
- nri.mPid, nri.mUid, nai, cbInfo.mCallingPackageName)) {
- continue;
- }
-
- try {
- cb.onConnectivityReportAvailable(report);
- } catch (RemoteException e) {
- // Exception while sending the ConnectivityReport. Move on to the next network.
- }
- }
- }
-
- private void handleUnregisterConnectivityDiagnosticsCallback(
- @NonNull IConnectivityDiagnosticsCallback cb, int uid) {
- ensureRunningOnConnectivityServiceThread();
- final IBinder iCb = cb.asBinder();
-
- final ConnectivityDiagnosticsCallbackInfo cbInfo =
- mConnectivityDiagnosticsCallbacks.remove(iCb);
- if (cbInfo == null) {
- if (VDBG) log("Removing diagnostics callback that is not currently registered");
- return;
- }
-
- final NetworkRequestInfo nri = cbInfo.mRequestInfo;
-
- // Caller's UID must either be the registrants (if they are unregistering) or the System's
- // (if the Binder died)
- if (uid != nri.mUid && uid != Process.SYSTEM_UID) {
- if (DBG) loge("Uid(" + uid + ") not registrant's (" + nri.mUid + ") or System's");
- return;
- }
-
- // Decrement the reference count for this NetworkRequestInfo. The reference count is
- // incremented when the NetworkRequestInfo is created as part of
- // enforceRequestCountLimit().
- nri.decrementRequestCount();
-
- iCb.unlinkToDeath(cbInfo, 0);
- }
-
- private void handleNetworkTestedWithExtras(
- @NonNull ConnectivityReportEvent reportEvent, @NonNull PersistableBundle extras) {
- final NetworkAgentInfo nai = reportEvent.mNai;
- final NetworkCapabilities networkCapabilities =
- getNetworkCapabilitiesWithoutUids(nai.networkCapabilities);
- final ConnectivityReport report =
- new ConnectivityReport(
- reportEvent.mNai.network,
- reportEvent.mTimestampMillis,
- nai.linkProperties,
- networkCapabilities,
- extras);
- nai.setConnectivityReport(report);
- final List<IConnectivityDiagnosticsCallback> results =
- getMatchingPermissionedCallbacks(nai);
- for (final IConnectivityDiagnosticsCallback cb : results) {
- try {
- cb.onConnectivityReportAvailable(report);
- } catch (RemoteException ex) {
- loge("Error invoking onConnectivityReport", ex);
- }
- }
- }
-
- private void handleDataStallSuspected(
- @NonNull NetworkAgentInfo nai, long timestampMillis, int detectionMethod,
- @NonNull PersistableBundle extras) {
- final NetworkCapabilities networkCapabilities =
- getNetworkCapabilitiesWithoutUids(nai.networkCapabilities);
- final DataStallReport report =
- new DataStallReport(
- nai.network,
- timestampMillis,
- detectionMethod,
- nai.linkProperties,
- networkCapabilities,
- extras);
- final List<IConnectivityDiagnosticsCallback> results =
- getMatchingPermissionedCallbacks(nai);
- for (final IConnectivityDiagnosticsCallback cb : results) {
- try {
- cb.onDataStallSuspected(report);
- } catch (RemoteException ex) {
- loge("Error invoking onDataStallSuspected", ex);
- }
- }
- }
-
- private void handleNetworkConnectivityReported(
- @NonNull NetworkAgentInfo nai, boolean connectivity) {
- final List<IConnectivityDiagnosticsCallback> results =
- getMatchingPermissionedCallbacks(nai);
- for (final IConnectivityDiagnosticsCallback cb : results) {
- try {
- cb.onNetworkConnectivityReported(nai.network, connectivity);
- } catch (RemoteException ex) {
- loge("Error invoking onNetworkConnectivityReported", ex);
- }
- }
- }
-
- private NetworkCapabilities getNetworkCapabilitiesWithoutUids(@NonNull NetworkCapabilities nc) {
- final NetworkCapabilities sanitized = new NetworkCapabilities(nc,
- NetworkCapabilities.REDACT_ALL);
- sanitized.setUids(null);
- sanitized.setAdministratorUids(new int[0]);
- sanitized.setOwnerUid(Process.INVALID_UID);
- return sanitized;
- }
-
- private List<IConnectivityDiagnosticsCallback> getMatchingPermissionedCallbacks(
- @NonNull NetworkAgentInfo nai) {
- final List<IConnectivityDiagnosticsCallback> results = new ArrayList<>();
- for (Entry<IBinder, ConnectivityDiagnosticsCallbackInfo> entry :
- mConnectivityDiagnosticsCallbacks.entrySet()) {
- final ConnectivityDiagnosticsCallbackInfo cbInfo = entry.getValue();
- final NetworkRequestInfo nri = cbInfo.mRequestInfo;
- // Connectivity Diagnostics rejects multilayer requests at registration hence get(0).
- if (nai.satisfies(nri.mRequests.get(0))) {
- if (checkConnectivityDiagnosticsPermissions(
- nri.mPid, nri.mUid, nai, cbInfo.mCallingPackageName)) {
- results.add(entry.getValue().mCb);
- }
- }
- }
- return results;
- }
-
- @VisibleForTesting
- boolean checkConnectivityDiagnosticsPermissions(
- int callbackPid, int callbackUid, NetworkAgentInfo nai, String callbackPackageName) {
- if (checkNetworkStackPermission(callbackPid, callbackUid)) {
- return true;
- }
-
- // LocationPermissionChecker#checkLocationPermission can throw SecurityException if the uid
- // and package name don't match. Throwing on the CS thread is not acceptable, so wrap the
- // call in a try-catch.
- try {
- if (!mLocationPermissionChecker.checkLocationPermission(
- callbackPackageName, null /* featureId */, callbackUid, null /* message */)) {
- return false;
- }
- } catch (SecurityException e) {
- return false;
- }
-
- for (NetworkAgentInfo virtual : mNetworkAgentInfos) {
- if (virtual.supportsUnderlyingNetworks()
- && virtual.networkCapabilities.getOwnerUid() == callbackUid
- && CollectionUtils.contains(virtual.declaredUnderlyingNetworks, nai.network)) {
- return true;
- }
- }
-
- // Administrator UIDs also contains the Owner UID
- final int[] administratorUids = nai.networkCapabilities.getAdministratorUids();
- return CollectionUtils.contains(administratorUids, callbackUid);
- }
-
- @Override
- public void registerConnectivityDiagnosticsCallback(
- @NonNull IConnectivityDiagnosticsCallback callback,
- @NonNull NetworkRequest request,
- @NonNull String callingPackageName) {
- if (request.legacyType != TYPE_NONE) {
- throw new IllegalArgumentException("ConnectivityManager.TYPE_* are deprecated."
- + " Please use NetworkCapabilities instead.");
- }
- final int callingUid = mDeps.getCallingUid();
- mAppOpsManager.checkPackage(callingUid, callingPackageName);
-
- // This NetworkCapabilities is only used for matching to Networks. Clear out its owner uid
- // and administrator uids to be safe.
- final NetworkCapabilities nc = new NetworkCapabilities(request.networkCapabilities);
- restrictRequestUidsForCallerAndSetRequestorInfo(nc, callingUid, callingPackageName);
-
- final NetworkRequest requestWithId =
- new NetworkRequest(
- nc, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.LISTEN);
-
- // NetworkRequestInfos created here count towards MAX_NETWORK_REQUESTS_PER_UID limit.
- //
- // nri is not bound to the death of callback. Instead, callback.bindToDeath() is set in
- // handleRegisterConnectivityDiagnosticsCallback(). nri will be cleaned up as part of the
- // callback's binder death.
- final NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, requestWithId);
- final ConnectivityDiagnosticsCallbackInfo cbInfo =
- new ConnectivityDiagnosticsCallbackInfo(callback, nri, callingPackageName);
-
- mConnectivityDiagnosticsHandler.sendMessage(
- mConnectivityDiagnosticsHandler.obtainMessage(
- ConnectivityDiagnosticsHandler
- .EVENT_REGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK,
- cbInfo));
- }
-
- @Override
- public void unregisterConnectivityDiagnosticsCallback(
- @NonNull IConnectivityDiagnosticsCallback callback) {
- Objects.requireNonNull(callback, "callback must be non-null");
- mConnectivityDiagnosticsHandler.sendMessage(
- mConnectivityDiagnosticsHandler.obtainMessage(
- ConnectivityDiagnosticsHandler
- .EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK,
- mDeps.getCallingUid(),
- 0,
- callback));
- }
-
- @Override
- public void simulateDataStall(int detectionMethod, long timestampMillis,
- @NonNull Network network, @NonNull PersistableBundle extras) {
- enforceAnyPermissionOf(android.Manifest.permission.MANAGE_TEST_NETWORKS,
- android.Manifest.permission.NETWORK_STACK);
- final NetworkCapabilities nc = getNetworkCapabilitiesInternal(network);
- if (!nc.hasTransport(TRANSPORT_TEST)) {
- throw new SecurityException("Data Stall simluation is only possible for test networks");
- }
-
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai == null || nai.creatorUid != mDeps.getCallingUid()) {
- throw new SecurityException("Data Stall simulation is only possible for network "
- + "creators");
- }
-
- // Instead of passing the data stall directly to the ConnectivityDiagnostics handler, treat
- // this as a Data Stall received directly from NetworkMonitor. This requires wrapping the
- // Data Stall information as a DataStallReportParcelable and passing to
- // #notifyDataStallSuspected. This ensures that unknown Data Stall detection methods are
- // still passed to ConnectivityDiagnostics (with new detection methods masked).
- final DataStallReportParcelable p = new DataStallReportParcelable();
- p.timestampMillis = timestampMillis;
- p.detectionMethod = detectionMethod;
-
- if (hasDataStallDetectionMethod(p, DETECTION_METHOD_DNS_EVENTS)) {
- p.dnsConsecutiveTimeouts = extras.getInt(KEY_DNS_CONSECUTIVE_TIMEOUTS);
- }
- if (hasDataStallDetectionMethod(p, DETECTION_METHOD_TCP_METRICS)) {
- p.tcpPacketFailRate = extras.getInt(KEY_TCP_PACKET_FAIL_RATE);
- p.tcpMetricsCollectionPeriodMillis = extras.getInt(
- KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS);
- }
-
- notifyDataStallSuspected(p, network.getNetId());
- }
-
- private class NetdCallback extends BaseNetdUnsolicitedEventListener {
- @Override
- public void onInterfaceClassActivityChanged(boolean isActive, int transportType,
- long timestampNs, int uid) {
- mNetworkActivityTracker.setAndReportNetworkActive(isActive, transportType, timestampNs);
- }
-
- @Override
- public void onInterfaceLinkStateChanged(String iface, boolean up) {
- for (NetworkAgentInfo nai : mNetworkAgentInfos) {
- nai.clatd.interfaceLinkStateChanged(iface, up);
- }
- }
-
- @Override
- public void onInterfaceRemoved(String iface) {
- for (NetworkAgentInfo nai : mNetworkAgentInfos) {
- nai.clatd.interfaceRemoved(iface);
- }
- }
- }
-
- private final LegacyNetworkActivityTracker mNetworkActivityTracker;
-
- /**
- * Class used for updating network activity tracking with netd and notify network activity
- * changes.
- */
- private static final class LegacyNetworkActivityTracker {
- private static final int NO_UID = -1;
- private final Context mContext;
- private final INetd mNetd;
- private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
- new RemoteCallbackList<>();
- // Indicate the current system default network activity is active or not.
- @GuardedBy("mActiveIdleTimers")
- private boolean mNetworkActive;
- @GuardedBy("mActiveIdleTimers")
- private final ArrayMap<String, IdleTimerParams> mActiveIdleTimers = new ArrayMap();
- private final Handler mHandler;
-
- private class IdleTimerParams {
- public final int timeout;
- public final int transportType;
-
- IdleTimerParams(int timeout, int transport) {
- this.timeout = timeout;
- this.transportType = transport;
- }
- }
-
- LegacyNetworkActivityTracker(@NonNull Context context, @NonNull Handler handler,
- @NonNull INetd netd) {
- mContext = context;
- mNetd = netd;
- mHandler = handler;
- }
-
- public void setAndReportNetworkActive(boolean active, int transportType, long tsNanos) {
- sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active, tsNanos);
- synchronized (mActiveIdleTimers) {
- mNetworkActive = active;
- // If there are no idle timers, it means that system is not monitoring
- // activity, so the system default network for those default network
- // unspecified apps is always considered active.
- //
- // TODO: If the mActiveIdleTimers is empty, netd will actually not send
- // any network activity change event. Whenever this event is received,
- // the mActiveIdleTimers should be always not empty. The legacy behavior
- // is no-op. Remove to refer to mNetworkActive only.
- if (mNetworkActive || mActiveIdleTimers.isEmpty()) {
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_REPORT_NETWORK_ACTIVITY));
- }
- }
- }
-
- // The network activity should only be updated from ConnectivityService handler thread
- // when mActiveIdleTimers lock is held.
- @GuardedBy("mActiveIdleTimers")
- private void reportNetworkActive() {
- final int length = mNetworkActivityListeners.beginBroadcast();
- if (DDBG) log("reportNetworkActive, notify " + length + " listeners");
- try {
- for (int i = 0; i < length; i++) {
- try {
- mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
- } catch (RemoteException | RuntimeException e) {
- loge("Fail to send network activie to listener " + e);
- }
- }
- } finally {
- mNetworkActivityListeners.finishBroadcast();
- }
- }
-
- @GuardedBy("mActiveIdleTimers")
- public void handleReportNetworkActivity() {
- synchronized (mActiveIdleTimers) {
- reportNetworkActive();
- }
- }
-
- // This is deprecated and only to support legacy use cases.
- private int transportTypeToLegacyType(int type) {
- switch (type) {
- case NetworkCapabilities.TRANSPORT_CELLULAR:
- return TYPE_MOBILE;
- case NetworkCapabilities.TRANSPORT_WIFI:
- return TYPE_WIFI;
- case NetworkCapabilities.TRANSPORT_BLUETOOTH:
- return TYPE_BLUETOOTH;
- case NetworkCapabilities.TRANSPORT_ETHERNET:
- return TYPE_ETHERNET;
- default:
- loge("Unexpected transport in transportTypeToLegacyType: " + type);
- }
- return ConnectivityManager.TYPE_NONE;
- }
-
- public void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) {
- final Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
- intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
- intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active);
- intent.putExtra(ConnectivityManager.EXTRA_REALTIME_NS, tsNanos);
- final long ident = Binder.clearCallingIdentity();
- try {
- mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL,
- RECEIVE_DATA_ACTIVITY_CHANGE,
- null /* resultReceiver */,
- null /* scheduler */,
- 0 /* initialCode */,
- null /* initialData */,
- null /* initialExtra */);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- /**
- * Setup data activity tracking for the given network.
- *
- * Every {@code setupDataActivityTracking} should be paired with a
- * {@link #removeDataActivityTracking} for cleanup.
- */
- private void setupDataActivityTracking(NetworkAgentInfo networkAgent) {
- final String iface = networkAgent.linkProperties.getInterfaceName();
-
- final int timeout;
- final int type;
-
- if (networkAgent.networkCapabilities.hasTransport(
- NetworkCapabilities.TRANSPORT_CELLULAR)) {
- timeout = Settings.Global.getInt(mContext.getContentResolver(),
- ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_MOBILE,
- 10);
- type = NetworkCapabilities.TRANSPORT_CELLULAR;
- } else if (networkAgent.networkCapabilities.hasTransport(
- NetworkCapabilities.TRANSPORT_WIFI)) {
- timeout = Settings.Global.getInt(mContext.getContentResolver(),
- ConnectivitySettingsManager.DATA_ACTIVITY_TIMEOUT_WIFI,
- 15);
- type = NetworkCapabilities.TRANSPORT_WIFI;
- } else {
- return; // do not track any other networks
- }
-
- updateRadioPowerState(true /* isActive */, type);
-
- if (timeout > 0 && iface != null) {
- try {
- synchronized (mActiveIdleTimers) {
- // Networks start up.
- mNetworkActive = true;
- mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, type));
- mNetd.idletimerAddInterface(iface, timeout, Integer.toString(type));
- reportNetworkActive();
- }
- } catch (Exception e) {
- // You shall not crash!
- loge("Exception in setupDataActivityTracking " + e);
- }
- }
- }
-
- /**
- * Remove data activity tracking when network disconnects.
- */
- private void removeDataActivityTracking(NetworkAgentInfo networkAgent) {
- final String iface = networkAgent.linkProperties.getInterfaceName();
- final NetworkCapabilities caps = networkAgent.networkCapabilities;
-
- if (iface == null) return;
-
- final int type;
- if (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
- type = NetworkCapabilities.TRANSPORT_CELLULAR;
- } else if (caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
- type = NetworkCapabilities.TRANSPORT_WIFI;
- } else {
- return; // do not track any other networks
- }
-
- try {
- updateRadioPowerState(false /* isActive */, type);
- synchronized (mActiveIdleTimers) {
- final IdleTimerParams params = mActiveIdleTimers.remove(iface);
- // The call fails silently if no idle timer setup for this interface
- mNetd.idletimerRemoveInterface(iface, params.timeout,
- Integer.toString(params.transportType));
- }
- } catch (Exception e) {
- // You shall not crash!
- loge("Exception in removeDataActivityTracking " + e);
- }
- }
-
- /**
- * Update data activity tracking when network state is updated.
- */
- public void updateDataActivityTracking(NetworkAgentInfo newNetwork,
- NetworkAgentInfo oldNetwork) {
- if (newNetwork != null) {
- setupDataActivityTracking(newNetwork);
- }
- if (oldNetwork != null) {
- removeDataActivityTracking(oldNetwork);
- }
- }
-
- private void updateRadioPowerState(boolean isActive, int transportType) {
- final BatteryStatsManager bs = mContext.getSystemService(BatteryStatsManager.class);
- switch (transportType) {
- case NetworkCapabilities.TRANSPORT_CELLULAR:
- bs.reportMobileRadioPowerState(isActive, NO_UID);
- break;
- case NetworkCapabilities.TRANSPORT_WIFI:
- bs.reportWifiRadioPowerState(isActive, NO_UID);
- break;
- default:
- logw("Untracked transport type:" + transportType);
- }
- }
-
- public boolean isDefaultNetworkActive() {
- synchronized (mActiveIdleTimers) {
- // If there are no idle timers, it means that system is not monitoring activity,
- // so the default network is always considered active.
- //
- // TODO : Distinguish between the cases where mActiveIdleTimers is empty because
- // tracking is disabled (negative idle timer value configured), or no active default
- // network. In the latter case, this reports active but it should report inactive.
- return mNetworkActive || mActiveIdleTimers.isEmpty();
- }
- }
-
- public void registerNetworkActivityListener(@NonNull INetworkActivityListener l) {
- mNetworkActivityListeners.register(l);
- }
-
- public void unregisterNetworkActivityListener(@NonNull INetworkActivityListener l) {
- mNetworkActivityListeners.unregister(l);
- }
-
- public void dump(IndentingPrintWriter pw) {
- synchronized (mActiveIdleTimers) {
- pw.print("mNetworkActive="); pw.println(mNetworkActive);
- pw.println("Idle timers:");
- for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {
- pw.print(" "); pw.print(ent.getKey()); pw.println(":");
- final IdleTimerParams params = ent.getValue();
- pw.print(" timeout="); pw.print(params.timeout);
- pw.print(" type="); pw.println(params.transportType);
- }
- }
- }
- }
-
- /**
- * Registers {@link QosSocketFilter} with {@link IQosCallback}.
- *
- * @param socketInfo the socket information
- * @param callback the callback to register
- */
- @Override
- public void registerQosSocketCallback(@NonNull final QosSocketInfo socketInfo,
- @NonNull final IQosCallback callback) {
- final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(socketInfo.getNetwork());
- if (nai == null || nai.networkCapabilities == null) {
- try {
- callback.onError(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
- } catch (final RemoteException ex) {
- loge("registerQosCallbackInternal: RemoteException", ex);
- }
- return;
- }
- registerQosCallbackInternal(new QosSocketFilter(socketInfo), callback, nai);
- }
-
- /**
- * Register a {@link IQosCallback} with base {@link QosFilter}.
- *
- * @param filter the filter to register
- * @param callback the callback to register
- * @param nai the agent information related to the filter's network
- */
- @VisibleForTesting
- public void registerQosCallbackInternal(@NonNull final QosFilter filter,
- @NonNull final IQosCallback callback, @NonNull final NetworkAgentInfo nai) {
- if (filter == null) throw new IllegalArgumentException("filter must be non-null");
- if (callback == null) throw new IllegalArgumentException("callback must be non-null");
-
- if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
- enforceConnectivityRestrictedNetworksPermission();
- }
- mQosCallbackTracker.registerCallback(callback, filter, nai);
- }
-
- /**
- * Unregisters the given callback.
- *
- * @param callback the callback to unregister
- */
- @Override
- public void unregisterQosCallback(@NonNull final IQosCallback callback) {
- Objects.requireNonNull(callback, "callback must be non-null");
- mQosCallbackTracker.unregisterCallback(callback);
- }
-
- // Network preference per-profile and OEM network preferences can't be set at the same
- // time, because it is unclear what should happen if both preferences are active for
- // one given UID. To make it possible, the stack would have to clarify what would happen
- // in case both are active at the same time. The implementation may have to be adjusted
- // to implement the resulting rules. For example, a priority could be defined between them,
- // where the OEM preference would be considered less or more important than the enterprise
- // preference ; this would entail implementing the priorities somehow, e.g. by doing
- // UID arithmetic with UID ranges or passing a priority to netd so that the routing rules
- // are set at the right level. Other solutions are possible, e.g. merging of the
- // preferences for the relevant UIDs.
- private static void throwConcurrentPreferenceException() {
- throw new IllegalStateException("Can't set NetworkPreferenceForUser and "
- + "set OemNetworkPreference at the same time");
- }
-
- /**
- * Request that a user profile is put by default on a network matching a given preference.
- *
- * See the documentation for the individual preferences for a description of the supported
- * behaviors.
- *
- * @param profile the profile concerned.
- * @param preference the preference for this profile, as one of the PROFILE_NETWORK_PREFERENCE_*
- * constants.
- * @param listener an optional listener to listen for completion of the operation.
- */
- @Override
- public void setProfileNetworkPreference(@NonNull final UserHandle profile,
- @ConnectivityManager.ProfileNetworkPreference final int preference,
- @Nullable final IOnCompleteListener listener) {
- Objects.requireNonNull(profile);
- PermissionUtils.enforceNetworkStackPermission(mContext);
- if (DBG) {
- log("setProfileNetworkPreference " + profile + " to " + preference);
- }
- if (profile.getIdentifier() < 0) {
- throw new IllegalArgumentException("Must explicitly specify a user handle ("
- + "UserHandle.CURRENT not supported)");
- }
- final UserManager um = mContext.getSystemService(UserManager.class);
- if (!um.isManagedProfile(profile.getIdentifier())) {
- throw new IllegalArgumentException("Profile must be a managed profile");
- }
- // Strictly speaking, mOemNetworkPreferences should only be touched on the
- // handler thread. However it is an immutable object, so reading the reference is
- // safe - it's just possible the value is slightly outdated. For the final check,
- // see #handleSetProfileNetworkPreference. But if this can be caught here it is a
- // lot easier to understand, so opportunistically check it.
- if (!mOemNetworkPreferences.isEmpty()) {
- throwConcurrentPreferenceException();
- }
- final NetworkCapabilities nc;
- switch (preference) {
- case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT:
- nc = null;
- break;
- case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE:
- final UidRange uids = UidRange.createForUser(profile);
- nc = createDefaultNetworkCapabilitiesForUidRange(uids);
- nc.addCapability(NET_CAPABILITY_ENTERPRISE);
- nc.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- break;
- default:
- throw new IllegalArgumentException(
- "Invalid preference in setProfileNetworkPreference");
- }
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_PROFILE_NETWORK_PREFERENCE,
- new Pair<>(new ProfileNetworkPreferences.Preference(profile, nc), listener)));
- }
-
- private void validateNetworkCapabilitiesOfProfileNetworkPreference(
- @Nullable final NetworkCapabilities nc) {
- if (null == nc) return; // Null caps are always allowed. It means to remove the setting.
- ensureRequestableCapabilities(nc);
- }
-
- private ArraySet<NetworkRequestInfo> createNrisFromProfileNetworkPreferences(
- @NonNull final ProfileNetworkPreferences prefs) {
- final ArraySet<NetworkRequestInfo> result = new ArraySet<>();
- for (final ProfileNetworkPreferences.Preference pref : prefs.preferences) {
- // The NRI for a user should be comprised of two layers:
- // - The request for the capabilities
- // - The request for the default network, for fallback. Create an image of it to
- // have the correct UIDs in it (also a request can only be part of one NRI, because
- // of lookups in 1:1 associations like mNetworkRequests).
- // Note that denying a fallback can be implemented simply by not adding the second
- // request.
- final ArrayList<NetworkRequest> nrs = new ArrayList<>();
- nrs.add(createNetworkRequest(NetworkRequest.Type.REQUEST, pref.capabilities));
- nrs.add(createDefaultInternetRequestForTransport(
- TYPE_NONE, NetworkRequest.Type.TRACK_DEFAULT));
- setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids()));
- final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs);
- result.add(nri);
- }
- return result;
- }
-
- private void handleSetProfileNetworkPreference(
- @NonNull final ProfileNetworkPreferences.Preference preference,
- @Nullable final IOnCompleteListener listener) {
- // setProfileNetworkPreference and setOemNetworkPreference are mutually exclusive, in
- // particular because it's not clear what preference should win in case both apply
- // to the same app.
- // The binder call has already checked this, but as mOemNetworkPreferences is only
- // touched on the handler thread, it's theoretically not impossible that it has changed
- // since.
- if (!mOemNetworkPreferences.isEmpty()) {
- // This may happen on a device with an OEM preference set when a user is removed.
- // In this case, it's safe to ignore. In particular this happens in the tests.
- loge("handleSetProfileNetworkPreference, but OEM network preferences not empty");
- return;
- }
-
- validateNetworkCapabilitiesOfProfileNetworkPreference(preference.capabilities);
-
- mProfileNetworkPreferences = mProfileNetworkPreferences.plus(preference);
- mSystemNetworkRequestCounter.transact(
- mDeps.getCallingUid(), mProfileNetworkPreferences.preferences.size(),
- () -> {
- final ArraySet<NetworkRequestInfo> nris =
- createNrisFromProfileNetworkPreferences(mProfileNetworkPreferences);
- replaceDefaultNetworkRequestsForPreference(nris);
- });
- // Finally, rematch.
- rematchAllNetworksAndRequests();
-
- if (null != listener) {
- try {
- listener.onComplete();
- } catch (RemoteException e) {
- loge("Listener for setProfileNetworkPreference has died");
- }
- }
- }
-
- private void enforceAutomotiveDevice() {
- final boolean isAutomotiveDevice =
- mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
- if (!isAutomotiveDevice) {
- throw new UnsupportedOperationException(
- "setOemNetworkPreference() is only available on automotive devices.");
- }
- }
-
- /**
- * Used by automotive devices to set the network preferences used to direct traffic at an
- * application level as per the given OemNetworkPreferences. An example use-case would be an
- * automotive OEM wanting to provide connectivity for applications critical to the usage of a
- * vehicle via a particular network.
- *
- * Calling this will overwrite the existing preference.
- *
- * @param preference {@link OemNetworkPreferences} The application network preference to be set.
- * @param listener {@link ConnectivityManager.OnCompleteListener} Listener used
- * to communicate completion of setOemNetworkPreference();
- */
- @Override
- public void setOemNetworkPreference(
- @NonNull final OemNetworkPreferences preference,
- @Nullable final IOnCompleteListener listener) {
-
- enforceAutomotiveDevice();
- enforceOemNetworkPreferencesPermission();
-
- if (!mProfileNetworkPreferences.isEmpty()) {
- // Strictly speaking, mProfileNetworkPreferences should only be touched on the
- // handler thread. However it is an immutable object, so reading the reference is
- // safe - it's just possible the value is slightly outdated. For the final check,
- // see #handleSetOemPreference. But if this can be caught here it is a
- // lot easier to understand, so opportunistically check it.
- throwConcurrentPreferenceException();
- }
-
- Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
- validateOemNetworkPreferences(preference);
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_OEM_NETWORK_PREFERENCE,
- new Pair<>(preference, listener)));
- }
-
- private void validateOemNetworkPreferences(@NonNull OemNetworkPreferences preference) {
- for (@OemNetworkPreferences.OemNetworkPreference final int pref
- : preference.getNetworkPreferences().values()) {
- if (OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED == pref) {
- final String msg = "OEM_NETWORK_PREFERENCE_UNINITIALIZED is an invalid value.";
- throw new IllegalArgumentException(msg);
- }
- }
- }
-
- private void handleSetOemNetworkPreference(
- @NonNull final OemNetworkPreferences preference,
- @Nullable final IOnCompleteListener listener) {
- Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
- if (DBG) {
- log("set OEM network preferences :" + preference.toString());
- }
- // setProfileNetworkPreference and setOemNetworkPreference are mutually exclusive, in
- // particular because it's not clear what preference should win in case both apply
- // to the same app.
- // The binder call has already checked this, but as mOemNetworkPreferences is only
- // touched on the handler thread, it's theoretically not impossible that it has changed
- // since.
- if (!mProfileNetworkPreferences.isEmpty()) {
- logwtf("handleSetOemPreference, but per-profile network preferences not empty");
- return;
- }
-
- mOemNetworkPreferencesLogs.log("UPDATE INITIATED: " + preference);
- final int uniquePreferenceCount = new ArraySet<>(
- preference.getNetworkPreferences().values()).size();
- mSystemNetworkRequestCounter.transact(
- mDeps.getCallingUid(), uniquePreferenceCount,
- () -> {
- final ArraySet<NetworkRequestInfo> nris =
- new OemNetworkRequestFactory()
- .createNrisFromOemNetworkPreferences(preference);
- replaceDefaultNetworkRequestsForPreference(nris);
- });
- mOemNetworkPreferences = preference;
-
- if (null != listener) {
- try {
- listener.onComplete();
- } catch (RemoteException e) {
- loge("Can't send onComplete in handleSetOemNetworkPreference", e);
- }
- }
- }
-
- private void replaceDefaultNetworkRequestsForPreference(
- @NonNull final Set<NetworkRequestInfo> nris) {
- // Pass in a defensive copy as this collection will be updated on remove.
- handleRemoveNetworkRequests(new ArraySet<>(mDefaultNetworkRequests));
- addPerAppDefaultNetworkRequests(nris);
- }
-
- private void addPerAppDefaultNetworkRequests(@NonNull final Set<NetworkRequestInfo> nris) {
- ensureRunningOnConnectivityServiceThread();
- mDefaultNetworkRequests.addAll(nris);
- final ArraySet<NetworkRequestInfo> perAppCallbackRequestsToUpdate =
- getPerAppCallbackRequestsToUpdate();
- final ArraySet<NetworkRequestInfo> nrisToRegister = new ArraySet<>(nris);
- mSystemNetworkRequestCounter.transact(
- mDeps.getCallingUid(), perAppCallbackRequestsToUpdate.size(),
- () -> {
- nrisToRegister.addAll(
- createPerAppCallbackRequestsToRegister(perAppCallbackRequestsToUpdate));
- handleRemoveNetworkRequests(perAppCallbackRequestsToUpdate);
- handleRegisterNetworkRequests(nrisToRegister);
- });
- }
-
- /**
- * All current requests that are tracking the default network need to be assessed as to whether
- * or not the current set of per-application default requests will be changing their default
- * network. If so, those requests will need to be updated so that they will send callbacks for
- * default network changes at the appropriate time. Additionally, those requests tracking the
- * default that were previously updated by this flow will need to be reassessed.
- * @return the nris which will need to be updated.
- */
- private ArraySet<NetworkRequestInfo> getPerAppCallbackRequestsToUpdate() {
- final ArraySet<NetworkRequestInfo> defaultCallbackRequests = new ArraySet<>();
- // Get the distinct nris to check since for multilayer requests, it is possible to have the
- // same nri in the map's values for each of its NetworkRequest objects.
- final ArraySet<NetworkRequestInfo> nris = new ArraySet<>(mNetworkRequests.values());
- for (final NetworkRequestInfo nri : nris) {
- // Include this nri if it is currently being tracked.
- if (isPerAppTrackedNri(nri)) {
- defaultCallbackRequests.add(nri);
- continue;
- }
- // We only track callbacks for requests tracking the default.
- if (NetworkRequest.Type.TRACK_DEFAULT != nri.mRequests.get(0).type) {
- continue;
- }
- // Include this nri if it will be tracked by the new per-app default requests.
- final boolean isNriGoingToBeTracked =
- getDefaultRequestTrackingUid(nri.mAsUid) != mDefaultRequest;
- if (isNriGoingToBeTracked) {
- defaultCallbackRequests.add(nri);
- }
- }
- return defaultCallbackRequests;
- }
-
- /**
- * Create nris for those network requests that are currently tracking the default network that
- * are being controlled by a per-application default.
- * @param perAppCallbackRequestsForUpdate the baseline network requests to be used as the
- * foundation when creating the nri. Important items include the calling uid's original
- * NetworkRequest to be used when mapping callbacks as well as the caller's uid and name. These
- * requests are assumed to have already been validated as needing to be updated.
- * @return the Set of nris to use when registering network requests.
- */
- private ArraySet<NetworkRequestInfo> createPerAppCallbackRequestsToRegister(
- @NonNull final ArraySet<NetworkRequestInfo> perAppCallbackRequestsForUpdate) {
- final ArraySet<NetworkRequestInfo> callbackRequestsToRegister = new ArraySet<>();
- for (final NetworkRequestInfo callbackRequest : perAppCallbackRequestsForUpdate) {
- final NetworkRequestInfo trackingNri =
- getDefaultRequestTrackingUid(callbackRequest.mAsUid);
-
- // If this nri is not being tracked, the change it back to an untracked nri.
- if (trackingNri == mDefaultRequest) {
- callbackRequestsToRegister.add(new NetworkRequestInfo(
- callbackRequest,
- Collections.singletonList(callbackRequest.getNetworkRequestForCallback())));
- continue;
- }
-
- final NetworkRequest request = callbackRequest.mRequests.get(0);
- callbackRequestsToRegister.add(new NetworkRequestInfo(
- callbackRequest,
- copyNetworkRequestsForUid(
- trackingNri.mRequests, callbackRequest.mAsUid,
- callbackRequest.mUid, request.getRequestorPackageName())));
- }
- return callbackRequestsToRegister;
- }
-
- private static void setNetworkRequestUids(@NonNull final List<NetworkRequest> requests,
- @NonNull final Set<UidRange> uids) {
- for (final NetworkRequest req : requests) {
- req.networkCapabilities.setUids(UidRange.toIntRanges(uids));
- }
- }
-
- /**
- * Class used to generate {@link NetworkRequestInfo} based off of {@link OemNetworkPreferences}.
- */
- @VisibleForTesting
- final class OemNetworkRequestFactory {
- ArraySet<NetworkRequestInfo> createNrisFromOemNetworkPreferences(
- @NonNull final OemNetworkPreferences preference) {
- final ArraySet<NetworkRequestInfo> nris = new ArraySet<>();
- final SparseArray<Set<Integer>> uids =
- createUidsFromOemNetworkPreferences(preference);
- for (int i = 0; i < uids.size(); i++) {
- final int key = uids.keyAt(i);
- final Set<Integer> value = uids.valueAt(i);
- final NetworkRequestInfo nri = createNriFromOemNetworkPreferences(key, value);
- // No need to add an nri without any requests.
- if (0 == nri.mRequests.size()) {
- continue;
- }
- nris.add(nri);
- }
-
- return nris;
- }
-
- private SparseArray<Set<Integer>> createUidsFromOemNetworkPreferences(
- @NonNull final OemNetworkPreferences preference) {
- final SparseArray<Set<Integer>> uids = new SparseArray<>();
- final PackageManager pm = mContext.getPackageManager();
- final List<UserHandle> users =
- mContext.getSystemService(UserManager.class).getUserHandles(true);
- if (null == users || users.size() == 0) {
- if (VDBG || DDBG) {
- log("No users currently available for setting the OEM network preference.");
- }
- return uids;
- }
- for (final Map.Entry<String, Integer> entry :
- preference.getNetworkPreferences().entrySet()) {
- @OemNetworkPreferences.OemNetworkPreference final int pref = entry.getValue();
- try {
- final int uid = pm.getApplicationInfo(entry.getKey(), 0).uid;
- if (!uids.contains(pref)) {
- uids.put(pref, new ArraySet<>());
- }
- for (final UserHandle ui : users) {
- // Add the rules for all users as this policy is device wide.
- uids.get(pref).add(ui.getUid(uid));
- }
- } catch (PackageManager.NameNotFoundException e) {
- // Although this may seem like an error scenario, it is ok that uninstalled
- // packages are sent on a network preference as the system will watch for
- // package installations associated with this network preference and update
- // accordingly. This is done so as to minimize race conditions on app install.
- continue;
- }
- }
- return uids;
- }
-
- private NetworkRequestInfo createNriFromOemNetworkPreferences(
- @OemNetworkPreferences.OemNetworkPreference final int preference,
- @NonNull final Set<Integer> uids) {
- final List<NetworkRequest> requests = new ArrayList<>();
- // Requests will ultimately be evaluated by order of insertion therefore it matters.
- switch (preference) {
- case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID:
- requests.add(createUnmeteredNetworkRequest());
- requests.add(createOemPaidNetworkRequest());
- requests.add(createDefaultInternetRequestForTransport(
- TYPE_NONE, NetworkRequest.Type.TRACK_DEFAULT));
- break;
- case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK:
- requests.add(createUnmeteredNetworkRequest());
- requests.add(createOemPaidNetworkRequest());
- break;
- case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY:
- requests.add(createOemPaidNetworkRequest());
- break;
- case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY:
- requests.add(createOemPrivateNetworkRequest());
- break;
- default:
- // This should never happen.
- throw new IllegalArgumentException("createNriFromOemNetworkPreferences()"
- + " called with invalid preference of " + preference);
- }
-
- final ArraySet ranges = new ArraySet<Integer>();
- for (final int uid : uids) {
- ranges.add(new UidRange(uid, uid));
- }
- setNetworkRequestUids(requests, ranges);
- return new NetworkRequestInfo(Process.myUid(), requests);
- }
-
- private NetworkRequest createUnmeteredNetworkRequest() {
- final NetworkCapabilities netcap = createDefaultPerAppNetCap()
- .addCapability(NET_CAPABILITY_NOT_METERED)
- .addCapability(NET_CAPABILITY_VALIDATED);
- return createNetworkRequest(NetworkRequest.Type.LISTEN, netcap);
- }
-
- private NetworkRequest createOemPaidNetworkRequest() {
- // NET_CAPABILITY_OEM_PAID is a restricted capability.
- final NetworkCapabilities netcap = createDefaultPerAppNetCap()
- .addCapability(NET_CAPABILITY_OEM_PAID)
- .removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- return createNetworkRequest(NetworkRequest.Type.REQUEST, netcap);
- }
-
- private NetworkRequest createOemPrivateNetworkRequest() {
- // NET_CAPABILITY_OEM_PRIVATE is a restricted capability.
- final NetworkCapabilities netcap = createDefaultPerAppNetCap()
- .addCapability(NET_CAPABILITY_OEM_PRIVATE)
- .removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- return createNetworkRequest(NetworkRequest.Type.REQUEST, netcap);
- }
-
- private NetworkCapabilities createDefaultPerAppNetCap() {
- final NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
- return netCap;
- }
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/ConnectivityServiceInitializer.java b/packages/Connectivity/service/src/com/android/server/ConnectivityServiceInitializer.java
deleted file mode 100644
index 2465479..0000000
--- a/packages/Connectivity/service/src/com/android/server/ConnectivityServiceInitializer.java
+++ /dev/null
@@ -1,44 +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 com.android.server;
-
-import android.content.Context;
-import android.util.Log;
-
-/**
- * Connectivity service initializer for core networking. This is called by system server to create
- * a new instance of ConnectivityService.
- */
-public final class ConnectivityServiceInitializer extends SystemService {
- private static final String TAG = ConnectivityServiceInitializer.class.getSimpleName();
- private final ConnectivityService mConnectivity;
-
- public ConnectivityServiceInitializer(Context context) {
- super(context);
- // Load JNI libraries used by ConnectivityService and its dependencies
- System.loadLibrary("service-connectivity");
- // TODO: Define formal APIs to get the needed services.
- mConnectivity = new ConnectivityService(context);
- }
-
- @Override
- public void onStart() {
- Log.i(TAG, "Registering " + Context.CONNECTIVITY_SERVICE);
- publishBinderService(Context.CONNECTIVITY_SERVICE, mConnectivity,
- /* allowIsolated= */ false);
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/NetIdManager.java b/packages/Connectivity/service/src/com/android/server/NetIdManager.java
deleted file mode 100644
index 61925c8..0000000
--- a/packages/Connectivity/service/src/com/android/server/NetIdManager.java
+++ /dev/null
@@ -1,89 +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.server;
-
-import android.annotation.NonNull;
-import android.net.ConnectivityManager;
-import android.util.SparseBooleanArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * Class used to reserve and release net IDs.
- *
- * <p>Instances of this class are thread-safe.
- */
-public class NetIdManager {
- // Sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
- public static final int MIN_NET_ID = 100; // some reserved marks
- // Top IDs reserved by IpSecService
- public static final int MAX_NET_ID = ConnectivityManager.getIpSecNetIdRange().getLower() - 1;
-
- @GuardedBy("mNetIdInUse")
- private final SparseBooleanArray mNetIdInUse = new SparseBooleanArray();
-
- @GuardedBy("mNetIdInUse")
- private int mLastNetId = MIN_NET_ID - 1;
-
- private final int mMaxNetId;
-
- public NetIdManager() {
- this(MAX_NET_ID);
- }
-
- @VisibleForTesting
- NetIdManager(int maxNetId) {
- mMaxNetId = maxNetId;
- }
-
- /**
- * Get the first netId that follows the provided lastId and is available.
- */
- private int getNextAvailableNetIdLocked(
- int lastId, @NonNull SparseBooleanArray netIdInUse) {
- int netId = lastId;
- for (int i = MIN_NET_ID; i <= mMaxNetId; i++) {
- netId = netId < mMaxNetId ? netId + 1 : MIN_NET_ID;
- if (!netIdInUse.get(netId)) {
- return netId;
- }
- }
- throw new IllegalStateException("No free netIds");
- }
-
- /**
- * Reserve a new ID for a network.
- */
- public int reserveNetId() {
- synchronized (mNetIdInUse) {
- mLastNetId = getNextAvailableNetIdLocked(mLastNetId, mNetIdInUse);
- // Make sure NetID unused. http://b/16815182
- mNetIdInUse.put(mLastNetId, true);
- return mLastNetId;
- }
- }
-
- /**
- * Clear a previously reserved ID for a network.
- */
- public void releaseNetId(int id) {
- synchronized (mNetIdInUse) {
- mNetIdInUse.delete(id);
- }
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/TestNetworkService.java b/packages/Connectivity/service/src/com/android/server/TestNetworkService.java
deleted file mode 100644
index 09873f4..0000000
--- a/packages/Connectivity/service/src/com/android/server/TestNetworkService.java
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static android.net.TestNetworkManager.TEST_TAP_PREFIX;
-import static android.net.TestNetworkManager.TEST_TUN_PREFIX;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.INetd;
-import android.net.ITestNetworkManager;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.NetworkAgent;
-import android.net.NetworkAgentConfig;
-import android.net.NetworkCapabilities;
-import android.net.NetworkProvider;
-import android.net.RouteInfo;
-import android.net.TestNetworkInterface;
-import android.net.TestNetworkSpecifier;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.net.module.util.NetdUtils;
-import com.android.net.module.util.NetworkStackConstants;
-import com.android.net.module.util.PermissionUtils;
-
-import java.io.UncheckedIOException;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InterfaceAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.util.ArrayList;
-import java.util.Objects;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/** @hide */
-class TestNetworkService extends ITestNetworkManager.Stub {
- @NonNull private static final String TEST_NETWORK_LOGTAG = "TestNetworkAgent";
- @NonNull private static final String TEST_NETWORK_PROVIDER_NAME = "TestNetworkProvider";
- @NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger();
-
- @NonNull private final Context mContext;
- @NonNull private final INetd mNetd;
-
- @NonNull private final HandlerThread mHandlerThread;
- @NonNull private final Handler mHandler;
-
- @NonNull private final ConnectivityManager mCm;
- @NonNull private final NetworkProvider mNetworkProvider;
-
- // Native method stubs
- private static native int jniCreateTunTap(boolean isTun, @NonNull String iface);
-
- @VisibleForTesting
- protected TestNetworkService(@NonNull Context context) {
- mHandlerThread = new HandlerThread("TestNetworkServiceThread");
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
-
- mContext = Objects.requireNonNull(context, "missing Context");
- mNetd = Objects.requireNonNull(
- INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE)),
- "could not get netd instance");
- mCm = mContext.getSystemService(ConnectivityManager.class);
- mNetworkProvider = new NetworkProvider(mContext, mHandler.getLooper(),
- TEST_NETWORK_PROVIDER_NAME);
- final long token = Binder.clearCallingIdentity();
- try {
- mCm.registerNetworkProvider(mNetworkProvider);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /**
- * Create a TUN or TAP interface with the given interface name and link addresses
- *
- * <p>This method will return the FileDescriptor to the interface. Close it to tear down the
- * interface.
- */
- private TestNetworkInterface createInterface(boolean isTun, LinkAddress[] linkAddrs) {
- enforceTestNetworkPermissions(mContext);
-
- Objects.requireNonNull(linkAddrs, "missing linkAddrs");
-
- String ifacePrefix = isTun ? TEST_TUN_PREFIX : TEST_TAP_PREFIX;
- String iface = ifacePrefix + sTestTunIndex.getAndIncrement();
- final long token = Binder.clearCallingIdentity();
- try {
- ParcelFileDescriptor tunIntf =
- ParcelFileDescriptor.adoptFd(jniCreateTunTap(isTun, iface));
- for (LinkAddress addr : linkAddrs) {
- mNetd.interfaceAddAddress(
- iface,
- addr.getAddress().getHostAddress(),
- addr.getPrefixLength());
- }
-
- return new TestNetworkInterface(tunIntf, iface);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /**
- * Create a TUN interface with the given interface name and link addresses
- *
- * <p>This method will return the FileDescriptor to the TUN interface. Close it to tear down the
- * TUN interface.
- */
- @Override
- public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
- return createInterface(true, linkAddrs);
- }
-
- /**
- * Create a TAP interface with the given interface name
- *
- * <p>This method will return the FileDescriptor to the TAP interface. Close it to tear down the
- * TAP interface.
- */
- @Override
- public TestNetworkInterface createTapInterface() {
- return createInterface(false, new LinkAddress[0]);
- }
-
- // Tracker for TestNetworkAgents
- @GuardedBy("mTestNetworkTracker")
- @NonNull
- private final SparseArray<TestNetworkAgent> mTestNetworkTracker = new SparseArray<>();
-
- public class TestNetworkAgent extends NetworkAgent implements IBinder.DeathRecipient {
- private static final int NETWORK_SCORE = 1; // Use a low, non-zero score.
-
- private final int mUid;
-
- @GuardedBy("mBinderLock")
- @NonNull
- private IBinder mBinder;
-
- @NonNull private final Object mBinderLock = new Object();
-
- private TestNetworkAgent(
- @NonNull Context context,
- @NonNull Looper looper,
- @NonNull NetworkCapabilities nc,
- @NonNull LinkProperties lp,
- @NonNull NetworkAgentConfig config,
- int uid,
- @NonNull IBinder binder,
- @NonNull NetworkProvider np)
- throws RemoteException {
- super(context, looper, TEST_NETWORK_LOGTAG, nc, lp, NETWORK_SCORE, config, np);
- mUid = uid;
- synchronized (mBinderLock) {
- mBinder = binder; // Binder null-checks in create()
-
- try {
- mBinder.linkToDeath(this, 0);
- } catch (RemoteException e) {
- binderDied();
- throw e; // Abort, signal failure up the stack.
- }
- }
- }
-
- /**
- * If the Binder object dies, this function is called to free the resources of this
- * TestNetworkAgent
- */
- @Override
- public void binderDied() {
- teardown();
- }
-
- @Override
- protected void unwanted() {
- teardown();
- }
-
- private void teardown() {
- unregister();
-
- // Synchronize on mBinderLock to ensure that unlinkToDeath is never called more than
- // once (otherwise it could throw an exception)
- synchronized (mBinderLock) {
- // If mBinder is null, this Test Network has already been cleaned up.
- if (mBinder == null) return;
- mBinder.unlinkToDeath(this, 0);
- mBinder = null;
- }
-
- // 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(getNetwork().getNetId());
- }
- }
- }
-
- private TestNetworkAgent registerTestNetworkAgent(
- @NonNull Looper looper,
- @NonNull Context context,
- @NonNull String iface,
- @Nullable LinkProperties lp,
- boolean isMetered,
- int callingUid,
- @NonNull int[] administratorUids,
- @NonNull IBinder binder)
- throws RemoteException, SocketException {
- Objects.requireNonNull(looper, "missing Looper");
- Objects.requireNonNull(context, "missing Context");
- // iface and binder validity checked by caller
-
- // Build narrow set of NetworkCapabilities, useful only for testing
- NetworkCapabilities nc = new NetworkCapabilities();
- nc.clearAll(); // Remove default capabilities.
- nc.addTransportType(NetworkCapabilities.TRANSPORT_TEST);
- nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
- nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
- nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
- nc.setNetworkSpecifier(new TestNetworkSpecifier(iface));
- nc.setAdministratorUids(administratorUids);
- if (!isMetered) {
- nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- }
-
- // Build LinkProperties
- if (lp == null) {
- lp = new LinkProperties();
- } else {
- lp = new LinkProperties(lp);
- // Use LinkAddress(es) from the interface itself to minimize how much the caller
- // is trusted.
- lp.setLinkAddresses(new ArrayList<>());
- }
- lp.setInterfaceName(iface);
-
- // Find the currently assigned addresses, and add them to LinkProperties
- boolean allowIPv4 = false, allowIPv6 = false;
- NetworkInterface netIntf = NetworkInterface.getByName(iface);
- Objects.requireNonNull(netIntf, "No such network interface found: " + netIntf);
-
- for (InterfaceAddress intfAddr : netIntf.getInterfaceAddresses()) {
- lp.addLinkAddress(
- new LinkAddress(intfAddr.getAddress(), intfAddr.getNetworkPrefixLength()));
-
- if (intfAddr.getAddress() instanceof Inet6Address) {
- allowIPv6 |= !intfAddr.getAddress().isLinkLocalAddress();
- } else if (intfAddr.getAddress() instanceof Inet4Address) {
- allowIPv4 = true;
- }
- }
-
- // Add global routes (but as non-default, non-internet providing network)
- if (allowIPv4) {
- lp.addRoute(new RouteInfo(new IpPrefix(
- NetworkStackConstants.IPV4_ADDR_ANY, 0), null, iface));
- }
- if (allowIPv6) {
- lp.addRoute(new RouteInfo(new IpPrefix(
- NetworkStackConstants.IPV6_ADDR_ANY, 0), null, iface));
- }
-
- final TestNetworkAgent agent = new TestNetworkAgent(context, looper, nc, lp,
- new NetworkAgentConfig.Builder().build(), callingUid, binder,
- mNetworkProvider);
- agent.register();
- agent.markConnected();
- return agent;
- }
-
- /**
- * Sets up a Network with extremely limited privileges, guarded by the MANAGE_TEST_NETWORKS
- * permission.
- *
- * <p>This method provides a Network that is useful only for testing.
- */
- @Override
- public void setupTestNetwork(
- @NonNull String iface,
- @Nullable LinkProperties lp,
- boolean isMetered,
- @NonNull int[] administratorUids,
- @NonNull IBinder binder) {
- enforceTestNetworkPermissions(mContext);
-
- Objects.requireNonNull(iface, "missing Iface");
- Objects.requireNonNull(binder, "missing IBinder");
-
- if (!(iface.startsWith(INetd.IPSEC_INTERFACE_PREFIX)
- || iface.startsWith(TEST_TUN_PREFIX))) {
- throw new IllegalArgumentException(
- "Cannot create network for non ipsec, non-testtun interface");
- }
-
- try {
- final long token = Binder.clearCallingIdentity();
- try {
- PermissionUtils.enforceNetworkStackPermission(mContext);
- NetdUtils.setInterfaceUp(mNetd, iface);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
-
- // Synchronize all accesses to mTestNetworkTracker to prevent the case where:
- // 1. TestNetworkAgent successfully binds to death of binder
- // 2. Before it is added to the mTestNetworkTracker, binder dies, binderDied() is called
- // (on a different thread)
- // 3. This thread is pre-empted, put() is called after remove()
- synchronized (mTestNetworkTracker) {
- TestNetworkAgent agent =
- registerTestNetworkAgent(
- mHandler.getLooper(),
- mContext,
- iface,
- lp,
- isMetered,
- Binder.getCallingUid(),
- administratorUids,
- binder);
-
- mTestNetworkTracker.put(agent.getNetwork().getNetId(), agent);
- }
- } catch (SocketException e) {
- throw new UncheckedIOException(e);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /** Teardown a test network */
- @Override
- public void teardownTestNetwork(int netId) {
- enforceTestNetworkPermissions(mContext);
-
- final TestNetworkAgent agent;
- synchronized (mTestNetworkTracker) {
- agent = mTestNetworkTracker.get(netId);
- }
-
- if (agent == null) {
- return; // Already torn down
- } else if (agent.mUid != Binder.getCallingUid()) {
- throw new SecurityException("Attempted to modify other user's test networks");
- }
-
- // Safe to be called multiple times.
- agent.teardown();
- }
-
- private static final String PERMISSION_NAME =
- android.Manifest.permission.MANAGE_TEST_NETWORKS;
-
- public static void enforceTestNetworkPermissions(@NonNull Context context) {
- context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService");
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/AutodestructReference.java b/packages/Connectivity/service/src/com/android/server/connectivity/AutodestructReference.java
deleted file mode 100644
index 009a43e..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/AutodestructReference.java
+++ /dev/null
@@ -1,42 +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.server.connectivity;
-
-import android.annotation.NonNull;
-
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * A ref that autodestructs at the first usage of it.
- * @param <T> The type of the held object
- * @hide
- */
-public class AutodestructReference<T> {
- private final AtomicReference<T> mHeld;
- public AutodestructReference(@NonNull T obj) {
- if (null == obj) throw new NullPointerException("Autodestruct reference to null");
- mHeld = new AtomicReference<>(obj);
- }
-
- /** Get the ref and destruct it. NPE if already destructed. */
- @NonNull
- public T getAndDestroy() {
- final T obj = mHeld.getAndSet(null);
- if (null == obj) throw new NullPointerException("Already autodestructed");
- return obj;
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/DnsManager.java b/packages/Connectivity/service/src/com/android/server/connectivity/DnsManager.java
deleted file mode 100644
index 05b12ba..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/DnsManager.java
+++ /dev/null
@@ -1,494 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_MAX_SAMPLES;
-import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_MIN_SAMPLES;
-import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
-import static android.net.ConnectivitySettingsManager.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER;
-import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
-import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
-
-import android.annotation.NonNull;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.net.ConnectivityManager;
-import android.net.ConnectivitySettingsManager;
-import android.net.IDnsResolver;
-import android.net.InetAddresses;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.ResolverOptionsParcel;
-import android.net.ResolverParamsParcel;
-import android.net.Uri;
-import android.net.shared.PrivateDnsConfig;
-import android.os.Binder;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-
-import java.net.InetAddress;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
-
-/**
- * Encapsulate the management of DNS settings for networks.
- *
- * This class it NOT designed for concurrent access. Furthermore, all non-static
- * methods MUST be called from ConnectivityService's thread. However, an exceptional
- * case is getPrivateDnsConfig(Network) which is exclusively for
- * ConnectivityService#dumpNetworkDiagnostics() on a random binder thread.
- *
- * [ Private DNS ]
- * The code handling Private DNS is spread across several components, but this
- * seems like the least bad place to collect all the observations.
- *
- * Private DNS handling and updating occurs in response to several different
- * events. Each is described here with its corresponding intended handling.
- *
- * [A] Event: A new network comes up.
- * Mechanics:
- * [1] ConnectivityService gets notifications from NetworkAgents.
- * [2] in updateNetworkInfo(), the first time the NetworkAgent goes into
- * into CONNECTED state, the Private DNS configuration is retrieved,
- * programmed, and strict mode hostname resolution (if applicable) is
- * enqueued in NetworkAgent's NetworkMonitor, via a call to
- * handlePerNetworkPrivateDnsConfig().
- * [3] Re-resolution of strict mode hostnames that fail to return any
- * IP addresses happens inside NetworkMonitor; it sends itself a
- * delayed CMD_EVALUATE_PRIVATE_DNS message in a simple backoff
- * schedule.
- * [4] Successfully resolved hostnames are sent to ConnectivityService
- * inside an EVENT_PRIVATE_DNS_CONFIG_RESOLVED message. The resolved
- * IP addresses are programmed into netd via:
- *
- * updatePrivateDns() -> updateDnses()
- *
- * both of which make calls into DnsManager.
- * [5] Upon a successful hostname resolution NetworkMonitor initiates a
- * validation attempt in the form of a lookup for a one-time hostname
- * that uses Private DNS.
- *
- * [B] Event: Private DNS settings are changed.
- * Mechanics:
- * [1] ConnectivityService gets notifications from its SettingsObserver.
- * [2] handlePrivateDnsSettingsChanged() is called, which calls
- * handlePerNetworkPrivateDnsConfig() and the process proceeds
- * as if from A.3 above.
- *
- * [C] Event: An application calls ConnectivityManager#reportBadNetwork().
- * Mechanics:
- * [1] NetworkMonitor is notified and initiates a reevaluation, which
- * always bypasses Private DNS.
- * [2] Once completed, NetworkMonitor checks if strict mode is in operation
- * and if so enqueues another evaluation of Private DNS, as if from
- * step A.5 above.
- *
- * @hide
- */
-public class DnsManager {
- private static final String TAG = DnsManager.class.getSimpleName();
- private static final PrivateDnsConfig PRIVATE_DNS_OFF = new PrivateDnsConfig();
-
- /* Defaults for resolver parameters. */
- private static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800;
- private static final int DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25;
- private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
- private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
-
- /**
- * Get PrivateDnsConfig.
- */
- public static PrivateDnsConfig getPrivateDnsConfig(Context context) {
- final int mode = ConnectivitySettingsManager.getPrivateDnsMode(context);
-
- final boolean useTls = mode != PRIVATE_DNS_MODE_OFF;
-
- if (PRIVATE_DNS_MODE_PROVIDER_HOSTNAME == mode) {
- final String specifier = getStringSetting(context.getContentResolver(),
- PRIVATE_DNS_SPECIFIER);
- return new PrivateDnsConfig(specifier, null);
- }
-
- return new PrivateDnsConfig(useTls);
- }
-
- public static Uri[] getPrivateDnsSettingsUris() {
- return new Uri[]{
- Settings.Global.getUriFor(PRIVATE_DNS_DEFAULT_MODE),
- Settings.Global.getUriFor(PRIVATE_DNS_MODE),
- Settings.Global.getUriFor(PRIVATE_DNS_SPECIFIER),
- };
- }
-
- public static class PrivateDnsValidationUpdate {
- public final int netId;
- public final InetAddress ipAddress;
- public final String hostname;
- // Refer to IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_*.
- public final int validationResult;
-
- public PrivateDnsValidationUpdate(int netId, InetAddress ipAddress,
- String hostname, int validationResult) {
- this.netId = netId;
- this.ipAddress = ipAddress;
- this.hostname = hostname;
- this.validationResult = validationResult;
- }
- }
-
- private static class PrivateDnsValidationStatuses {
- enum ValidationStatus {
- IN_PROGRESS,
- FAILED,
- SUCCEEDED
- }
-
- // Validation statuses of <hostname, ipAddress> pairs for a single netId
- // Caution : not thread-safe. As mentioned in the top file comment, all
- // methods of this class must only be called on ConnectivityService's thread.
- private Map<Pair<String, InetAddress>, ValidationStatus> mValidationMap;
-
- private PrivateDnsValidationStatuses() {
- mValidationMap = new HashMap<>();
- }
-
- private boolean hasValidatedServer() {
- for (ValidationStatus status : mValidationMap.values()) {
- if (status == ValidationStatus.SUCCEEDED) {
- return true;
- }
- }
- return false;
- }
-
- private void updateTrackedDnses(String[] ipAddresses, String hostname) {
- Set<Pair<String, InetAddress>> latestDnses = new HashSet<>();
- for (String ipAddress : ipAddresses) {
- try {
- latestDnses.add(new Pair(hostname,
- InetAddresses.parseNumericAddress(ipAddress)));
- } catch (IllegalArgumentException e) {}
- }
- // Remove <hostname, ipAddress> pairs that should not be tracked.
- for (Iterator<Map.Entry<Pair<String, InetAddress>, ValidationStatus>> it =
- mValidationMap.entrySet().iterator(); it.hasNext(); ) {
- Map.Entry<Pair<String, InetAddress>, ValidationStatus> entry = it.next();
- if (!latestDnses.contains(entry.getKey())) {
- it.remove();
- }
- }
- // Add new <hostname, ipAddress> pairs that should be tracked.
- for (Pair<String, InetAddress> p : latestDnses) {
- if (!mValidationMap.containsKey(p)) {
- mValidationMap.put(p, ValidationStatus.IN_PROGRESS);
- }
- }
- }
-
- private void updateStatus(PrivateDnsValidationUpdate update) {
- Pair<String, InetAddress> p = new Pair(update.hostname,
- update.ipAddress);
- if (!mValidationMap.containsKey(p)) {
- return;
- }
- if (update.validationResult == VALIDATION_RESULT_SUCCESS) {
- mValidationMap.put(p, ValidationStatus.SUCCEEDED);
- } else if (update.validationResult == VALIDATION_RESULT_FAILURE) {
- mValidationMap.put(p, ValidationStatus.FAILED);
- } else {
- Log.e(TAG, "Unknown private dns validation operation="
- + update.validationResult);
- }
- }
-
- private LinkProperties fillInValidatedPrivateDns(LinkProperties lp) {
- lp.setValidatedPrivateDnsServers(Collections.EMPTY_LIST);
- mValidationMap.forEach((key, value) -> {
- if (value == ValidationStatus.SUCCEEDED) {
- lp.addValidatedPrivateDnsServer(key.second);
- }
- });
- return lp;
- }
- }
-
- private final Context mContext;
- private final ContentResolver mContentResolver;
- private final IDnsResolver mDnsResolver;
- private final ConcurrentHashMap<Integer, PrivateDnsConfig> mPrivateDnsMap;
- // TODO: Replace the Map with SparseArrays.
- private final Map<Integer, PrivateDnsValidationStatuses> mPrivateDnsValidationMap;
- private final Map<Integer, LinkProperties> mLinkPropertiesMap;
- private final Map<Integer, int[]> mTransportsMap;
-
- private int mSampleValidity;
- private int mSuccessThreshold;
- private int mMinSamples;
- private int mMaxSamples;
-
- public DnsManager(Context ctx, IDnsResolver dnsResolver) {
- mContext = ctx;
- mContentResolver = mContext.getContentResolver();
- mDnsResolver = dnsResolver;
- mPrivateDnsMap = new ConcurrentHashMap<>();
- mPrivateDnsValidationMap = new HashMap<>();
- mLinkPropertiesMap = new HashMap<>();
- mTransportsMap = new HashMap<>();
-
- // TODO: Create and register ContentObservers to track every setting
- // used herein, posting messages to respond to changes.
- }
-
- public PrivateDnsConfig getPrivateDnsConfig() {
- return getPrivateDnsConfig(mContext);
- }
-
- public void removeNetwork(Network network) {
- mPrivateDnsMap.remove(network.getNetId());
- mPrivateDnsValidationMap.remove(network.getNetId());
- mTransportsMap.remove(network.getNetId());
- mLinkPropertiesMap.remove(network.getNetId());
- }
-
- // This is exclusively called by ConnectivityService#dumpNetworkDiagnostics() which
- // is not on the ConnectivityService handler thread.
- public PrivateDnsConfig getPrivateDnsConfig(@NonNull Network network) {
- return mPrivateDnsMap.getOrDefault(network.getNetId(), PRIVATE_DNS_OFF);
- }
-
- public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) {
- Log.w(TAG, "updatePrivateDns(" + network + ", " + cfg + ")");
- return (cfg != null)
- ? mPrivateDnsMap.put(network.getNetId(), cfg)
- : mPrivateDnsMap.remove(network.getNetId());
- }
-
- public void updatePrivateDnsStatus(int netId, LinkProperties lp) {
- // Use the PrivateDnsConfig data pushed to this class instance
- // from ConnectivityService.
- final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId,
- PRIVATE_DNS_OFF);
-
- final boolean useTls = privateDnsCfg.useTls;
- final PrivateDnsValidationStatuses statuses =
- useTls ? mPrivateDnsValidationMap.get(netId) : null;
- final boolean validated = (null != statuses) && statuses.hasValidatedServer();
- final boolean strictMode = privateDnsCfg.inStrictMode();
- final String tlsHostname = strictMode ? privateDnsCfg.hostname : null;
- final boolean usingPrivateDns = strictMode || validated;
-
- lp.setUsePrivateDns(usingPrivateDns);
- lp.setPrivateDnsServerName(tlsHostname);
- if (usingPrivateDns && null != statuses) {
- statuses.fillInValidatedPrivateDns(lp);
- } else {
- lp.setValidatedPrivateDnsServers(Collections.EMPTY_LIST);
- }
- }
-
- public void updatePrivateDnsValidation(PrivateDnsValidationUpdate update) {
- final PrivateDnsValidationStatuses statuses = mPrivateDnsValidationMap.get(update.netId);
- if (statuses == null) return;
- statuses.updateStatus(update);
- }
-
- /**
- * When creating a new network or transport types are changed in a specific network,
- * transport types are always saved to a hashMap before update dns config.
- * When destroying network, the specific network will be removed from the hashMap.
- * The hashMap is always accessed on the same thread.
- */
- public void updateTransportsForNetwork(int netId, @NonNull int[] transportTypes) {
- mTransportsMap.put(netId, transportTypes);
- sendDnsConfigurationForNetwork(netId);
- }
-
- /**
- * When {@link LinkProperties} are changed in a specific network, they are
- * always saved to a hashMap before update dns config.
- * When destroying network, the specific network will be removed from the hashMap.
- * The hashMap is always accessed on the same thread.
- */
- public void noteDnsServersForNetwork(int netId, @NonNull LinkProperties lp) {
- mLinkPropertiesMap.put(netId, lp);
- sendDnsConfigurationForNetwork(netId);
- }
-
- /**
- * Send dns configuration parameters to resolver for a given network.
- */
- public void sendDnsConfigurationForNetwork(int netId) {
- final LinkProperties lp = mLinkPropertiesMap.get(netId);
- final int[] transportTypes = mTransportsMap.get(netId);
- if (lp == null || transportTypes == null) return;
- updateParametersSettings();
- final ResolverParamsParcel paramsParcel = new ResolverParamsParcel();
-
- // We only use the PrivateDnsConfig data pushed to this class instance
- // from ConnectivityService because it works in coordination with
- // NetworkMonitor to decide which networks need validation and runs the
- // blocking calls to resolve Private DNS strict mode hostnames.
- //
- // At this time we do not attempt to enable Private DNS on non-Internet
- // networks like IMS.
- final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId,
- PRIVATE_DNS_OFF);
- final boolean useTls = privateDnsCfg.useTls;
- final boolean strictMode = privateDnsCfg.inStrictMode();
-
- paramsParcel.netId = netId;
- paramsParcel.sampleValiditySeconds = mSampleValidity;
- paramsParcel.successThreshold = mSuccessThreshold;
- paramsParcel.minSamples = mMinSamples;
- paramsParcel.maxSamples = mMaxSamples;
- paramsParcel.servers = makeStrings(lp.getDnsServers());
- paramsParcel.domains = getDomainStrings(lp.getDomains());
- paramsParcel.tlsName = strictMode ? privateDnsCfg.hostname : "";
- paramsParcel.tlsServers =
- strictMode ? makeStrings(
- Arrays.stream(privateDnsCfg.ips)
- .filter((ip) -> lp.isReachable(ip))
- .collect(Collectors.toList()))
- : useTls ? paramsParcel.servers // Opportunistic
- : new String[0]; // Off
- paramsParcel.resolverOptions = new ResolverOptionsParcel();
- paramsParcel.transportTypes = transportTypes;
- // Prepare to track the validation status of the DNS servers in the
- // resolver config when private DNS is in opportunistic or strict mode.
- if (useTls) {
- if (!mPrivateDnsValidationMap.containsKey(netId)) {
- mPrivateDnsValidationMap.put(netId, new PrivateDnsValidationStatuses());
- }
- mPrivateDnsValidationMap.get(netId).updateTrackedDnses(paramsParcel.tlsServers,
- paramsParcel.tlsName);
- } else {
- mPrivateDnsValidationMap.remove(netId);
- }
-
- Log.d(TAG, String.format("sendDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, "
- + "%d, %d, %s, %s)", paramsParcel.netId, Arrays.toString(paramsParcel.servers),
- Arrays.toString(paramsParcel.domains), paramsParcel.sampleValiditySeconds,
- paramsParcel.successThreshold, paramsParcel.minSamples,
- paramsParcel.maxSamples, paramsParcel.baseTimeoutMsec,
- paramsParcel.retryCount, paramsParcel.tlsName,
- Arrays.toString(paramsParcel.tlsServers)));
-
- try {
- mDnsResolver.setResolverConfiguration(paramsParcel);
- } catch (RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "Error setting DNS configuration: " + e);
- return;
- }
- }
-
- /**
- * Flush DNS caches and events work before boot has completed.
- */
- public void flushVmDnsCache() {
- /*
- * Tell the VMs to toss their DNS caches
- */
- final Intent intent = new Intent(ConnectivityManager.ACTION_CLEAR_DNS_CACHE);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
- /*
- * Connectivity events can happen before boot has completed ...
- */
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- final long ident = Binder.clearCallingIdentity();
- try {
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- private void updateParametersSettings() {
- mSampleValidity = getIntSetting(
- DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
- DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
- if (mSampleValidity < 0 || mSampleValidity > 65535) {
- Log.w(TAG, "Invalid sampleValidity=" + mSampleValidity + ", using default="
- + DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
- mSampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
- }
-
- mSuccessThreshold = getIntSetting(
- DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
- DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
- if (mSuccessThreshold < 0 || mSuccessThreshold > 100) {
- Log.w(TAG, "Invalid successThreshold=" + mSuccessThreshold + ", using default="
- + DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
- mSuccessThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
- }
-
- mMinSamples = getIntSetting(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
- mMaxSamples = getIntSetting(DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
- if (mMinSamples < 0 || mMinSamples > mMaxSamples || mMaxSamples > 64) {
- Log.w(TAG, "Invalid sample count (min, max)=(" + mMinSamples + ", " + mMaxSamples
- + "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", "
- + DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
- mMinSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES;
- mMaxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES;
- }
- }
-
- private int getIntSetting(String which, int dflt) {
- return Settings.Global.getInt(mContentResolver, which, dflt);
- }
-
- /**
- * Create a string array of host addresses from a collection of InetAddresses
- *
- * @param addrs a Collection of InetAddresses
- * @return an array of Strings containing their host addresses
- */
- private String[] makeStrings(Collection<InetAddress> addrs) {
- String[] result = new String[addrs.size()];
- int i = 0;
- for (InetAddress addr : addrs) {
- result[i++] = addr.getHostAddress();
- }
- return result;
- }
-
- private static String getStringSetting(ContentResolver cr, String which) {
- return Settings.Global.getString(cr, which);
- }
-
- private static String[] getDomainStrings(String domains) {
- return (TextUtils.isEmpty(domains)) ? new String[0] : domains.split(" ");
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/FullScore.java b/packages/Connectivity/service/src/com/android/server/connectivity/FullScore.java
deleted file mode 100644
index fbfa7a1..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/FullScore.java
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkScore.KEEP_CONNECTED_NONE;
-import static android.net.NetworkScore.POLICY_EXITING;
-import static android.net.NetworkScore.POLICY_TRANSPORT_PRIMARY;
-import static android.net.NetworkScore.POLICY_YIELD_TO_BAD_WIFI;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.net.NetworkAgentConfig;
-import android.net.NetworkCapabilities;
-import android.net.NetworkScore;
-import android.net.NetworkScore.KeepConnectedReason;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.StringJoiner;
-
-/**
- * This class represents how desirable a network is.
- *
- * FullScore is very similar to NetworkScore, but it contains the bits that are managed
- * by ConnectivityService. This provides static guarantee that all users must know whether
- * they are handling a score that had the CS-managed bits set.
- */
-public class FullScore {
- // This will be removed soon. Do *NOT* depend on it for any new code that is not part of
- // a migration.
- private final int mLegacyInt;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = {"POLICY_"}, value = {
- POLICY_IS_VALIDATED,
- POLICY_IS_VPN,
- POLICY_EVER_USER_SELECTED,
- POLICY_ACCEPT_UNVALIDATED,
- POLICY_IS_UNMETERED
- })
- public @interface Policy {
- }
-
- // Agent-managed policies are in NetworkScore. They start from 1.
- // CS-managed policies, counting from 63 downward
- // This network is validated. CS-managed because the source of truth is in NetworkCapabilities.
- /** @hide */
- public static final int POLICY_IS_VALIDATED = 63;
-
- // This is a VPN and behaves as one for scoring purposes.
- /** @hide */
- public static final int POLICY_IS_VPN = 62;
-
- // This network has been selected by the user manually from settings or a 3rd party app
- // at least once. {@see NetworkAgentConfig#explicitlySelected}.
- /** @hide */
- public static final int POLICY_EVER_USER_SELECTED = 61;
-
- // The user has indicated in UI that this network should be used even if it doesn't
- // validate. {@see NetworkAgentConfig#acceptUnvalidated}.
- /** @hide */
- public static final int POLICY_ACCEPT_UNVALIDATED = 60;
-
- // This network is unmetered. {@see NetworkCapabilities.NET_CAPABILITY_NOT_METERED}.
- /** @hide */
- public static final int POLICY_IS_UNMETERED = 59;
-
- // This network is invincible. This is useful for offers until there is an API to listen
- // to requests.
- /** @hide */
- public static final int POLICY_IS_INVINCIBLE = 58;
-
- // This network has been validated at least once since it was connected, but not explicitly
- // avoided in UI.
- // TODO : remove setAvoidUnvalidated and instead disconnect the network when the user
- // chooses to move away from this network, and remove this flag.
- /** @hide */
- public static final int POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD = 57;
-
- // To help iterate when printing
- @VisibleForTesting
- static final int MIN_CS_MANAGED_POLICY = POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD;
- @VisibleForTesting
- static final int MAX_CS_MANAGED_POLICY = POLICY_IS_VALIDATED;
-
- // Mask for policies in NetworkScore. This should have all bits managed by NetworkScore set
- // and all bits managed by FullScore unset. As bits are handled from 0 up in NetworkScore and
- // from 63 down in FullScore, cut at the 32nd bit for simplicity, but change this if some day
- // there are more than 32 bits handled on either side.
- // YIELD_TO_BAD_WIFI is temporarily handled by ConnectivityService, but the factory is still
- // allowed to set it, so that it's possible to transition from handling it in CS to handling
- // it in the factory.
- private static final long EXTERNAL_POLICIES_MASK = 0x00000000FFFFFFFFL;
-
- @VisibleForTesting
- static @NonNull String policyNameOf(final int policy) {
- switch (policy) {
- case POLICY_IS_VALIDATED: return "IS_VALIDATED";
- case POLICY_IS_VPN: return "IS_VPN";
- case POLICY_EVER_USER_SELECTED: return "EVER_USER_SELECTED";
- case POLICY_ACCEPT_UNVALIDATED: return "ACCEPT_UNVALIDATED";
- case POLICY_IS_UNMETERED: return "IS_UNMETERED";
- case POLICY_YIELD_TO_BAD_WIFI: return "YIELD_TO_BAD_WIFI";
- case POLICY_TRANSPORT_PRIMARY: return "TRANSPORT_PRIMARY";
- case POLICY_EXITING: return "EXITING";
- case POLICY_IS_INVINCIBLE: return "INVINCIBLE";
- case POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD: return "EVER_VALIDATED";
- }
- throw new IllegalArgumentException("Unknown policy : " + policy);
- }
-
- // Bitmask of all the policies applied to this score.
- private final long mPolicies;
-
- private final int mKeepConnectedReason;
-
- FullScore(final int legacyInt, final long policies,
- @KeepConnectedReason final int keepConnectedReason) {
- mLegacyInt = legacyInt;
- mPolicies = policies;
- mKeepConnectedReason = keepConnectedReason;
- }
-
- /**
- * Given a score supplied by the NetworkAgent and CS-managed objects, produce a full score.
- *
- * @param score the score supplied by the agent
- * @param caps the NetworkCapabilities of the network
- * @param config the NetworkAgentConfig of the network
- * @param everValidated whether this network has ever validated
- * @param yieldToBadWiFi whether this network yields to a previously validated wifi gone bad
- * @return a FullScore that is appropriate to use for ranking.
- */
- // TODO : this shouldn't manage bad wifi avoidance – instead this should be done by the
- // telephony factory, so that it depends on the carrier. For now this is handled by
- // connectivity for backward compatibility.
- public static FullScore fromNetworkScore(@NonNull final NetworkScore score,
- @NonNull final NetworkCapabilities caps, @NonNull final NetworkAgentConfig config,
- final boolean everValidated, final boolean yieldToBadWiFi) {
- return withPolicies(score.getLegacyInt(), score.getPolicies(),
- score.getKeepConnectedReason(),
- caps.hasCapability(NET_CAPABILITY_VALIDATED),
- caps.hasTransport(TRANSPORT_VPN),
- caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- everValidated,
- config.explicitlySelected,
- config.acceptUnvalidated,
- yieldToBadWiFi,
- false /* invincible */); // only prospective scores can be invincible
- }
-
- /**
- * Given a score supplied by a NetworkProvider, produce a prospective score for an offer.
- *
- * NetworkOffers have score filters that are compared to the scores of actual networks
- * to see if they could possibly beat the current satisfier. Some things the agent can't
- * know in advance ; a good example is the validation bit – some networks will validate,
- * others won't. For comparison purposes, assume the best, so all possibly beneficial
- * networks will be brought up.
- *
- * @param score the score supplied by the agent for this offer
- * @param caps the capabilities supplied by the agent for this offer
- * @return a FullScore appropriate for comparing to actual network's scores.
- */
- public static FullScore makeProspectiveScore(@NonNull final NetworkScore score,
- @NonNull final NetworkCapabilities caps) {
- // If the network offers Internet access, it may validate.
- final boolean mayValidate = caps.hasCapability(NET_CAPABILITY_INTERNET);
- // VPN transports are known in advance.
- final boolean vpn = caps.hasTransport(TRANSPORT_VPN);
- // Prospective scores are always unmetered, because unmetered networks are stronger
- // than metered networks, and it's not known in advance whether the network is metered.
- final boolean unmetered = true;
- // If the offer may validate, then it should be considered to have validated at some point
- final boolean everValidated = mayValidate;
- // The network hasn't been chosen by the user (yet, at least).
- final boolean everUserSelected = false;
- // Don't assume the user will accept unvalidated connectivity.
- final boolean acceptUnvalidated = false;
- // Don't assume clinging to bad wifi
- final boolean yieldToBadWiFi = false;
- // A prospective score is invincible if the legacy int in the filter is over the maximum
- // score.
- final boolean invincible = score.getLegacyInt() > NetworkRanker.LEGACY_INT_MAX;
- return withPolicies(score.getLegacyInt(), score.getPolicies(), KEEP_CONNECTED_NONE,
- mayValidate, vpn, unmetered, everValidated, everUserSelected, acceptUnvalidated,
- yieldToBadWiFi, invincible);
- }
-
- /**
- * Return a new score given updated caps and config.
- *
- * @param caps the NetworkCapabilities of the network
- * @param config the NetworkAgentConfig of the network
- * @return a score with the policies from the arguments reset
- */
- // TODO : this shouldn't manage bad wifi avoidance – instead this should be done by the
- // telephony factory, so that it depends on the carrier. For now this is handled by
- // connectivity for backward compatibility.
- public FullScore mixInScore(@NonNull final NetworkCapabilities caps,
- @NonNull final NetworkAgentConfig config,
- final boolean everValidated,
- final boolean yieldToBadWifi) {
- return withPolicies(mLegacyInt, mPolicies, mKeepConnectedReason,
- caps.hasCapability(NET_CAPABILITY_VALIDATED),
- caps.hasTransport(TRANSPORT_VPN),
- caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- everValidated,
- config.explicitlySelected,
- config.acceptUnvalidated,
- yieldToBadWifi,
- false /* invincible */); // only prospective scores can be invincible
- }
-
- // TODO : this shouldn't manage bad wifi avoidance – instead this should be done by the
- // telephony factory, so that it depends on the carrier. For now this is handled by
- // connectivity for backward compatibility.
- private static FullScore withPolicies(@NonNull final int legacyInt,
- final long externalPolicies,
- @KeepConnectedReason final int keepConnectedReason,
- final boolean isValidated,
- final boolean isVpn,
- final boolean isUnmetered,
- final boolean everValidated,
- final boolean everUserSelected,
- final boolean acceptUnvalidated,
- final boolean yieldToBadWiFi,
- final boolean invincible) {
- return new FullScore(legacyInt, (externalPolicies & EXTERNAL_POLICIES_MASK)
- | (isValidated ? 1L << POLICY_IS_VALIDATED : 0)
- | (isVpn ? 1L << POLICY_IS_VPN : 0)
- | (isUnmetered ? 1L << POLICY_IS_UNMETERED : 0)
- | (everValidated ? 1L << POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD : 0)
- | (everUserSelected ? 1L << POLICY_EVER_USER_SELECTED : 0)
- | (acceptUnvalidated ? 1L << POLICY_ACCEPT_UNVALIDATED : 0)
- | (yieldToBadWiFi ? 1L << POLICY_YIELD_TO_BAD_WIFI : 0)
- | (invincible ? 1L << POLICY_IS_INVINCIBLE : 0),
- keepConnectedReason);
- }
-
- /**
- * Returns this score but validated.
- */
- public FullScore asValidated() {
- return new FullScore(mLegacyInt, mPolicies | (1L << POLICY_IS_VALIDATED),
- mKeepConnectedReason);
- }
-
- /**
- * For backward compatibility, get the legacy int.
- * This will be removed before S is published.
- */
- public int getLegacyInt() {
- return getLegacyInt(false /* pretendValidated */);
- }
-
- public int getLegacyIntAsValidated() {
- return getLegacyInt(true /* pretendValidated */);
- }
-
- // TODO : remove these two constants
- // Penalty applied to scores of Networks that have not been validated.
- private static final int UNVALIDATED_SCORE_PENALTY = 40;
-
- // Score for a network that can be used unvalidated
- private static final int ACCEPT_UNVALIDATED_NETWORK_SCORE = 100;
-
- private int getLegacyInt(boolean pretendValidated) {
- // If the user has chosen this network at least once, give it the maximum score when
- // checking to pretend it's validated, or if it doesn't need to validate because the
- // user said to use it even if it doesn't validate.
- // This ensures that networks that have been selected in UI are not torn down before the
- // user gets a chance to prefer it when a higher-scoring network (e.g., Ethernet) is
- // available.
- if (hasPolicy(POLICY_EVER_USER_SELECTED)
- && (hasPolicy(POLICY_ACCEPT_UNVALIDATED) || pretendValidated)) {
- return ACCEPT_UNVALIDATED_NETWORK_SCORE;
- }
-
- int score = mLegacyInt;
- // Except for VPNs, networks are subject to a penalty for not being validated.
- // Apply the penalty unless the network is a VPN, or it's validated or pretending to be.
- if (!hasPolicy(POLICY_IS_VALIDATED) && !pretendValidated && !hasPolicy(POLICY_IS_VPN)) {
- score -= UNVALIDATED_SCORE_PENALTY;
- }
- if (score < 0) score = 0;
- return score;
- }
-
- /**
- * @return whether this score has a particular policy.
- */
- @VisibleForTesting
- public boolean hasPolicy(final int policy) {
- return 0 != (mPolicies & (1L << policy));
- }
-
- /**
- * Returns the keep-connected reason, or KEEP_CONNECTED_NONE.
- */
- public int getKeepConnectedReason() {
- return mKeepConnectedReason;
- }
-
- // Example output :
- // Score(50 ; Policies : EVER_USER_SELECTED&IS_VALIDATED)
- @Override
- public String toString() {
- final StringJoiner sj = new StringJoiner(
- "&", // delimiter
- "Score(" + mLegacyInt + " ; KeepConnected : " + mKeepConnectedReason
- + " ; Policies : ", // prefix
- ")"); // suffix
- for (int i = NetworkScore.MIN_AGENT_MANAGED_POLICY;
- i <= NetworkScore.MAX_AGENT_MANAGED_POLICY; ++i) {
- if (hasPolicy(i)) sj.add(policyNameOf(i));
- }
- for (int i = MIN_CS_MANAGED_POLICY; i <= MAX_CS_MANAGED_POLICY; ++i) {
- if (hasPolicy(i)) sj.add(policyNameOf(i));
- }
- return sj.toString();
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/KeepaliveTracker.java b/packages/Connectivity/service/src/com/android/server/connectivity/KeepaliveTracker.java
deleted file mode 100644
index 7d922a4..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/KeepaliveTracker.java
+++ /dev/null
@@ -1,761 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.NattSocketKeepalive.NATT_PORT;
-import static android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE;
-import static android.net.SocketKeepalive.BINDER_DIED;
-import static android.net.SocketKeepalive.DATA_RECEIVED;
-import static android.net.SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES;
-import static android.net.SocketKeepalive.ERROR_INVALID_INTERVAL;
-import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
-import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK;
-import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
-import static android.net.SocketKeepalive.ERROR_NO_SUCH_SLOT;
-import static android.net.SocketKeepalive.ERROR_STOP_REASON_UNINITIALIZED;
-import static android.net.SocketKeepalive.ERROR_UNSUPPORTED;
-import static android.net.SocketKeepalive.MAX_INTERVAL_SEC;
-import static android.net.SocketKeepalive.MIN_INTERVAL_SEC;
-import static android.net.SocketKeepalive.NO_KEEPALIVE;
-import static android.net.SocketKeepalive.SUCCESS;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.net.ConnectivityResources;
-import android.net.ISocketKeepaliveCallback;
-import android.net.InetAddresses;
-import android.net.InvalidPacketException;
-import android.net.KeepalivePacketData;
-import android.net.NattKeepalivePacketData;
-import android.net.NetworkAgent;
-import android.net.SocketKeepalive.InvalidSocketException;
-import android.net.TcpKeepalivePacketData;
-import android.net.util.KeepaliveUtils;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Process;
-import android.os.RemoteException;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.connectivity.resources.R;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.net.module.util.HexDump;
-import com.android.net.module.util.IpUtils;
-
-import java.io.FileDescriptor;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-
-/**
- * Manages socket keepalive requests.
- *
- * Provides methods to stop and start keepalive requests, and keeps track of keepalives across all
- * networks. This class is tightly coupled to ConnectivityService. It is not thread-safe and its
- * handle* methods must be called only from the ConnectivityService handler thread.
- */
-public class KeepaliveTracker {
-
- private static final String TAG = "KeepaliveTracker";
- private static final boolean DBG = false;
-
- public static final String PERMISSION = android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD;
-
- /** Keeps track of keepalive requests. */
- private final HashMap <NetworkAgentInfo, HashMap<Integer, KeepaliveInfo>> mKeepalives =
- new HashMap<> ();
- private final Handler mConnectivityServiceHandler;
- @NonNull
- private final TcpKeepaliveController mTcpController;
- @NonNull
- private final Context mContext;
-
- // Supported keepalive count for each transport type, can be configured through
- // config_networkSupportedKeepaliveCount. For better error handling, use
- // {@link getSupportedKeepalivesForNetworkCapabilities} instead of direct access.
- @NonNull
- private final int[] mSupportedKeepalives;
-
- // Reserved privileged keepalive slots per transport. Caller's permission will be enforced if
- // the number of remaining keepalive slots is less than or equal to the threshold.
- private final int mReservedPrivilegedSlots;
-
- // Allowed unprivileged keepalive slots per uid. Caller's permission will be enforced if
- // the number of remaining keepalive slots is less than or equal to the threshold.
- private final int mAllowedUnprivilegedSlotsForUid;
-
- public KeepaliveTracker(Context context, Handler handler) {
- mConnectivityServiceHandler = handler;
- mTcpController = new TcpKeepaliveController(handler);
- mContext = context;
- mSupportedKeepalives = KeepaliveUtils.getSupportedKeepalives(mContext);
-
- final ConnectivityResources res = new ConnectivityResources(mContext);
- mReservedPrivilegedSlots = res.get().getInteger(
- R.integer.config_reservedPrivilegedKeepaliveSlots);
- mAllowedUnprivilegedSlotsForUid = res.get().getInteger(
- R.integer.config_allowedUnprivilegedKeepalivePerUid);
- }
-
- /**
- * Tracks information about a socket keepalive.
- *
- * All information about this keepalive is known at construction time except the slot number,
- * which is only returned when the hardware has successfully started the keepalive.
- */
- class KeepaliveInfo implements IBinder.DeathRecipient {
- // Bookkeeping data.
- private final ISocketKeepaliveCallback mCallback;
- private final int mUid;
- private final int mPid;
- private final boolean mPrivileged;
- private final NetworkAgentInfo mNai;
- private final int mType;
- private final FileDescriptor mFd;
-
- public static final int TYPE_NATT = 1;
- public static final int TYPE_TCP = 2;
-
- // Keepalive slot. A small integer that identifies this keepalive among the ones handled
- // by this network.
- private int mSlot = NO_KEEPALIVE;
-
- // Packet data.
- private final KeepalivePacketData mPacket;
- private final int mInterval;
-
- // Whether the keepalive is started or not. The initial state is NOT_STARTED.
- private static final int NOT_STARTED = 1;
- private static final int STARTING = 2;
- private static final int STARTED = 3;
- private static final int STOPPING = 4;
- private int mStartedState = NOT_STARTED;
- private int mStopReason = ERROR_STOP_REASON_UNINITIALIZED;
-
- KeepaliveInfo(@NonNull ISocketKeepaliveCallback callback,
- @NonNull NetworkAgentInfo nai,
- @NonNull KeepalivePacketData packet,
- int interval,
- int type,
- @Nullable FileDescriptor fd) throws InvalidSocketException {
- mCallback = callback;
- mPid = Binder.getCallingPid();
- mUid = Binder.getCallingUid();
- mPrivileged = (PERMISSION_GRANTED == mContext.checkPermission(PERMISSION, mPid, mUid));
-
- mNai = nai;
- mPacket = packet;
- mInterval = interval;
- mType = type;
-
- // For SocketKeepalive, a dup of fd is kept in mFd so the source port from which the
- // keepalives are sent cannot be reused by another app even if the fd gets closed by
- // the user. A null is acceptable here for backward compatibility of PacketKeepalive
- // API.
- try {
- if (fd != null) {
- mFd = Os.dup(fd);
- } else {
- Log.d(TAG, toString() + " calls with null fd");
- if (!mPrivileged) {
- throw new SecurityException(
- "null fd is not allowed for unprivileged access.");
- }
- if (mType == TYPE_TCP) {
- throw new IllegalArgumentException(
- "null fd is not allowed for tcp socket keepalives.");
- }
- mFd = null;
- }
- } catch (ErrnoException e) {
- Log.e(TAG, "Cannot dup fd: ", e);
- throw new InvalidSocketException(ERROR_INVALID_SOCKET, e);
- }
-
- try {
- mCallback.asBinder().linkToDeath(this, 0);
- } catch (RemoteException e) {
- binderDied();
- }
- }
-
- public NetworkAgentInfo getNai() {
- return mNai;
- }
-
- private String startedStateString(final int state) {
- switch (state) {
- case NOT_STARTED : return "NOT_STARTED";
- case STARTING : return "STARTING";
- case STARTED : return "STARTED";
- case STOPPING : return "STOPPING";
- }
- throw new IllegalArgumentException("Unknown state");
- }
-
- public String toString() {
- return "KeepaliveInfo ["
- + " type=" + mType
- + " network=" + mNai.network
- + " startedState=" + startedStateString(mStartedState)
- + " "
- + IpUtils.addressAndPortToString(mPacket.getSrcAddress(), mPacket.getSrcPort())
- + "->"
- + IpUtils.addressAndPortToString(mPacket.getDstAddress(), mPacket.getDstPort())
- + " interval=" + mInterval
- + " uid=" + mUid + " pid=" + mPid + " privileged=" + mPrivileged
- + " packetData=" + HexDump.toHexString(mPacket.getPacket())
- + " ]";
- }
-
- /** Called when the application process is killed. */
- public void binderDied() {
- stop(BINDER_DIED);
- }
-
- void unlinkDeathRecipient() {
- if (mCallback != null) {
- mCallback.asBinder().unlinkToDeath(this, 0);
- }
- }
-
- private int checkNetworkConnected() {
- if (!mNai.networkInfo.isConnectedOrConnecting()) {
- return ERROR_INVALID_NETWORK;
- }
- return SUCCESS;
- }
-
- private int checkSourceAddress() {
- // Check that we have the source address.
- for (InetAddress address : mNai.linkProperties.getAddresses()) {
- if (address.equals(mPacket.getSrcAddress())) {
- return SUCCESS;
- }
- }
- return ERROR_INVALID_IP_ADDRESS;
- }
-
- private int checkInterval() {
- if (mInterval < MIN_INTERVAL_SEC || mInterval > MAX_INTERVAL_SEC) {
- return ERROR_INVALID_INTERVAL;
- }
- return SUCCESS;
- }
-
- private int checkPermission() {
- final HashMap<Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(mNai);
- if (networkKeepalives == null) {
- return ERROR_INVALID_NETWORK;
- }
-
- if (mPrivileged) return SUCCESS;
-
- final int supported = KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(
- mSupportedKeepalives, mNai.networkCapabilities);
-
- int takenUnprivilegedSlots = 0;
- for (final KeepaliveInfo ki : networkKeepalives.values()) {
- if (!ki.mPrivileged) ++takenUnprivilegedSlots;
- }
- if (takenUnprivilegedSlots > supported - mReservedPrivilegedSlots) {
- return ERROR_INSUFFICIENT_RESOURCES;
- }
-
- // Count unprivileged keepalives for the same uid across networks.
- int unprivilegedCountSameUid = 0;
- for (final HashMap<Integer, KeepaliveInfo> kaForNetwork : mKeepalives.values()) {
- for (final KeepaliveInfo ki : kaForNetwork.values()) {
- if (ki.mUid == mUid) {
- unprivilegedCountSameUid++;
- }
- }
- }
- if (unprivilegedCountSameUid > mAllowedUnprivilegedSlotsForUid) {
- return ERROR_INSUFFICIENT_RESOURCES;
- }
- return SUCCESS;
- }
-
- private int checkLimit() {
- final HashMap<Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(mNai);
- if (networkKeepalives == null) {
- return ERROR_INVALID_NETWORK;
- }
- final int supported = KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(
- mSupportedKeepalives, mNai.networkCapabilities);
- if (supported == 0) return ERROR_UNSUPPORTED;
- if (networkKeepalives.size() > supported) return ERROR_INSUFFICIENT_RESOURCES;
- return SUCCESS;
- }
-
- private int isValid() {
- synchronized (mNai) {
- int error = checkInterval();
- if (error == SUCCESS) error = checkLimit();
- if (error == SUCCESS) error = checkPermission();
- if (error == SUCCESS) error = checkNetworkConnected();
- if (error == SUCCESS) error = checkSourceAddress();
- return error;
- }
- }
-
- void start(int slot) {
- mSlot = slot;
- int error = isValid();
- if (error == SUCCESS) {
- Log.d(TAG, "Starting keepalive " + mSlot + " on " + mNai.toShortString());
- switch (mType) {
- case TYPE_NATT:
- final NattKeepalivePacketData nattData = (NattKeepalivePacketData) mPacket;
- mNai.onAddNattKeepalivePacketFilter(slot, nattData);
- mNai.onStartNattSocketKeepalive(slot, mInterval, nattData);
- break;
- case TYPE_TCP:
- try {
- mTcpController.startSocketMonitor(mFd, this, mSlot);
- } catch (InvalidSocketException e) {
- handleStopKeepalive(mNai, mSlot, ERROR_INVALID_SOCKET);
- return;
- }
- final TcpKeepalivePacketData tcpData = (TcpKeepalivePacketData) mPacket;
- mNai.onAddTcpKeepalivePacketFilter(slot, tcpData);
- // TODO: check result from apf and notify of failure as needed.
- mNai.onStartTcpSocketKeepalive(slot, mInterval, tcpData);
- break;
- default:
- Log.wtf(TAG, "Starting keepalive with unknown type: " + mType);
- handleStopKeepalive(mNai, mSlot, error);
- return;
- }
- mStartedState = STARTING;
- } else {
- handleStopKeepalive(mNai, mSlot, error);
- return;
- }
- }
-
- void stop(int reason) {
- int uid = Binder.getCallingUid();
- if (uid != mUid && uid != Process.SYSTEM_UID) {
- if (DBG) {
- Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network);
- }
- }
- // Ignore the case when the network disconnects immediately after stop() has been
- // called and the keepalive code is waiting for the response from the modem. This
- // might happen when the caller listens for a lower-layer network disconnect
- // callback and stop the keepalive at that time. But the stop() races with the
- // stop() generated in ConnectivityService network disconnection code path.
- if (mStartedState == STOPPING && reason == ERROR_INVALID_NETWORK) return;
-
- // Store the reason of stopping, and report it after the keepalive is fully stopped.
- if (mStopReason != ERROR_STOP_REASON_UNINITIALIZED) {
- throw new IllegalStateException("Unexpected stop reason: " + mStopReason);
- }
- mStopReason = reason;
- Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.toShortString()
- + ": " + reason);
- switch (mStartedState) {
- case NOT_STARTED:
- // Remove the reference of the keepalive that meet error before starting,
- // e.g. invalid parameter.
- cleanupStoppedKeepalive(mNai, mSlot);
- break;
- default:
- mStartedState = STOPPING;
- switch (mType) {
- case TYPE_TCP:
- mTcpController.stopSocketMonitor(mSlot);
- // fall through
- case TYPE_NATT:
- mNai.onStopSocketKeepalive(mSlot);
- mNai.onRemoveKeepalivePacketFilter(mSlot);
- break;
- default:
- Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType);
- }
- }
-
- // Close the duplicated fd that maintains the lifecycle of socket whenever
- // keepalive is running.
- if (mFd != null) {
- try {
- Os.close(mFd);
- } catch (ErrnoException e) {
- // This should not happen since system server controls the lifecycle of fd when
- // keepalive offload is running.
- Log.wtf(TAG, "Error closing fd for keepalive " + mSlot + ": " + e);
- }
- }
- }
-
- void onFileDescriptorInitiatedStop(final int socketKeepaliveReason) {
- handleStopKeepalive(mNai, mSlot, socketKeepaliveReason);
- }
- }
-
- void notifyErrorCallback(ISocketKeepaliveCallback cb, int error) {
- if (DBG) Log.w(TAG, "Sending onError(" + error + ") callback");
- try {
- cb.onError(error);
- } catch (RemoteException e) {
- Log.w(TAG, "Discarded onError(" + error + ") callback");
- }
- }
-
- private int findFirstFreeSlot(NetworkAgentInfo nai) {
- HashMap networkKeepalives = mKeepalives.get(nai);
- if (networkKeepalives == null) {
- networkKeepalives = new HashMap<Integer, KeepaliveInfo>();
- mKeepalives.put(nai, networkKeepalives);
- }
-
- // Find the lowest-numbered free slot. Slot numbers start from 1, because that's what two
- // separate chipset implementations independently came up with.
- int slot;
- for (slot = 1; slot <= networkKeepalives.size(); slot++) {
- if (networkKeepalives.get(slot) == null) {
- return slot;
- }
- }
- return slot;
- }
-
- public void handleStartKeepalive(Message message) {
- KeepaliveInfo ki = (KeepaliveInfo) message.obj;
- NetworkAgentInfo nai = ki.getNai();
- int slot = findFirstFreeSlot(nai);
- mKeepalives.get(nai).put(slot, ki);
- ki.start(slot);
- }
-
- public void handleStopAllKeepalives(NetworkAgentInfo nai, int reason) {
- final HashMap<Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
- if (networkKeepalives != null) {
- final ArrayList<KeepaliveInfo> kalist = new ArrayList(networkKeepalives.values());
- for (KeepaliveInfo ki : kalist) {
- ki.stop(reason);
- // Clean up keepalives since the network agent is disconnected and unable to pass
- // back asynchronous result of stop().
- cleanupStoppedKeepalive(nai, ki.mSlot);
- }
- }
- }
-
- public void handleStopKeepalive(NetworkAgentInfo nai, int slot, int reason) {
- final String networkName = NetworkAgentInfo.toShortString(nai);
- HashMap <Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
- if (networkKeepalives == null) {
- Log.e(TAG, "Attempt to stop keepalive on nonexistent network " + networkName);
- return;
- }
- KeepaliveInfo ki = networkKeepalives.get(slot);
- if (ki == null) {
- Log.e(TAG, "Attempt to stop nonexistent keepalive " + slot + " on " + networkName);
- return;
- }
- ki.stop(reason);
- // Clean up keepalives will be done as a result of calling ki.stop() after the slots are
- // freed.
- }
-
- private void cleanupStoppedKeepalive(NetworkAgentInfo nai, int slot) {
- final String networkName = NetworkAgentInfo.toShortString(nai);
- HashMap<Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
- if (networkKeepalives == null) {
- Log.e(TAG, "Attempt to remove keepalive on nonexistent network " + networkName);
- return;
- }
- KeepaliveInfo ki = networkKeepalives.get(slot);
- if (ki == null) {
- Log.e(TAG, "Attempt to remove nonexistent keepalive " + slot + " on " + networkName);
- return;
- }
-
- // Remove the keepalive from hash table so the slot can be considered available when reusing
- // it.
- networkKeepalives.remove(slot);
- Log.d(TAG, "Remove keepalive " + slot + " on " + networkName + ", "
- + networkKeepalives.size() + " remains.");
- if (networkKeepalives.isEmpty()) {
- mKeepalives.remove(nai);
- }
-
- // Notify app that the keepalive is stopped.
- final int reason = ki.mStopReason;
- if (reason == SUCCESS) {
- try {
- ki.mCallback.onStopped();
- } catch (RemoteException e) {
- Log.w(TAG, "Discarded onStop callback: " + reason);
- }
- } else if (reason == DATA_RECEIVED) {
- try {
- ki.mCallback.onDataReceived();
- } catch (RemoteException e) {
- Log.w(TAG, "Discarded onDataReceived callback: " + reason);
- }
- } else if (reason == ERROR_STOP_REASON_UNINITIALIZED) {
- throw new IllegalStateException("Unexpected stop reason: " + reason);
- } else if (reason == ERROR_NO_SUCH_SLOT) {
- throw new IllegalStateException("No such slot: " + reason);
- } else {
- notifyErrorCallback(ki.mCallback, reason);
- }
-
- ki.unlinkDeathRecipient();
- }
-
- public void handleCheckKeepalivesStillValid(NetworkAgentInfo nai) {
- HashMap <Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
- if (networkKeepalives != null) {
- ArrayList<Pair<Integer, Integer>> invalidKeepalives = new ArrayList<>();
- for (int slot : networkKeepalives.keySet()) {
- int error = networkKeepalives.get(slot).isValid();
- if (error != SUCCESS) {
- invalidKeepalives.add(Pair.create(slot, error));
- }
- }
- for (Pair<Integer, Integer> slotAndError: invalidKeepalives) {
- handleStopKeepalive(nai, slotAndError.first, slotAndError.second);
- }
- }
- }
-
- /** Handle keepalive events from lower layer. */
- public void handleEventSocketKeepalive(@NonNull NetworkAgentInfo nai, int slot, int reason) {
- KeepaliveInfo ki = null;
- try {
- ki = mKeepalives.get(nai).get(slot);
- } catch(NullPointerException e) {}
- if (ki == null) {
- Log.e(TAG, "Event " + NetworkAgent.EVENT_SOCKET_KEEPALIVE + "," + slot + "," + reason
- + " for unknown keepalive " + slot + " on " + nai.toShortString());
- return;
- }
-
- // This can be called in a number of situations :
- // - startedState is STARTING.
- // - reason is SUCCESS => go to STARTED.
- // - reason isn't SUCCESS => it's an error starting. Go to NOT_STARTED and stop keepalive.
- // - startedState is STARTED.
- // - reason is SUCCESS => it's a success stopping. Go to NOT_STARTED and stop keepalive.
- // - reason isn't SUCCESS => it's an error in exec. Go to NOT_STARTED and stop keepalive.
- // The control is not supposed to ever come here if the state is NOT_STARTED. This is
- // because in NOT_STARTED state, the code will switch to STARTING before sending messages
- // to start, and the only way to NOT_STARTED is this function, through the edges outlined
- // above : in all cases, keepalive gets stopped and can't restart without going into
- // STARTING as messages are ordered. This also depends on the hardware processing the
- // messages in order.
- // TODO : clarify this code and get rid of mStartedState. Using a StateMachine is an
- // option.
- if (KeepaliveInfo.STARTING == ki.mStartedState) {
- if (SUCCESS == reason) {
- // Keepalive successfully started.
- Log.d(TAG, "Started keepalive " + slot + " on " + nai.toShortString());
- ki.mStartedState = KeepaliveInfo.STARTED;
- try {
- ki.mCallback.onStarted(slot);
- } catch (RemoteException e) {
- Log.w(TAG, "Discarded onStarted(" + slot + ") callback");
- }
- } else {
- Log.d(TAG, "Failed to start keepalive " + slot + " on " + nai.toShortString()
- + ": " + reason);
- // The message indicated some error trying to start: do call handleStopKeepalive.
- handleStopKeepalive(nai, slot, reason);
- }
- } else if (KeepaliveInfo.STOPPING == ki.mStartedState) {
- // The message indicated result of stopping : clean up keepalive slots.
- Log.d(TAG, "Stopped keepalive " + slot + " on " + nai.toShortString()
- + " stopped: " + reason);
- ki.mStartedState = KeepaliveInfo.NOT_STARTED;
- cleanupStoppedKeepalive(nai, slot);
- } else {
- Log.wtf(TAG, "Event " + NetworkAgent.EVENT_SOCKET_KEEPALIVE + "," + slot + "," + reason
- + " for keepalive in wrong state: " + ki.toString());
- }
- }
-
- /**
- * Called when requesting that keepalives be started on a IPsec NAT-T socket. See
- * {@link android.net.SocketKeepalive}.
- **/
- public void startNattKeepalive(@Nullable NetworkAgentInfo nai,
- @Nullable FileDescriptor fd,
- int intervalSeconds,
- @NonNull ISocketKeepaliveCallback cb,
- @NonNull String srcAddrString,
- int srcPort,
- @NonNull String dstAddrString,
- int dstPort) {
- if (nai == null) {
- notifyErrorCallback(cb, ERROR_INVALID_NETWORK);
- return;
- }
-
- InetAddress srcAddress, dstAddress;
- try {
- srcAddress = InetAddresses.parseNumericAddress(srcAddrString);
- dstAddress = InetAddresses.parseNumericAddress(dstAddrString);
- } catch (IllegalArgumentException e) {
- notifyErrorCallback(cb, ERROR_INVALID_IP_ADDRESS);
- return;
- }
-
- KeepalivePacketData packet;
- try {
- packet = NattKeepalivePacketData.nattKeepalivePacket(
- srcAddress, srcPort, dstAddress, NATT_PORT);
- } catch (InvalidPacketException e) {
- notifyErrorCallback(cb, e.getError());
- return;
- }
- KeepaliveInfo ki = null;
- try {
- ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds,
- KeepaliveInfo.TYPE_NATT, fd);
- } catch (InvalidSocketException | IllegalArgumentException | SecurityException e) {
- Log.e(TAG, "Fail to construct keepalive", e);
- notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
- return;
- }
- Log.d(TAG, "Created keepalive: " + ki.toString());
- mConnectivityServiceHandler.obtainMessage(
- NetworkAgent.CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget();
- }
-
- /**
- * Called by ConnectivityService to start TCP keepalive on a file descriptor.
- *
- * In order to offload keepalive for application correctly, sequence number, ack number and
- * other fields are needed to form the keepalive packet. Thus, this function synchronously
- * puts the socket into repair mode to get the necessary information. After the socket has been
- * put into repair mode, the application cannot access the socket until reverted to normal.
- *
- * See {@link android.net.SocketKeepalive}.
- **/
- public void startTcpKeepalive(@Nullable NetworkAgentInfo nai,
- @NonNull FileDescriptor fd,
- int intervalSeconds,
- @NonNull ISocketKeepaliveCallback cb) {
- if (nai == null) {
- notifyErrorCallback(cb, ERROR_INVALID_NETWORK);
- return;
- }
-
- final TcpKeepalivePacketData packet;
- try {
- packet = TcpKeepaliveController.getTcpKeepalivePacket(fd);
- } catch (InvalidSocketException e) {
- notifyErrorCallback(cb, e.error);
- return;
- } catch (InvalidPacketException e) {
- notifyErrorCallback(cb, e.getError());
- return;
- }
- KeepaliveInfo ki = null;
- try {
- ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds,
- KeepaliveInfo.TYPE_TCP, fd);
- } catch (InvalidSocketException | IllegalArgumentException | SecurityException e) {
- Log.e(TAG, "Fail to construct keepalive e=" + e);
- notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
- return;
- }
- Log.d(TAG, "Created keepalive: " + ki.toString());
- mConnectivityServiceHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget();
- }
-
- /**
- * Called when requesting that keepalives be started on a IPsec NAT-T socket. This function is
- * identical to {@link #startNattKeepalive}, but also takes a {@code resourceId}, which is the
- * resource index bound to the {@link UdpEncapsulationSocket} when creating by
- * {@link com.android.server.IpSecService} to verify whether the given
- * {@link UdpEncapsulationSocket} is legitimate.
- **/
- public void startNattKeepalive(@Nullable NetworkAgentInfo nai,
- @Nullable FileDescriptor fd,
- int resourceId,
- int intervalSeconds,
- @NonNull ISocketKeepaliveCallback cb,
- @NonNull String srcAddrString,
- @NonNull String dstAddrString,
- int dstPort) {
- // Ensure that the socket is created by IpSecService.
- if (!isNattKeepaliveSocketValid(fd, resourceId)) {
- notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
- }
-
- // Get src port to adopt old API.
- int srcPort = 0;
- try {
- final SocketAddress srcSockAddr = Os.getsockname(fd);
- srcPort = ((InetSocketAddress) srcSockAddr).getPort();
- } catch (ErrnoException e) {
- notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
- }
-
- // Forward request to old API.
- startNattKeepalive(nai, fd, intervalSeconds, cb, srcAddrString, srcPort,
- dstAddrString, dstPort);
- }
-
- /**
- * Verify if the IPsec NAT-T file descriptor and resource Id hold for IPsec keepalive is valid.
- **/
- public static boolean isNattKeepaliveSocketValid(@Nullable FileDescriptor fd, int resourceId) {
- // TODO: 1. confirm whether the fd is called from system api or created by IpSecService.
- // 2. If the fd is created from the system api, check that it's bounded. And
- // call dup to keep the fd open.
- // 3. If the fd is created from IpSecService, check if the resource ID is valid. And
- // hold the resource needed in IpSecService.
- if (null == fd) {
- return false;
- }
- return true;
- }
-
- public void dump(IndentingPrintWriter pw) {
- pw.println("Supported Socket keepalives: " + Arrays.toString(mSupportedKeepalives));
- pw.println("Reserved Privileged keepalives: " + mReservedPrivilegedSlots);
- pw.println("Allowed Unprivileged keepalives per uid: " + mAllowedUnprivilegedSlotsForUid);
- pw.println("Socket keepalives:");
- pw.increaseIndent();
- for (NetworkAgentInfo nai : mKeepalives.keySet()) {
- pw.println(nai.toShortString());
- pw.increaseIndent();
- for (int slot : mKeepalives.get(nai).keySet()) {
- KeepaliveInfo ki = mKeepalives.get(nai).get(slot);
- pw.println(slot + ": " + ki.toString());
- }
- pw.decreaseIndent();
- }
- pw.decreaseIndent();
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/LingerMonitor.java b/packages/Connectivity/service/src/com/android/server/connectivity/LingerMonitor.java
deleted file mode 100644
index 032612c..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/LingerMonitor.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.ConnectivityManager.NETID_UNSET;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.net.ConnectivityResources;
-import android.net.NetworkCapabilities;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
-
-import com.android.connectivity.resources.R;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.MessageUtils;
-import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
-
-import java.util.Arrays;
-import java.util.HashMap;
-
-/**
- * Class that monitors default network linger events and possibly notifies the user of network
- * switches.
- *
- * This class is not thread-safe and all its methods must be called on the ConnectivityService
- * handler thread.
- */
-public class LingerMonitor {
-
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
- private static final String TAG = LingerMonitor.class.getSimpleName();
-
- public static final int DEFAULT_NOTIFICATION_DAILY_LIMIT = 3;
- public static final long DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS = DateUtils.MINUTE_IN_MILLIS;
-
- private static final HashMap<String, Integer> TRANSPORT_NAMES = makeTransportToNameMap();
- @VisibleForTesting
- public static final Intent CELLULAR_SETTINGS = new Intent().setComponent(new ComponentName(
- "com.android.settings", "com.android.settings.Settings$DataUsageSummaryActivity"));
-
- @VisibleForTesting
- public static final int NOTIFY_TYPE_NONE = 0;
- public static final int NOTIFY_TYPE_NOTIFICATION = 1;
- public static final int NOTIFY_TYPE_TOAST = 2;
-
- private static SparseArray<String> sNotifyTypeNames = MessageUtils.findMessageNames(
- new Class[] { LingerMonitor.class }, new String[]{ "NOTIFY_TYPE_" });
-
- private final Context mContext;
- final Resources mResources;
- private final NetworkNotificationManager mNotifier;
- private final int mDailyLimit;
- private final long mRateLimitMillis;
-
- private long mFirstNotificationMillis;
- private long mLastNotificationMillis;
- private int mNotificationCounter;
-
- /** Current notifications. Maps the netId we switched away from to the netId we switched to. */
- private final SparseIntArray mNotifications = new SparseIntArray();
-
- /** Whether we ever notified that we switched away from a particular network. */
- private final SparseBooleanArray mEverNotified = new SparseBooleanArray();
-
- public LingerMonitor(Context context, NetworkNotificationManager notifier,
- int dailyLimit, long rateLimitMillis) {
- mContext = context;
- mResources = new ConnectivityResources(mContext).get();
- mNotifier = notifier;
- mDailyLimit = dailyLimit;
- mRateLimitMillis = rateLimitMillis;
- // Ensure that (now - mLastNotificationMillis) >= rateLimitMillis at first
- mLastNotificationMillis = -rateLimitMillis;
- }
-
- private static HashMap<String, Integer> makeTransportToNameMap() {
- SparseArray<String> numberToName = MessageUtils.findMessageNames(
- new Class[] { NetworkCapabilities.class }, new String[]{ "TRANSPORT_" });
- HashMap<String, Integer> nameToNumber = new HashMap<>();
- for (int i = 0; i < numberToName.size(); i++) {
- // MessageUtils will fail to initialize if there are duplicate constant values, so there
- // are no duplicates here.
- nameToNumber.put(numberToName.valueAt(i), numberToName.keyAt(i));
- }
- return nameToNumber;
- }
-
- private static boolean hasTransport(NetworkAgentInfo nai, int transport) {
- return nai.networkCapabilities.hasTransport(transport);
- }
-
- private int getNotificationSource(NetworkAgentInfo toNai) {
- for (int i = 0; i < mNotifications.size(); i++) {
- if (mNotifications.valueAt(i) == toNai.network.getNetId()) {
- return mNotifications.keyAt(i);
- }
- }
- return NETID_UNSET;
- }
-
- private boolean everNotified(NetworkAgentInfo nai) {
- return mEverNotified.get(nai.network.getNetId(), false);
- }
-
- @VisibleForTesting
- public boolean isNotificationEnabled(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
- // TODO: Evaluate moving to CarrierConfigManager.
- String[] notifySwitches = mResources.getStringArray(R.array.config_networkNotifySwitches);
-
- if (VDBG) {
- Log.d(TAG, "Notify on network switches: " + Arrays.toString(notifySwitches));
- }
-
- for (String notifySwitch : notifySwitches) {
- if (TextUtils.isEmpty(notifySwitch)) continue;
- String[] transports = notifySwitch.split("-", 2);
- if (transports.length != 2) {
- Log.e(TAG, "Invalid network switch notification configuration: " + notifySwitch);
- continue;
- }
- int fromTransport = TRANSPORT_NAMES.get("TRANSPORT_" + transports[0]);
- int toTransport = TRANSPORT_NAMES.get("TRANSPORT_" + transports[1]);
- if (hasTransport(fromNai, fromTransport) && hasTransport(toNai, toTransport)) {
- return true;
- }
- }
-
- return false;
- }
-
- private void showNotification(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
- mNotifier.showNotification(fromNai.network.getNetId(), NotificationType.NETWORK_SWITCH,
- fromNai, toNai, createNotificationIntent(), true);
- }
-
- @VisibleForTesting
- protected PendingIntent createNotificationIntent() {
- return PendingIntent.getActivity(
- mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
- 0 /* requestCode */,
- CELLULAR_SETTINGS,
- PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
- }
-
- // Removes any notification that was put up as a result of switching to nai.
- private void maybeStopNotifying(NetworkAgentInfo nai) {
- int fromNetId = getNotificationSource(nai);
- if (fromNetId != NETID_UNSET) {
- mNotifications.delete(fromNetId);
- mNotifier.clearNotification(fromNetId);
- // Toasts can't be deleted.
- }
- }
-
- // Notify the user of a network switch using a notification or a toast.
- private void notify(NetworkAgentInfo fromNai, NetworkAgentInfo toNai, boolean forceToast) {
- int notifyType = mResources.getInteger(R.integer.config_networkNotifySwitchType);
- if (notifyType == NOTIFY_TYPE_NOTIFICATION && forceToast) {
- notifyType = NOTIFY_TYPE_TOAST;
- }
-
- if (VDBG) {
- Log.d(TAG, "Notify type: " + sNotifyTypeNames.get(notifyType, "" + notifyType));
- }
-
- switch (notifyType) {
- case NOTIFY_TYPE_NONE:
- return;
- case NOTIFY_TYPE_NOTIFICATION:
- showNotification(fromNai, toNai);
- break;
- case NOTIFY_TYPE_TOAST:
- mNotifier.showToast(fromNai, toNai);
- break;
- default:
- Log.e(TAG, "Unknown notify type " + notifyType);
- return;
- }
-
- if (DBG) {
- Log.d(TAG, "Notifying switch from=" + fromNai.toShortString()
- + " to=" + toNai.toShortString()
- + " type=" + sNotifyTypeNames.get(notifyType, "unknown(" + notifyType + ")"));
- }
-
- mNotifications.put(fromNai.network.getNetId(), toNai.network.getNetId());
- mEverNotified.put(fromNai.network.getNetId(), true);
- }
-
- /**
- * Put up or dismiss a notification or toast for of a change in the default network if needed.
- *
- * Putting up a notification when switching from no network to some network is not supported
- * and as such this method can't be called with a null |fromNai|. It can be called with a
- * null |toNai| if there isn't a default network any more.
- *
- * @param fromNai switching from this NAI
- * @param toNai switching to this NAI
- */
- // The default network changed from fromNai to toNai due to a change in score.
- public void noteLingerDefaultNetwork(@NonNull final NetworkAgentInfo fromNai,
- @Nullable final NetworkAgentInfo toNai) {
- if (VDBG) {
- Log.d(TAG, "noteLingerDefaultNetwork from=" + fromNai.toShortString()
- + " everValidated=" + fromNai.everValidated
- + " lastValidated=" + fromNai.lastValidated
- + " to=" + toNai.toShortString());
- }
-
- // If we are currently notifying the user because the device switched to fromNai, now that
- // we are switching away from it we should remove the notification. This includes the case
- // where we switch back to toNai because its score improved again (e.g., because it regained
- // Internet access).
- maybeStopNotifying(fromNai);
-
- // If the network was simply lost (either because it disconnected or because it stopped
- // being the default with no replacement), then don't show a notification.
- if (null == toNai) return;
-
- // If this network never validated, don't notify. Otherwise, we could do things like:
- //
- // 1. Unvalidated wifi connects.
- // 2. Unvalidated mobile data connects.
- // 3. Cell validates, and we show a notification.
- // or:
- // 1. User connects to wireless printer.
- // 2. User turns on cellular data.
- // 3. We show a notification.
- if (!fromNai.everValidated) return;
-
- // If this network is a captive portal, don't notify. This cannot happen on initial connect
- // to a captive portal, because the everValidated check above will fail. However, it can
- // happen if the captive portal reasserts itself (e.g., because its timeout fires). In that
- // case, as soon as the captive portal reasserts itself, we'll show a sign-in notification.
- // We don't want to overwrite that notification with this one; the user has already been
- // notified, and of the two, the captive portal notification is the more useful one because
- // it allows the user to sign in to the captive portal. In this case, display a toast
- // in addition to the captive portal notification.
- //
- // Note that if the network we switch to is already up when the captive portal reappears,
- // this won't work because NetworkMonitor tells ConnectivityService that the network is
- // unvalidated (causing a switch) before asking it to show the sign in notification. In this
- // case, the toast won't show and we'll only display the sign in notification. This is the
- // best we can do at this time.
- boolean forceToast = fromNai.networkCapabilities.hasCapability(
- NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
-
- // Only show the notification once, in order to avoid irritating the user every time.
- // TODO: should we do this?
- if (everNotified(fromNai)) {
- if (VDBG) {
- Log.d(TAG, "Not notifying handover from " + fromNai.toShortString()
- + ", already notified");
- }
- return;
- }
-
- // Only show the notification if we switched away because a network became unvalidated, not
- // because its score changed.
- // TODO: instead of just skipping notification, keep a note of it, and show it if it becomes
- // unvalidated.
- if (fromNai.lastValidated) return;
-
- if (!isNotificationEnabled(fromNai, toNai)) return;
-
- final long now = SystemClock.elapsedRealtime();
- if (isRateLimited(now) || isAboveDailyLimit(now)) return;
-
- notify(fromNai, toNai, forceToast);
- }
-
- public void noteDisconnect(NetworkAgentInfo nai) {
- mNotifications.delete(nai.network.getNetId());
- mEverNotified.delete(nai.network.getNetId());
- maybeStopNotifying(nai);
- // No need to cancel notifications on nai: NetworkMonitor does that on disconnect.
- }
-
- private boolean isRateLimited(long now) {
- final long millisSinceLast = now - mLastNotificationMillis;
- if (millisSinceLast < mRateLimitMillis) {
- return true;
- }
- mLastNotificationMillis = now;
- return false;
- }
-
- private boolean isAboveDailyLimit(long now) {
- if (mFirstNotificationMillis == 0) {
- mFirstNotificationMillis = now;
- }
- final long millisSinceFirst = now - mFirstNotificationMillis;
- if (millisSinceFirst > DateUtils.DAY_IN_MILLIS) {
- mNotificationCounter = 0;
- mFirstNotificationMillis = 0;
- }
- if (mNotificationCounter >= mDailyLimit) {
- return true;
- }
- mNotificationCounter++;
- return false;
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/MockableSystemProperties.java b/packages/Connectivity/service/src/com/android/server/connectivity/MockableSystemProperties.java
deleted file mode 100644
index a25b89a..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/MockableSystemProperties.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import android.os.SystemProperties;
-
-public class MockableSystemProperties {
-
- public String get(String key) {
- return SystemProperties.get(key);
- }
-
- public int getInt(String key, int def) {
- return SystemProperties.getInt(key, def);
- }
-
- public boolean getBoolean(String key, boolean def) {
- return SystemProperties.getBoolean(key, def);
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/Nat464Xlat.java b/packages/Connectivity/service/src/com/android/server/connectivity/Nat464Xlat.java
deleted file mode 100644
index c66a280..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/Nat464Xlat.java
+++ /dev/null
@@ -1,523 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-
-import static com.android.net.module.util.CollectionUtils.contains;
-
-import android.annotation.NonNull;
-import android.net.ConnectivityManager;
-import android.net.IDnsResolver;
-import android.net.INetd;
-import android.net.InetAddresses;
-import android.net.InterfaceConfigurationParcel;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.NetworkInfo;
-import android.net.RouteInfo;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.net.module.util.NetworkStackConstants;
-import com.android.server.ConnectivityService;
-
-import java.net.Inet6Address;
-import java.util.Objects;
-
-/**
- * Class to manage a 464xlat CLAT daemon. Nat464Xlat is not thread safe and should be manipulated
- * from a consistent and unique thread context. It is the responsibility of ConnectivityService to
- * call into this class from its own Handler thread.
- *
- * @hide
- */
-public class Nat464Xlat {
- private static final String TAG = Nat464Xlat.class.getSimpleName();
-
- // This must match the interface prefix in clatd.c.
- private static final String CLAT_PREFIX = "v4-";
-
- // The network types on which we will start clatd,
- // allowing clat only on networks for which we can support IPv6-only.
- private static final int[] NETWORK_TYPES = {
- ConnectivityManager.TYPE_MOBILE,
- ConnectivityManager.TYPE_WIFI,
- ConnectivityManager.TYPE_ETHERNET,
- };
-
- // The network states in which running clatd is supported.
- private static final NetworkInfo.State[] NETWORK_STATES = {
- NetworkInfo.State.CONNECTED,
- NetworkInfo.State.SUSPENDED,
- };
-
- private final IDnsResolver mDnsResolver;
- private final INetd mNetd;
-
- // The network we're running on, and its type.
- private final NetworkAgentInfo mNetwork;
-
- private enum State {
- IDLE, // start() not called. Base iface and stacked iface names are null.
- DISCOVERING, // same as IDLE, except prefix discovery in progress.
- STARTING, // start() called. Base iface and stacked iface names are known.
- RUNNING, // start() called, and the stacked iface is known to be up.
- }
-
- /**
- * NAT64 prefix currently in use. Only valid in STARTING or RUNNING states.
- * Used, among other things, to avoid updates when switching from a prefix learned from one
- * source (e.g., RA) to the same prefix learned from another source (e.g., RA).
- */
- private IpPrefix mNat64PrefixInUse;
- /** NAT64 prefix (if any) discovered from DNS via RFC 7050. */
- private IpPrefix mNat64PrefixFromDns;
- /** NAT64 prefix (if any) learned from the network via RA. */
- private IpPrefix mNat64PrefixFromRa;
- private String mBaseIface;
- private String mIface;
- private Inet6Address mIPv6Address;
- private State mState = State.IDLE;
-
- private boolean mEnableClatOnCellular;
- private boolean mPrefixDiscoveryRunning;
-
- public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver,
- ConnectivityService.Dependencies deps) {
- mDnsResolver = dnsResolver;
- mNetd = netd;
- mNetwork = nai;
- mEnableClatOnCellular = deps.getCellular464XlatEnabled();
- }
-
- /**
- * Whether to attempt 464xlat on this network. This is true for an IPv6-only network that is
- * currently connected and where the NetworkAgent has not disabled 464xlat. It is the signal to
- * enable NAT64 prefix discovery.
- *
- * @param nai the NetworkAgentInfo corresponding to the network.
- * @return true if the network requires clat, false otherwise.
- */
- @VisibleForTesting
- protected boolean requiresClat(NetworkAgentInfo nai) {
- // TODO: migrate to NetworkCapabilities.TRANSPORT_*.
- final boolean supported = contains(NETWORK_TYPES, nai.networkInfo.getType());
- final boolean connected = contains(NETWORK_STATES, nai.networkInfo.getState());
-
- // Only run clat on networks that have a global IPv6 address and don't have a native IPv4
- // address.
- LinkProperties lp = nai.linkProperties;
- final boolean isIpv6OnlyNetwork = (lp != null) && lp.hasGlobalIpv6Address()
- && !lp.hasIpv4Address();
-
- // If the network tells us it doesn't use clat, respect that.
- final boolean skip464xlat = (nai.netAgentConfig() != null)
- && nai.netAgentConfig().skip464xlat;
-
- return supported && connected && isIpv6OnlyNetwork && !skip464xlat
- && (nai.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)
- ? isCellular464XlatEnabled() : true);
- }
-
- /**
- * Whether the clat demon should be started on this network now. This is true if requiresClat is
- * true and a NAT64 prefix has been discovered.
- *
- * @param nai the NetworkAgentInfo corresponding to the network.
- * @return true if the network should start clat, false otherwise.
- */
- @VisibleForTesting
- protected boolean shouldStartClat(NetworkAgentInfo nai) {
- LinkProperties lp = nai.linkProperties;
- return requiresClat(nai) && lp != null && lp.getNat64Prefix() != null;
- }
-
- /**
- * @return true if clatd has been started and has not yet stopped.
- * A true result corresponds to internal states STARTING and RUNNING.
- */
- public boolean isStarted() {
- return (mState == State.STARTING || mState == State.RUNNING);
- }
-
- /**
- * @return true if clatd has been started but the stacked interface is not yet up.
- */
- public boolean isStarting() {
- return mState == State.STARTING;
- }
-
- /**
- * @return true if clatd has been started and the stacked interface is up.
- */
- public boolean isRunning() {
- return mState == State.RUNNING;
- }
-
- /**
- * Start clatd, register this Nat464Xlat as a network observer for the stacked interface,
- * and set internal state.
- */
- private void enterStartingState(String baseIface) {
- mNat64PrefixInUse = selectNat64Prefix();
- String addrStr = null;
- try {
- addrStr = mNetd.clatdStart(baseIface, mNat64PrefixInUse.toString());
- } catch (RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "Error starting clatd on " + baseIface + ": " + e);
- }
- mIface = CLAT_PREFIX + baseIface;
- mBaseIface = baseIface;
- mState = State.STARTING;
- try {
- mIPv6Address = (Inet6Address) InetAddresses.parseNumericAddress(addrStr);
- } catch (ClassCastException | IllegalArgumentException | NullPointerException e) {
- Log.e(TAG, "Invalid IPv6 address " + addrStr);
- }
- if (mPrefixDiscoveryRunning && !isPrefixDiscoveryNeeded()) {
- stopPrefixDiscovery();
- }
- if (!mPrefixDiscoveryRunning) {
- setPrefix64(mNat64PrefixInUse);
- }
- }
-
- /**
- * Enter running state just after getting confirmation that the stacked interface is up, and
- * turn ND offload off if on WiFi.
- */
- private void enterRunningState() {
- mState = State.RUNNING;
- }
-
- /**
- * Unregister as a base observer for the stacked interface, and clear internal state.
- */
- private void leaveStartedState() {
- mNat64PrefixInUse = null;
- mIface = null;
- mBaseIface = null;
-
- if (!mPrefixDiscoveryRunning) {
- setPrefix64(null);
- }
-
- if (isPrefixDiscoveryNeeded()) {
- if (!mPrefixDiscoveryRunning) {
- startPrefixDiscovery();
- }
- mState = State.DISCOVERING;
- } else {
- stopPrefixDiscovery();
- mState = State.IDLE;
- }
- }
-
- @VisibleForTesting
- protected void start() {
- if (isStarted()) {
- Log.e(TAG, "startClat: already started");
- return;
- }
-
- String baseIface = mNetwork.linkProperties.getInterfaceName();
- if (baseIface == null) {
- Log.e(TAG, "startClat: Can't start clat on null interface");
- return;
- }
- // TODO: should we only do this if mNetd.clatdStart() succeeds?
- Log.i(TAG, "Starting clatd on " + baseIface);
- enterStartingState(baseIface);
- }
-
- @VisibleForTesting
- protected void stop() {
- if (!isStarted()) {
- Log.e(TAG, "stopClat: already stopped");
- return;
- }
-
- Log.i(TAG, "Stopping clatd on " + mBaseIface);
- try {
- mNetd.clatdStop(mBaseIface);
- } catch (RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "Error stopping clatd on " + mBaseIface + ": " + e);
- }
-
- String iface = mIface;
- boolean wasRunning = isRunning();
-
- // Change state before updating LinkProperties. handleUpdateLinkProperties ends up calling
- // fixupLinkProperties, and if at that time the state is still RUNNING, fixupLinkProperties
- // would wrongly inform ConnectivityService that there is still a stacked interface.
- leaveStartedState();
-
- if (wasRunning) {
- LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
- lp.removeStackedLink(iface);
- mNetwork.connService().handleUpdateLinkProperties(mNetwork, lp);
- }
- }
-
- private void startPrefixDiscovery() {
- try {
- mDnsResolver.startPrefix64Discovery(getNetId());
- } catch (RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "Error starting prefix discovery on netId " + getNetId() + ": " + e);
- }
- mPrefixDiscoveryRunning = true;
- }
-
- private void stopPrefixDiscovery() {
- try {
- mDnsResolver.stopPrefix64Discovery(getNetId());
- } catch (RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "Error stopping prefix discovery on netId " + getNetId() + ": " + e);
- }
- mPrefixDiscoveryRunning = false;
- }
-
- private boolean isPrefixDiscoveryNeeded() {
- // If there is no NAT64 prefix in the RA, prefix discovery is always needed. It cannot be
- // stopped after it succeeds, because stopping it will cause netd to report that the prefix
- // has been removed, and that will cause us to stop clatd.
- return requiresClat(mNetwork) && mNat64PrefixFromRa == null;
- }
-
- private void setPrefix64(IpPrefix prefix) {
- final String prefixString = (prefix != null) ? prefix.toString() : "";
- try {
- mDnsResolver.setPrefix64(getNetId(), prefixString);
- } catch (RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "Error setting NAT64 prefix on netId " + getNetId() + " to "
- + prefix + ": " + e);
- }
- }
-
- private void maybeHandleNat64PrefixChange() {
- final IpPrefix newPrefix = selectNat64Prefix();
- if (!Objects.equals(mNat64PrefixInUse, newPrefix)) {
- Log.d(TAG, "NAT64 prefix changed from " + mNat64PrefixInUse + " to "
- + newPrefix);
- stop();
- // It's safe to call update here, even though this method is called from update, because
- // stop() is guaranteed to have moved out of STARTING and RUNNING, which are the only
- // states in which this method can be called.
- update();
- }
- }
-
- /**
- * Starts/stops NAT64 prefix discovery and clatd as necessary.
- */
- public void update() {
- // TODO: turn this class into a proper StateMachine. http://b/126113090
- switch (mState) {
- case IDLE:
- if (isPrefixDiscoveryNeeded()) {
- startPrefixDiscovery(); // Enters DISCOVERING state.
- mState = State.DISCOVERING;
- } else if (requiresClat(mNetwork)) {
- start(); // Enters STARTING state.
- }
- break;
-
- case DISCOVERING:
- if (shouldStartClat(mNetwork)) {
- // NAT64 prefix detected. Start clatd.
- start(); // Enters STARTING state.
- return;
- }
- if (!requiresClat(mNetwork)) {
- // IPv4 address added. Go back to IDLE state.
- stopPrefixDiscovery();
- mState = State.IDLE;
- return;
- }
- break;
-
- case STARTING:
- case RUNNING:
- // NAT64 prefix removed, or IPv4 address added.
- // Stop clatd and go back into DISCOVERING or idle.
- if (!shouldStartClat(mNetwork)) {
- stop();
- break;
- }
- // Only necessary while clat is actually started.
- maybeHandleNat64PrefixChange();
- break;
- }
- }
-
- /**
- * Picks a NAT64 prefix to use. Always prefers the prefix from the RA if one is received from
- * both RA and DNS, because the prefix in the RA has better security and updatability, and will
- * almost always be received first anyway.
- *
- * Any network that supports legacy hosts will support discovering the DNS64 prefix via DNS as
- * well. If the prefix from the RA is withdrawn, fall back to that for reliability purposes.
- */
- private IpPrefix selectNat64Prefix() {
- return mNat64PrefixFromRa != null ? mNat64PrefixFromRa : mNat64PrefixFromDns;
- }
-
- public void setNat64PrefixFromRa(IpPrefix prefix) {
- mNat64PrefixFromRa = prefix;
- }
-
- public void setNat64PrefixFromDns(IpPrefix prefix) {
- mNat64PrefixFromDns = prefix;
- }
-
- /**
- * Copies the stacked clat link in oldLp, if any, to the passed LinkProperties.
- * This is necessary because the LinkProperties in mNetwork come from the transport layer, which
- * has no idea that 464xlat is running on top of it.
- */
- public void fixupLinkProperties(@NonNull LinkProperties oldLp, @NonNull LinkProperties lp) {
- // This must be done even if clatd is not running, because otherwise shouldStartClat would
- // never return true.
- lp.setNat64Prefix(selectNat64Prefix());
-
- if (!isRunning()) {
- return;
- }
- if (lp.getAllInterfaceNames().contains(mIface)) {
- return;
- }
-
- Log.d(TAG, "clatd running, updating NAI for " + mIface);
- for (LinkProperties stacked: oldLp.getStackedLinks()) {
- if (Objects.equals(mIface, stacked.getInterfaceName())) {
- lp.addStackedLink(stacked);
- return;
- }
- }
- }
-
- private LinkProperties makeLinkProperties(LinkAddress clatAddress) {
- LinkProperties stacked = new LinkProperties();
- stacked.setInterfaceName(mIface);
-
- // Although the clat interface is a point-to-point tunnel, we don't
- // point the route directly at the interface because some apps don't
- // understand routes without gateways (see, e.g., http://b/9597256
- // http://b/9597516). Instead, set the next hop of the route to the
- // clat IPv4 address itself (for those apps, it doesn't matter what
- // the IP of the gateway is, only that there is one).
- RouteInfo ipv4Default = new RouteInfo(
- new LinkAddress(NetworkStackConstants.IPV4_ADDR_ANY, 0),
- clatAddress.getAddress(), mIface);
- stacked.addRoute(ipv4Default);
- stacked.addLinkAddress(clatAddress);
- return stacked;
- }
-
- private LinkAddress getLinkAddress(String iface) {
- try {
- final InterfaceConfigurationParcel config = mNetd.interfaceGetCfg(iface);
- return new LinkAddress(
- InetAddresses.parseNumericAddress(config.ipv4Addr), config.prefixLength);
- } catch (IllegalArgumentException | RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "Error getting link properties: " + e);
- return null;
- }
- }
-
- /**
- * Adds stacked link on base link and transitions to RUNNING state.
- */
- private void handleInterfaceLinkStateChanged(String iface, boolean up) {
- // TODO: if we call start(), then stop(), then start() again, and the
- // interfaceLinkStateChanged notification for the first start is delayed past the first
- // stop, then the code becomes out of sync with system state and will behave incorrectly.
- //
- // This is not trivial to fix because:
- // 1. It is not guaranteed that start() will eventually result in the interface coming up,
- // because there could be an error starting clat (e.g., if the interface goes down before
- // the packet socket can be bound).
- // 2. If start is called multiple times, there is nothing in the interfaceLinkStateChanged
- // notification that says which start() call the interface was created by.
- //
- // Once this code is converted to StateMachine, it will be possible to use deferMessage to
- // ensure it stays in STARTING state until the interfaceLinkStateChanged notification fires,
- // and possibly use a timeout (or provide some guarantees at the lower layer) to address #1.
- if (!isStarting() || !up || !Objects.equals(mIface, iface)) {
- return;
- }
-
- LinkAddress clatAddress = getLinkAddress(iface);
- if (clatAddress == null) {
- Log.e(TAG, "clatAddress was null for stacked iface " + iface);
- return;
- }
-
- Log.i(TAG, String.format("interface %s is up, adding stacked link %s on top of %s",
- mIface, mIface, mBaseIface));
- enterRunningState();
- LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
- lp.addStackedLink(makeLinkProperties(clatAddress));
- mNetwork.connService().handleUpdateLinkProperties(mNetwork, lp);
- }
-
- /**
- * Removes stacked link on base link and transitions to IDLE state.
- */
- private void handleInterfaceRemoved(String iface) {
- if (!Objects.equals(mIface, iface)) {
- return;
- }
- if (!isRunning()) {
- return;
- }
-
- Log.i(TAG, "interface " + iface + " removed");
- // If we're running, and the interface was removed, then we didn't call stop(), and it's
- // likely that clatd crashed. Ensure we call stop() so we can start clatd again. Calling
- // stop() will also update LinkProperties, and if clatd crashed, the LinkProperties update
- // will cause ConnectivityService to call start() again.
- stop();
- }
-
- public void interfaceLinkStateChanged(String iface, boolean up) {
- mNetwork.handler().post(() -> { handleInterfaceLinkStateChanged(iface, up); });
- }
-
- public void interfaceRemoved(String iface) {
- mNetwork.handler().post(() -> handleInterfaceRemoved(iface));
- }
-
- @Override
- public String toString() {
- return "mBaseIface: " + mBaseIface + ", mIface: " + mIface + ", mState: " + mState;
- }
-
- @VisibleForTesting
- protected int getNetId() {
- return mNetwork.network.getNetId();
- }
-
- @VisibleForTesting
- protected boolean isCellular464XlatEnabled() {
- return mEnableClatOnCellular;
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkAgentInfo.java
deleted file mode 100644
index 18becd4..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/NetworkAgentInfo.java
+++ /dev/null
@@ -1,1215 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.transportNamesOf;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.net.CaptivePortalData;
-import android.net.IDnsResolver;
-import android.net.INetd;
-import android.net.INetworkAgent;
-import android.net.INetworkAgentRegistry;
-import android.net.INetworkMonitor;
-import android.net.LinkProperties;
-import android.net.NattKeepalivePacketData;
-import android.net.Network;
-import android.net.NetworkAgent;
-import android.net.NetworkAgentConfig;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkMonitorManager;
-import android.net.NetworkRequest;
-import android.net.NetworkScore;
-import android.net.NetworkStateSnapshot;
-import android.net.QosCallbackException;
-import android.net.QosFilter;
-import android.net.QosFilterParcelable;
-import android.net.QosSession;
-import android.net.TcpKeepalivePacketData;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.telephony.data.EpsBearerQosSessionAttributes;
-import android.telephony.data.NrQosSessionAttributes;
-import android.util.Log;
-import android.util.Pair;
-import android.util.SparseArray;
-
-import com.android.internal.util.WakeupMessage;
-import com.android.server.ConnectivityService;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Objects;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-/**
- * A bag class used by ConnectivityService for holding a collection of most recent
- * information published by a particular NetworkAgent as well as the
- * AsyncChannel/messenger for reaching that NetworkAgent and lists of NetworkRequests
- * interested in using it. Default sort order is descending by score.
- */
-// States of a network:
-// --------------------
-// 1. registered, uncreated, disconnected, unvalidated
-// This state is entered when a NetworkFactory registers a NetworkAgent in any state except
-// the CONNECTED state.
-// 2. registered, uncreated, connecting, unvalidated
-// This state is entered when a registered NetworkAgent for a VPN network transitions to the
-// CONNECTING state (TODO: go through this state for every network, not just VPNs).
-// ConnectivityService will tell netd to create the network early in order to add extra UID
-// routing rules referencing the netID. These rules need to be in place before the network is
-// connected to avoid racing against client apps trying to connect to a half-setup network.
-// 3. registered, uncreated, connected, unvalidated
-// This state is entered when a registered NetworkAgent transitions to the CONNECTED state.
-// ConnectivityService will tell netd to create the network if it was not already created, and
-// immediately transition to state #4.
-// 4. registered, created, connected, unvalidated
-// If this network can satisfy the default NetworkRequest, then NetworkMonitor will
-// probe for Internet connectivity.
-// If this network cannot satisfy the default NetworkRequest, it will immediately be
-// transitioned to state #5.
-// A network may remain in this state if NetworkMonitor fails to find Internet connectivity,
-// for example:
-// a. a captive portal is present, or
-// b. a WiFi router whose Internet backhaul is down, or
-// c. a wireless connection stops transfering packets temporarily (e.g. device is in elevator
-// or tunnel) but does not disconnect from the AP/cell tower, or
-// d. a stand-alone device offering a WiFi AP without an uplink for configuration purposes.
-// 5. registered, created, connected, validated
-//
-// The device's default network connection:
-// ----------------------------------------
-// Networks in states #4 and #5 may be used as a device's default network connection if they
-// satisfy the default NetworkRequest.
-// A network, that satisfies the default NetworkRequest, in state #5 should always be chosen
-// in favor of a network, that satisfies the default NetworkRequest, in state #4.
-// When deciding between two networks, that both satisfy the default NetworkRequest, to select
-// for the default network connection, the one with the higher score should be chosen.
-//
-// When a network disconnects:
-// ---------------------------
-// If a network's transport disappears, for example:
-// a. WiFi turned off, or
-// b. cellular data turned off, or
-// c. airplane mode is turned on, or
-// d. a wireless connection disconnects from AP/cell tower entirely (e.g. device is out of range
-// of AP for an extended period of time, or switches to another AP without roaming)
-// then that network can transition from any state (#1-#5) to unregistered. This happens by
-// the transport disconnecting their NetworkAgent's AsyncChannel with ConnectivityManager.
-// ConnectivityService also tells netd to destroy the network.
-//
-// When ConnectivityService disconnects a network:
-// -----------------------------------------------
-// If a network is just connected, ConnectivityService will think it will be used soon, but might
-// not be used. Thus, a 5s timer will be held to prevent the network being torn down immediately.
-// This "nascent" state is implemented by the "lingering" logic below without relating to any
-// request, and is used in some cases where network requests race with network establishment. The
-// nascent state ends when the 5-second timer fires, or as soon as the network satisfies a
-// request, whichever is earlier. In this state, the network is considered in the background.
-//
-// If a network has no chance of satisfying any requests (even if it were to become validated
-// and enter state #5), ConnectivityService will disconnect the NetworkAgent's AsyncChannel.
-//
-// If the network was satisfying a foreground NetworkRequest (i.e. had been the highest scoring that
-// satisfied the NetworkRequest's constraints), but is no longer the highest scoring network for any
-// foreground NetworkRequest, then there will be a 30s pause to allow network communication to be
-// wrapped up rather than abruptly terminated. During this pause the network is said to be
-// "lingering". During this pause if the network begins satisfying a foreground NetworkRequest,
-// ConnectivityService will cancel the future disconnection of the NetworkAgent's AsyncChannel, and
-// the network is no longer considered "lingering". After the linger timer expires, if the network
-// is satisfying one or more background NetworkRequests it is kept up in the background. If it is
-// not, ConnectivityService disconnects the NetworkAgent's AsyncChannel.
-public class NetworkAgentInfo implements Comparable<NetworkAgentInfo>, NetworkRanker.Scoreable {
-
- @NonNull public NetworkInfo networkInfo;
- // This Network object should always be used if possible, so as to encourage reuse of the
- // enclosed socket factory and connection pool. Avoid creating other Network objects.
- // This Network object is always valid.
- @NonNull public final Network network;
- @NonNull public LinkProperties linkProperties;
- // This should only be modified by ConnectivityService, via setNetworkCapabilities().
- // TODO: make this private with a getter.
- @NonNull public NetworkCapabilities networkCapabilities;
- @NonNull public final NetworkAgentConfig networkAgentConfig;
-
- // Underlying networks declared by the agent. Only set if supportsUnderlyingNetworks is true.
- // The networks in this list might be declared by a VPN app using setUnderlyingNetworks and are
- // not guaranteed to be current or correct, or even to exist.
- //
- // This array is read and iterated on multiple threads with no locking so its contents must
- // never be modified. When the list of networks changes, replace with a new array, on the
- // handler thread.
- public @Nullable volatile Network[] declaredUnderlyingNetworks;
-
- // The capabilities originally announced by the NetworkAgent, regardless of any capabilities
- // that were added or removed due to this network's underlying networks.
- // Only set if #supportsUnderlyingNetworks is true.
- public @Nullable NetworkCapabilities declaredCapabilities;
-
- // Indicates if netd has been told to create this Network. From this point on the appropriate
- // routing rules are setup and routes are added so packets can begin flowing over the Network.
- // This is a sticky bit; once set it is never cleared.
- public boolean created;
- // Set to true after the first time this network is marked as CONNECTED. Once set, the network
- // shows up in API calls, is able to satisfy NetworkRequests and can become the default network.
- // This is a sticky bit; once set it is never cleared.
- public boolean everConnected;
- // Set to true if this Network successfully passed validation or if it did not satisfy the
- // default NetworkRequest in which case validation will not be attempted.
- // This is a sticky bit; once set it is never cleared even if future validation attempts fail.
- public boolean everValidated;
-
- // The result of the last validation attempt on this network (true if validated, false if not).
- public boolean lastValidated;
-
- // If true, becoming unvalidated will lower the network's score. This is only meaningful if the
- // system is configured not to do this for certain networks, e.g., if the
- // config_networkAvoidBadWifi option is set to 0 and the user has not overridden that via
- // Settings.Global.NETWORK_AVOID_BAD_WIFI.
- public boolean avoidUnvalidated;
-
- // Whether a captive portal was ever detected on this network.
- // This is a sticky bit; once set it is never cleared.
- public boolean everCaptivePortalDetected;
-
- // Whether a captive portal was found during the last network validation attempt.
- public boolean lastCaptivePortalDetected;
-
- // Set to true when partial connectivity was detected.
- public boolean partialConnectivity;
-
- // Delay between when the network is disconnected and when the native network is destroyed.
- public int teardownDelayMs;
-
- // Captive portal info of the network from RFC8908, if any.
- // Obtained by ConnectivityService and merged into NetworkAgent-provided information.
- public CaptivePortalData capportApiData;
-
- // The UID of the remote entity that created this Network.
- public final int creatorUid;
-
- // Network agent portal info of the network, if any. This information is provided from
- // non-RFC8908 sources, such as Wi-Fi Passpoint, which can provide information such as Venue
- // URL, Terms & Conditions URL, and network friendly name.
- public CaptivePortalData networkAgentPortalData;
-
- // Networks are lingered when they become unneeded as a result of their NetworkRequests being
- // satisfied by a higher-scoring network. so as to allow communication to wrap up before the
- // network is taken down. This usually only happens to the default network. Lingering ends with
- // either the linger timeout expiring and the network being taken down, or the network
- // satisfying a request again.
- public static class InactivityTimer implements Comparable<InactivityTimer> {
- public final int requestId;
- public final long expiryMs;
-
- public InactivityTimer(int requestId, long expiryMs) {
- this.requestId = requestId;
- this.expiryMs = expiryMs;
- }
- public boolean equals(Object o) {
- if (!(o instanceof InactivityTimer)) return false;
- InactivityTimer other = (InactivityTimer) o;
- return (requestId == other.requestId) && (expiryMs == other.expiryMs);
- }
- public int hashCode() {
- return Objects.hash(requestId, expiryMs);
- }
- public int compareTo(InactivityTimer other) {
- return (expiryMs != other.expiryMs) ?
- Long.compare(expiryMs, other.expiryMs) :
- Integer.compare(requestId, other.requestId);
- }
- public String toString() {
- return String.format("%s, expires %dms", requestId,
- expiryMs - SystemClock.elapsedRealtime());
- }
- }
-
- /**
- * Inform ConnectivityService that the network LINGER period has
- * expired.
- * obj = this NetworkAgentInfo
- */
- public static final int EVENT_NETWORK_LINGER_COMPLETE = 1001;
-
- /**
- * Inform ConnectivityService that the agent is half-connected.
- * arg1 = ARG_AGENT_SUCCESS or ARG_AGENT_FAILURE
- * obj = NetworkAgentInfo
- * @hide
- */
- public static final int EVENT_AGENT_REGISTERED = 1002;
-
- /**
- * Inform ConnectivityService that the agent was disconnected.
- * obj = NetworkAgentInfo
- * @hide
- */
- public static final int EVENT_AGENT_DISCONNECTED = 1003;
-
- /**
- * Argument for EVENT_AGENT_HALF_CONNECTED indicating failure.
- */
- public static final int ARG_AGENT_FAILURE = 0;
-
- /**
- * Argument for EVENT_AGENT_HALF_CONNECTED indicating success.
- */
- public static final int ARG_AGENT_SUCCESS = 1;
-
- // How long this network should linger for.
- private int mLingerDurationMs;
-
- // All inactivity timers for this network, sorted by expiry time. A timer is added whenever
- // a request is moved to a network with a better score, regardless of whether the network is or
- // was lingering or not. An inactivity timer is also added when a network connects
- // without immediately satisfying any requests.
- // TODO: determine if we can replace this with a smaller or unsorted data structure. (e.g.,
- // SparseLongArray) combined with the timestamp of when the last timer is scheduled to fire.
- private final SortedSet<InactivityTimer> mInactivityTimers = new TreeSet<>();
-
- // For fast lookups. Indexes into mInactivityTimers by request ID.
- private final SparseArray<InactivityTimer> mInactivityTimerForRequest = new SparseArray<>();
-
- // Inactivity expiry timer. Armed whenever mInactivityTimers is non-empty, regardless of
- // whether the network is inactive or not. Always set to the expiry of the mInactivityTimers
- // that expires last. When the timer fires, all inactivity state is cleared, and if the network
- // has no requests, it is torn down.
- private WakeupMessage mInactivityMessage;
-
- // Inactivity expiry. Holds the expiry time of the inactivity timer, or 0 if the timer is not
- // armed.
- private long mInactivityExpiryMs;
-
- // Whether the network is inactive or not. Must be maintained separately from the above because
- // it depends on the state of other networks and requests, which only ConnectivityService knows.
- // (Example: we don't linger a network if it would become the best for a NetworkRequest if it
- // validated).
- private boolean mInactive;
-
- // This represents the quality of the network. As opposed to NetworkScore, FullScore includes
- // the ConnectivityService-managed bits.
- private FullScore mScore;
-
- // The list of NetworkRequests being satisfied by this Network.
- private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
-
- // How many of the satisfied requests are actual requests and not listens.
- private int mNumRequestNetworkRequests = 0;
-
- // How many of the satisfied requests are of type BACKGROUND_REQUEST.
- private int mNumBackgroundNetworkRequests = 0;
-
- // The last ConnectivityReport made available for this network. This value is only null before a
- // report is generated. Once non-null, it will never be null again.
- @Nullable private ConnectivityReport mConnectivityReport;
-
- public final INetworkAgent networkAgent;
- // Only accessed from ConnectivityService handler thread
- private final AgentDeathMonitor mDeathMonitor = new AgentDeathMonitor();
-
- public final int factorySerialNumber;
-
- // Used by ConnectivityService to keep track of 464xlat.
- public final Nat464Xlat clatd;
-
- // Set after asynchronous creation of the NetworkMonitor.
- private volatile NetworkMonitorManager mNetworkMonitor;
-
- private static final String TAG = ConnectivityService.class.getSimpleName();
- private static final boolean VDBG = false;
- private final ConnectivityService mConnService;
- private final Context mContext;
- private final Handler mHandler;
- private final QosCallbackTracker mQosCallbackTracker;
-
- public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info,
- @NonNull LinkProperties lp, @NonNull NetworkCapabilities nc,
- @NonNull NetworkScore score, Context context,
- Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
- IDnsResolver dnsResolver, int factorySerialNumber, int creatorUid,
- int lingerDurationMs, QosCallbackTracker qosCallbackTracker,
- ConnectivityService.Dependencies deps) {
- Objects.requireNonNull(net);
- Objects.requireNonNull(info);
- Objects.requireNonNull(lp);
- Objects.requireNonNull(nc);
- Objects.requireNonNull(context);
- Objects.requireNonNull(config);
- Objects.requireNonNull(qosCallbackTracker);
- networkAgent = na;
- network = net;
- networkInfo = info;
- linkProperties = lp;
- networkCapabilities = nc;
- networkAgentConfig = config;
- mConnService = connService;
- setScore(score); // uses members connService, networkCapabilities and networkAgentConfig
- clatd = new Nat464Xlat(this, netd, dnsResolver, deps);
- mContext = context;
- mHandler = handler;
- this.factorySerialNumber = factorySerialNumber;
- this.creatorUid = creatorUid;
- mLingerDurationMs = lingerDurationMs;
- mQosCallbackTracker = qosCallbackTracker;
- }
-
- private class AgentDeathMonitor implements IBinder.DeathRecipient {
- @Override
- public void binderDied() {
- notifyDisconnected();
- }
- }
-
- /**
- * Notify the NetworkAgent that it was registered, and should be unregistered if it dies.
- *
- * Must be called from the ConnectivityService handler thread. A NetworkAgent can only be
- * registered once.
- */
- public void notifyRegistered() {
- try {
- networkAgent.asBinder().linkToDeath(mDeathMonitor, 0);
- networkAgent.onRegistered(new NetworkAgentMessageHandler(mHandler));
- } catch (RemoteException e) {
- Log.e(TAG, "Error registering NetworkAgent", e);
- maybeUnlinkDeathMonitor();
- mHandler.obtainMessage(EVENT_AGENT_REGISTERED, ARG_AGENT_FAILURE, 0, this)
- .sendToTarget();
- return;
- }
-
- mHandler.obtainMessage(EVENT_AGENT_REGISTERED, ARG_AGENT_SUCCESS, 0, this).sendToTarget();
- }
-
- /**
- * Disconnect the NetworkAgent. Must be called from the ConnectivityService handler thread.
- */
- public void disconnect() {
- try {
- networkAgent.onDisconnected();
- } catch (RemoteException e) {
- Log.i(TAG, "Error disconnecting NetworkAgent", e);
- // Fall through: it's fine if the remote has died
- }
-
- notifyDisconnected();
- maybeUnlinkDeathMonitor();
- }
-
- private void maybeUnlinkDeathMonitor() {
- try {
- networkAgent.asBinder().unlinkToDeath(mDeathMonitor, 0);
- } catch (NoSuchElementException e) {
- // Was not linked: ignore
- }
- }
-
- private void notifyDisconnected() {
- // Note this may be called multiple times if ConnectivityService disconnects while the
- // NetworkAgent also dies. ConnectivityService ignores disconnects of already disconnected
- // agents.
- mHandler.obtainMessage(EVENT_AGENT_DISCONNECTED, this).sendToTarget();
- }
-
- /**
- * Notify the NetworkAgent that bandwidth update was requested.
- */
- public void onBandwidthUpdateRequested() {
- try {
- networkAgent.onBandwidthUpdateRequested();
- } catch (RemoteException e) {
- Log.e(TAG, "Error sending bandwidth update request event", e);
- }
- }
-
- /**
- * Notify the NetworkAgent that validation status has changed.
- */
- public void onValidationStatusChanged(int validationStatus, @Nullable String captivePortalUrl) {
- try {
- networkAgent.onValidationStatusChanged(validationStatus, captivePortalUrl);
- } catch (RemoteException e) {
- Log.e(TAG, "Error sending validation status change event", e);
- }
- }
-
- /**
- * Notify the NetworkAgent that the acceptUnvalidated setting should be saved.
- */
- public void onSaveAcceptUnvalidated(boolean acceptUnvalidated) {
- try {
- networkAgent.onSaveAcceptUnvalidated(acceptUnvalidated);
- } catch (RemoteException e) {
- Log.e(TAG, "Error sending accept unvalidated event", e);
- }
- }
-
- /**
- * Notify the NetworkAgent that NATT socket keepalive should be started.
- */
- public void onStartNattSocketKeepalive(int slot, int intervalDurationMs,
- @NonNull NattKeepalivePacketData packetData) {
- try {
- networkAgent.onStartNattSocketKeepalive(slot, intervalDurationMs, packetData);
- } catch (RemoteException e) {
- Log.e(TAG, "Error sending NATT socket keepalive start event", e);
- }
- }
-
- /**
- * Notify the NetworkAgent that TCP socket keepalive should be started.
- */
- public void onStartTcpSocketKeepalive(int slot, int intervalDurationMs,
- @NonNull TcpKeepalivePacketData packetData) {
- try {
- networkAgent.onStartTcpSocketKeepalive(slot, intervalDurationMs, packetData);
- } catch (RemoteException e) {
- Log.e(TAG, "Error sending TCP socket keepalive start event", e);
- }
- }
-
- /**
- * Notify the NetworkAgent that socket keepalive should be stopped.
- */
- public void onStopSocketKeepalive(int slot) {
- try {
- networkAgent.onStopSocketKeepalive(slot);
- } catch (RemoteException e) {
- Log.e(TAG, "Error sending TCP socket keepalive stop event", e);
- }
- }
-
- /**
- * Notify the NetworkAgent that signal strength thresholds should be updated.
- */
- public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) {
- try {
- networkAgent.onSignalStrengthThresholdsUpdated(thresholds);
- } catch (RemoteException e) {
- Log.e(TAG, "Error sending signal strength thresholds event", e);
- }
- }
-
- /**
- * Notify the NetworkAgent that automatic reconnect should be prevented.
- */
- public void onPreventAutomaticReconnect() {
- try {
- networkAgent.onPreventAutomaticReconnect();
- } catch (RemoteException e) {
- Log.e(TAG, "Error sending prevent automatic reconnect event", e);
- }
- }
-
- /**
- * Notify the NetworkAgent that a NATT keepalive packet filter should be added.
- */
- public void onAddNattKeepalivePacketFilter(int slot,
- @NonNull NattKeepalivePacketData packetData) {
- try {
- networkAgent.onAddNattKeepalivePacketFilter(slot, packetData);
- } catch (RemoteException e) {
- Log.e(TAG, "Error sending add NATT keepalive packet filter event", e);
- }
- }
-
- /**
- * Notify the NetworkAgent that a TCP keepalive packet filter should be added.
- */
- public void onAddTcpKeepalivePacketFilter(int slot,
- @NonNull TcpKeepalivePacketData packetData) {
- try {
- networkAgent.onAddTcpKeepalivePacketFilter(slot, packetData);
- } catch (RemoteException e) {
- Log.e(TAG, "Error sending add TCP keepalive packet filter event", e);
- }
- }
-
- /**
- * Notify the NetworkAgent that a keepalive packet filter should be removed.
- */
- public void onRemoveKeepalivePacketFilter(int slot) {
- try {
- networkAgent.onRemoveKeepalivePacketFilter(slot);
- } catch (RemoteException e) {
- Log.e(TAG, "Error sending remove keepalive packet filter event", e);
- }
- }
-
- /**
- * Notify the NetworkAgent that the qos filter should be registered against the given qos
- * callback id.
- */
- public void onQosFilterCallbackRegistered(final int qosCallbackId,
- final QosFilter qosFilter) {
- try {
- networkAgent.onQosFilterCallbackRegistered(qosCallbackId,
- new QosFilterParcelable(qosFilter));
- } catch (final RemoteException e) {
- Log.e(TAG, "Error registering a qos callback id against a qos filter", e);
- }
- }
-
- /**
- * Notify the NetworkAgent that the given qos callback id should be unregistered.
- */
- public void onQosCallbackUnregistered(final int qosCallbackId) {
- try {
- networkAgent.onQosCallbackUnregistered(qosCallbackId);
- } catch (RemoteException e) {
- Log.e(TAG, "Error unregistering a qos callback id", e);
- }
- }
-
- /**
- * Notify the NetworkAgent that the network is successfully connected.
- */
- public void onNetworkCreated() {
- try {
- networkAgent.onNetworkCreated();
- } catch (RemoteException e) {
- Log.e(TAG, "Error sending network created event", e);
- }
- }
-
- /**
- * Notify the NetworkAgent that the native network has been destroyed.
- */
- public void onNetworkDestroyed() {
- try {
- networkAgent.onNetworkDestroyed();
- } catch (RemoteException e) {
- Log.e(TAG, "Error sending network destroyed event", e);
- }
- }
-
- // TODO: consider moving out of NetworkAgentInfo into its own class
- private class NetworkAgentMessageHandler extends INetworkAgentRegistry.Stub {
- private final Handler mHandler;
-
- private NetworkAgentMessageHandler(Handler handler) {
- mHandler = handler;
- }
-
- @Override
- public void sendNetworkCapabilities(@NonNull NetworkCapabilities nc) {
- Objects.requireNonNull(nc);
- mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED,
- new Pair<>(NetworkAgentInfo.this, nc)).sendToTarget();
- }
-
- @Override
- public void sendLinkProperties(@NonNull LinkProperties lp) {
- Objects.requireNonNull(lp);
- mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED,
- new Pair<>(NetworkAgentInfo.this, lp)).sendToTarget();
- }
-
- @Override
- public void sendNetworkInfo(@NonNull NetworkInfo info) {
- Objects.requireNonNull(info);
- mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_INFO_CHANGED,
- new Pair<>(NetworkAgentInfo.this, info)).sendToTarget();
- }
-
- @Override
- public void sendScore(@NonNull final NetworkScore score) {
- mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_SCORE_CHANGED,
- new Pair<>(NetworkAgentInfo.this, score)).sendToTarget();
- }
-
- @Override
- public void sendExplicitlySelected(boolean explicitlySelected, boolean acceptPartial) {
- mHandler.obtainMessage(NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED,
- explicitlySelected ? 1 : 0, acceptPartial ? 1 : 0,
- new Pair<>(NetworkAgentInfo.this, null)).sendToTarget();
- }
-
- @Override
- public void sendSocketKeepaliveEvent(int slot, int reason) {
- mHandler.obtainMessage(NetworkAgent.EVENT_SOCKET_KEEPALIVE,
- slot, reason, new Pair<>(NetworkAgentInfo.this, null)).sendToTarget();
- }
-
- @Override
- public void sendUnderlyingNetworks(@Nullable List<Network> networks) {
- mHandler.obtainMessage(NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED,
- new Pair<>(NetworkAgentInfo.this, networks)).sendToTarget();
- }
-
- @Override
- public void sendEpsQosSessionAvailable(final int qosCallbackId, final QosSession session,
- final EpsBearerQosSessionAttributes attributes) {
- mQosCallbackTracker.sendEventEpsQosSessionAvailable(qosCallbackId, session, attributes);
- }
-
- @Override
- public void sendNrQosSessionAvailable(final int qosCallbackId, final QosSession session,
- final NrQosSessionAttributes attributes) {
- mQosCallbackTracker.sendEventNrQosSessionAvailable(qosCallbackId, session, attributes);
- }
-
- @Override
- public void sendQosSessionLost(final int qosCallbackId, final QosSession session) {
- mQosCallbackTracker.sendEventQosSessionLost(qosCallbackId, session);
- }
-
- @Override
- public void sendQosCallbackError(final int qosCallbackId,
- @QosCallbackException.ExceptionType final int exceptionType) {
- mQosCallbackTracker.sendEventQosCallbackError(qosCallbackId, exceptionType);
- }
-
- @Override
- public void sendTeardownDelayMs(int teardownDelayMs) {
- mHandler.obtainMessage(NetworkAgent.EVENT_TEARDOWN_DELAY_CHANGED,
- teardownDelayMs, 0, new Pair<>(NetworkAgentInfo.this, null)).sendToTarget();
- }
-
- @Override
- public void sendLingerDuration(final int durationMs) {
- mHandler.obtainMessage(NetworkAgent.EVENT_LINGER_DURATION_CHANGED,
- new Pair<>(NetworkAgentInfo.this, durationMs)).sendToTarget();
- }
- }
-
- /**
- * Inform NetworkAgentInfo that a new NetworkMonitor was created.
- */
- public void onNetworkMonitorCreated(INetworkMonitor networkMonitor) {
- mNetworkMonitor = new NetworkMonitorManager(networkMonitor);
- }
-
- /**
- * Set the NetworkCapabilities on this NetworkAgentInfo. Also attempts to notify NetworkMonitor
- * of the new capabilities, if NetworkMonitor has been created.
- *
- * <p>If {@link NetworkMonitor#notifyNetworkCapabilitiesChanged(NetworkCapabilities)} fails,
- * the exception is logged but not reported to callers.
- *
- * @return the old capabilities of this network.
- */
- @NonNull public synchronized NetworkCapabilities getAndSetNetworkCapabilities(
- @NonNull final NetworkCapabilities nc) {
- final NetworkCapabilities oldNc = networkCapabilities;
- networkCapabilities = nc;
- mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig, everValidatedForYield(),
- yieldToBadWiFi());
- final NetworkMonitorManager nm = mNetworkMonitor;
- if (nm != null) {
- nm.notifyNetworkCapabilitiesChanged(nc);
- }
- return oldNc;
- }
-
- private boolean yieldToBadWiFi() {
- // Only cellular networks yield to bad wifi
- return networkCapabilities.hasTransport(TRANSPORT_CELLULAR) && !mConnService.avoidBadWifi();
- }
-
- public ConnectivityService connService() {
- return mConnService;
- }
-
- public NetworkAgentConfig netAgentConfig() {
- return networkAgentConfig;
- }
-
- public Handler handler() {
- return mHandler;
- }
-
- public Network network() {
- return network;
- }
-
- /**
- * Get the NetworkMonitorManager in this NetworkAgentInfo.
- *
- * <p>This will be null before {@link #onNetworkMonitorCreated(INetworkMonitor)} is called.
- */
- public NetworkMonitorManager networkMonitor() {
- return mNetworkMonitor;
- }
-
- // Functions for manipulating the requests satisfied by this network.
- //
- // These functions must only called on ConnectivityService's main thread.
-
- private static final boolean ADD = true;
- private static final boolean REMOVE = false;
-
- private void updateRequestCounts(boolean add, NetworkRequest request) {
- int delta = add ? +1 : -1;
- switch (request.type) {
- case REQUEST:
- mNumRequestNetworkRequests += delta;
- break;
-
- case BACKGROUND_REQUEST:
- mNumRequestNetworkRequests += delta;
- mNumBackgroundNetworkRequests += delta;
- break;
-
- case LISTEN:
- case LISTEN_FOR_BEST:
- case TRACK_DEFAULT:
- case TRACK_SYSTEM_DEFAULT:
- break;
-
- case NONE:
- default:
- Log.wtf(TAG, "Unhandled request type " + request.type);
- break;
- }
- }
-
- /**
- * Add {@code networkRequest} to this network as it's satisfied by this network.
- * @return true if {@code networkRequest} was added or false if {@code networkRequest} was
- * already present.
- */
- public boolean addRequest(NetworkRequest networkRequest) {
- NetworkRequest existing = mNetworkRequests.get(networkRequest.requestId);
- if (existing == networkRequest) return false;
- if (existing != null) {
- // Should only happen if the requestId wraps. If that happens lots of other things will
- // be broken as well.
- Log.wtf(TAG, String.format("Duplicate requestId for %s and %s on %s",
- networkRequest, existing, toShortString()));
- updateRequestCounts(REMOVE, existing);
- }
- mNetworkRequests.put(networkRequest.requestId, networkRequest);
- updateRequestCounts(ADD, networkRequest);
- return true;
- }
-
- /**
- * Remove the specified request from this network.
- */
- public void removeRequest(int requestId) {
- NetworkRequest existing = mNetworkRequests.get(requestId);
- if (existing == null) return;
- updateRequestCounts(REMOVE, existing);
- mNetworkRequests.remove(requestId);
- if (existing.isRequest()) {
- unlingerRequest(existing.requestId);
- }
- }
-
- /**
- * Returns whether this network is currently satisfying the request with the specified ID.
- */
- public boolean isSatisfyingRequest(int id) {
- return mNetworkRequests.get(id) != null;
- }
-
- /**
- * Returns the request at the specified position in the list of requests satisfied by this
- * network.
- */
- public NetworkRequest requestAt(int index) {
- return mNetworkRequests.valueAt(index);
- }
-
- /**
- * Returns the number of requests currently satisfied by this network for which
- * {@link android.net.NetworkRequest#isRequest} returns {@code true}.
- */
- public int numRequestNetworkRequests() {
- return mNumRequestNetworkRequests;
- }
-
- /**
- * Returns the number of requests currently satisfied by this network of type
- * {@link android.net.NetworkRequest.Type.BACKGROUND_REQUEST}.
- */
- public int numBackgroundNetworkRequests() {
- return mNumBackgroundNetworkRequests;
- }
-
- /**
- * Returns the number of foreground requests currently satisfied by this network.
- */
- public int numForegroundNetworkRequests() {
- return mNumRequestNetworkRequests - mNumBackgroundNetworkRequests;
- }
-
- /**
- * Returns the number of requests of any type currently satisfied by this network.
- */
- public int numNetworkRequests() {
- return mNetworkRequests.size();
- }
-
- /**
- * Returns whether the network is a background network. A network is a background network if it
- * does not have the NET_CAPABILITY_FOREGROUND capability, which implies it is satisfying no
- * foreground request, is not lingering (i.e. kept for a while after being outscored), and is
- * not a speculative network (i.e. kept pending validation when validation would have it
- * outscore another foreground network). That implies it is being kept up by some background
- * request (otherwise it would be torn down), maybe the mobile always-on request.
- */
- public boolean isBackgroundNetwork() {
- return !isVPN() && numForegroundNetworkRequests() == 0 && mNumBackgroundNetworkRequests > 0
- && !isLingering();
- }
-
- // Does this network satisfy request?
- public boolean satisfies(NetworkRequest request) {
- return created &&
- request.networkCapabilities.satisfiedByNetworkCapabilities(networkCapabilities);
- }
-
- public boolean satisfiesImmutableCapabilitiesOf(NetworkRequest request) {
- return created &&
- request.networkCapabilities.satisfiedByImmutableNetworkCapabilities(
- networkCapabilities);
- }
-
- /** Whether this network is a VPN. */
- public boolean isVPN() {
- return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
- }
-
- /** Whether this network might have underlying networks. Currently only true for VPNs. */
- public boolean supportsUnderlyingNetworks() {
- return isVPN();
- }
-
- // Caller must not mutate. This method is called frequently and making a defensive copy
- // would be too expensive. This is used by NetworkRanker.Scoreable, so it can be compared
- // against other scoreables.
- @Override public NetworkCapabilities getCapsNoCopy() {
- return networkCapabilities;
- }
-
- // NetworkRanker.Scoreable
- @Override public FullScore getScore() {
- return mScore;
- }
-
- // Get the current score for this Network. This may be modified from what the
- // NetworkAgent sent, as it has modifiers applied to it.
- public int getCurrentScore() {
- return mScore.getLegacyInt();
- }
-
- // Get the current score for this Network as if it was validated. This may be modified from
- // what the NetworkAgent sent, as it has modifiers applied to it.
- public int getCurrentScoreAsValidated() {
- return mScore.getLegacyIntAsValidated();
- }
-
- /**
- * Mix-in the ConnectivityService-managed bits in the score.
- */
- public void setScore(final NetworkScore score) {
- mScore = FullScore.fromNetworkScore(score, networkCapabilities, networkAgentConfig,
- everValidatedForYield(), yieldToBadWiFi());
- }
-
- /**
- * Update the ConnectivityService-managed bits in the score.
- *
- * Call this after updating the network agent config.
- */
- public void updateScoreForNetworkAgentUpdate() {
- mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig,
- everValidatedForYield(), yieldToBadWiFi());
- }
-
- private boolean everValidatedForYield() {
- return everValidated && !avoidUnvalidated;
- }
-
- /**
- * Returns a Scoreable identical to this NAI, but validated.
- *
- * This is useful to probe what scoring would be if this network validated, to know
- * whether to provisionally keep a network that may or may not validate.
- *
- * @return a Scoreable identical to this NAI, but validated.
- */
- public NetworkRanker.Scoreable getValidatedScoreable() {
- return new NetworkRanker.Scoreable() {
- @Override public FullScore getScore() {
- return mScore.asValidated();
- }
-
- @Override public NetworkCapabilities getCapsNoCopy() {
- return networkCapabilities;
- }
- };
- }
-
- /**
- * Return a {@link NetworkStateSnapshot} for this network.
- */
- @NonNull
- public NetworkStateSnapshot getNetworkStateSnapshot() {
- synchronized (this) {
- // Network objects are outwardly immutable so there is no point in duplicating.
- // Duplicating also precludes sharing socket factories and connection pools.
- final String subscriberId = (networkAgentConfig != null)
- ? networkAgentConfig.subscriberId : null;
- return new NetworkStateSnapshot(network, new NetworkCapabilities(networkCapabilities),
- new LinkProperties(linkProperties), subscriberId, networkInfo.getType());
- }
- }
-
- /**
- * Sets the specified requestId to linger on this network for the specified time. Called by
- * ConnectivityService when any request is moved to another network with a higher score, or
- * when a network is newly created.
- *
- * @param requestId The requestId of the request that no longer need to be served by this
- * network. Or {@link NetworkRequest.REQUEST_ID_NONE} if this is the
- * {@code InactivityTimer} for a newly created network.
- */
- // TODO: Consider creating a dedicated function for nascent network, e.g. start/stopNascent.
- public void lingerRequest(int requestId, long now, long duration) {
- if (mInactivityTimerForRequest.get(requestId) != null) {
- // Cannot happen. Once a request is lingering on a particular network, we cannot
- // re-linger it unless that network becomes the best for that request again, in which
- // case we should have unlingered it.
- Log.wtf(TAG, toShortString() + ": request " + requestId + " already lingered");
- }
- final long expiryMs = now + duration;
- InactivityTimer timer = new InactivityTimer(requestId, expiryMs);
- if (VDBG) Log.d(TAG, "Adding InactivityTimer " + timer + " to " + toShortString());
- mInactivityTimers.add(timer);
- mInactivityTimerForRequest.put(requestId, timer);
- }
-
- /**
- * Sets the specified requestId to linger on this network for the timeout set when
- * initializing or modified by {@link #setLingerDuration(int)}. Called by
- * ConnectivityService when any request is moved to another network with a higher score.
- *
- * @param requestId The requestId of the request that no longer need to be served by this
- * network.
- * @param now current system timestamp obtained by {@code SystemClock.elapsedRealtime}.
- */
- public void lingerRequest(int requestId, long now) {
- lingerRequest(requestId, now, mLingerDurationMs);
- }
-
- /**
- * Cancel lingering. Called by ConnectivityService when a request is added to this network.
- * Returns true if the given requestId was lingering on this network, false otherwise.
- */
- public boolean unlingerRequest(int requestId) {
- InactivityTimer timer = mInactivityTimerForRequest.get(requestId);
- if (timer != null) {
- if (VDBG) {
- Log.d(TAG, "Removing InactivityTimer " + timer + " from " + toShortString());
- }
- mInactivityTimers.remove(timer);
- mInactivityTimerForRequest.remove(requestId);
- return true;
- }
- return false;
- }
-
- public long getInactivityExpiry() {
- return mInactivityExpiryMs;
- }
-
- public void updateInactivityTimer() {
- long newExpiry = mInactivityTimers.isEmpty() ? 0 : mInactivityTimers.last().expiryMs;
- if (newExpiry == mInactivityExpiryMs) return;
-
- // Even if we're going to reschedule the timer, cancel it first. This is because the
- // semantics of WakeupMessage guarantee that if cancel is called then the alarm will
- // never call its callback (handleLingerComplete), even if it has already fired.
- // WakeupMessage makes no such guarantees about rescheduling a message, so if mLingerMessage
- // has already been dispatched, rescheduling to some time in the future won't stop it
- // from calling its callback immediately.
- if (mInactivityMessage != null) {
- mInactivityMessage.cancel();
- mInactivityMessage = null;
- }
-
- if (newExpiry > 0) {
- // If the newExpiry timestamp is in the past, the wakeup message will fire immediately.
- mInactivityMessage = new WakeupMessage(
- mContext, mHandler,
- "NETWORK_LINGER_COMPLETE." + network.getNetId() /* cmdName */,
- EVENT_NETWORK_LINGER_COMPLETE /* cmd */,
- 0 /* arg1 (unused) */, 0 /* arg2 (unused) */,
- this /* obj (NetworkAgentInfo) */);
- mInactivityMessage.schedule(newExpiry);
- }
-
- mInactivityExpiryMs = newExpiry;
- }
-
- public void setInactive() {
- mInactive = true;
- }
-
- public void unsetInactive() {
- mInactive = false;
- }
-
- public boolean isInactive() {
- return mInactive;
- }
-
- public boolean isLingering() {
- return mInactive && !isNascent();
- }
-
- /**
- * Set the linger duration for this NAI.
- * @param durationMs The new linger duration, in milliseconds.
- */
- public void setLingerDuration(final int durationMs) {
- final long diff = durationMs - mLingerDurationMs;
- final ArrayList<InactivityTimer> newTimers = new ArrayList<>();
- for (final InactivityTimer timer : mInactivityTimers) {
- if (timer.requestId == NetworkRequest.REQUEST_ID_NONE) {
- // Don't touch nascent timer, re-add as is.
- newTimers.add(timer);
- } else {
- newTimers.add(new InactivityTimer(timer.requestId, timer.expiryMs + diff));
- }
- }
- mInactivityTimers.clear();
- mInactivityTimers.addAll(newTimers);
- updateInactivityTimer();
- mLingerDurationMs = durationMs;
- }
-
- /**
- * Return whether the network satisfies no request, but is still being kept up
- * because it has just connected less than
- * {@code ConnectivityService#DEFAULT_NASCENT_DELAY_MS}ms ago and is thus still considered
- * nascent. Note that nascent mechanism uses inactivity timer which isn't
- * associated with a request. Thus, use {@link NetworkRequest#REQUEST_ID_NONE} to identify it.
- *
- */
- public boolean isNascent() {
- return mInactive && mInactivityTimers.size() == 1
- && mInactivityTimers.first().requestId == NetworkRequest.REQUEST_ID_NONE;
- }
-
- public void clearInactivityState() {
- if (mInactivityMessage != null) {
- mInactivityMessage.cancel();
- mInactivityMessage = null;
- }
- mInactivityTimers.clear();
- mInactivityTimerForRequest.clear();
- // Sets mInactivityExpiryMs, cancels and nulls out mInactivityMessage.
- updateInactivityTimer();
- mInactive = false;
- }
-
- public void dumpInactivityTimers(PrintWriter pw) {
- for (InactivityTimer timer : mInactivityTimers) {
- pw.println(timer);
- }
- }
-
- /**
- * Sets the most recent ConnectivityReport for this network.
- *
- * <p>This should only be called from the ConnectivityService thread.
- *
- * @hide
- */
- public void setConnectivityReport(@NonNull ConnectivityReport connectivityReport) {
- mConnectivityReport = connectivityReport;
- }
-
- /**
- * Returns the most recent ConnectivityReport for this network, or null if none have been
- * reported yet.
- *
- * <p>This should only be called from the ConnectivityService thread.
- *
- * @hide
- */
- @Nullable
- public ConnectivityReport getConnectivityReport() {
- return mConnectivityReport;
- }
-
- // TODO: Print shorter members first and only print the boolean variable which value is true
- // to improve readability.
- public String toString() {
- return "NetworkAgentInfo{"
- + "network{" + network + "} handle{" + network.getNetworkHandle() + "} ni{"
- + networkInfo.toShortString() + "} "
- + mScore + " "
- + (isNascent() ? " nascent" : (isLingering() ? " lingering" : ""))
- + (everValidated ? " everValidated" : "")
- + (lastValidated ? " lastValidated" : "")
- + (partialConnectivity ? " partialConnectivity" : "")
- + (everCaptivePortalDetected ? " everCaptivePortal" : "")
- + (lastCaptivePortalDetected ? " isCaptivePortal" : "")
- + (networkAgentConfig.explicitlySelected ? " explicitlySelected" : "")
- + (networkAgentConfig.acceptUnvalidated ? " acceptUnvalidated" : "")
- + (networkAgentConfig.acceptPartialConnectivity ? " acceptPartialConnectivity" : "")
- + (clatd.isStarted() ? " clat{" + clatd + "} " : "")
- + (declaredUnderlyingNetworks != null
- ? " underlying{" + Arrays.toString(declaredUnderlyingNetworks) + "}" : "")
- + " lp{" + linkProperties + "}"
- + " nc{" + networkCapabilities + "}"
- + "}";
- }
-
- /**
- * Show a short string representing a Network.
- *
- * This is often not enough for debugging purposes for anything complex, but the full form
- * is very long and hard to read, so this is useful when there isn't a lot of ambiguity.
- * This represents the network with something like "[100 WIFI|VPN]" or "[108 MOBILE]".
- */
- public String toShortString() {
- return "[" + network.getNetId() + " "
- + transportNamesOf(networkCapabilities.getTransportTypes()) + "]";
- }
-
- // Enables sorting in descending order of score.
- @Override
- public int compareTo(NetworkAgentInfo other) {
- return other.getCurrentScore() - getCurrentScore();
- }
-
- /**
- * Null-guarding version of NetworkAgentInfo#toShortString()
- */
- @NonNull
- public static String toShortString(@Nullable final NetworkAgentInfo nai) {
- return null != nai ? nai.toShortString() : "[null]";
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/NetworkDiagnostics.java b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkDiagnostics.java
deleted file mode 100644
index 2e51be3..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/NetworkDiagnostics.java
+++ /dev/null
@@ -1,757 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.system.OsConstants.*;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.InetAddresses;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.RouteInfo;
-import android.net.TrafficStats;
-import android.net.shared.PrivateDnsConfig;
-import android.net.util.NetworkConstants;
-import android.os.SystemClock;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.StructTimeval;
-import android.text.TextUtils;
-import android.util.Pair;
-
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.net.module.util.NetworkStackConstants;
-
-import libcore.io.IoUtils;
-
-import java.io.Closeable;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.NetworkInterface;
-import java.net.SocketAddress;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import javax.net.ssl.SNIHostName;
-import javax.net.ssl.SNIServerName;
-import javax.net.ssl.SSLParameters;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
-
-/**
- * NetworkDiagnostics
- *
- * A simple class to diagnose network connectivity fundamentals. Current
- * checks performed are:
- * - ICMPv4/v6 echo requests for all routers
- * - ICMPv4/v6 echo requests for all DNS servers
- * - DNS UDP queries to all DNS servers
- *
- * Currently unimplemented checks include:
- * - report ARP/ND data about on-link neighbors
- * - DNS TCP queries to all DNS servers
- * - HTTP DIRECT and PROXY checks
- * - port 443 blocking/TLS intercept checks
- * - QUIC reachability checks
- * - MTU checks
- *
- * The supplied timeout bounds the entire diagnostic process. Each specific
- * check class must implement this upper bound on measurements in whichever
- * manner is most appropriate and effective.
- *
- * @hide
- */
-public class NetworkDiagnostics {
- private static final String TAG = "NetworkDiagnostics";
-
- private static final InetAddress TEST_DNS4 = InetAddresses.parseNumericAddress("8.8.8.8");
- private static final InetAddress TEST_DNS6 = InetAddresses.parseNumericAddress(
- "2001:4860:4860::8888");
-
- // For brevity elsewhere.
- private static final long now() {
- return SystemClock.elapsedRealtime();
- }
-
- // Values from RFC 1035 section 4.1.1, names from <arpa/nameser.h>.
- // Should be a member of DnsUdpCheck, but "compiler says no".
- public static enum DnsResponseCode { NOERROR, FORMERR, SERVFAIL, NXDOMAIN, NOTIMP, REFUSED };
-
- private final Network mNetwork;
- private final LinkProperties mLinkProperties;
- private final PrivateDnsConfig mPrivateDnsCfg;
- private final Integer mInterfaceIndex;
-
- private final long mTimeoutMs;
- private final long mStartTime;
- private final long mDeadlineTime;
-
- // A counter, initialized to the total number of measurements,
- // so callers can wait for completion.
- private final CountDownLatch mCountDownLatch;
-
- public class Measurement {
- private static final String SUCCEEDED = "SUCCEEDED";
- private static final String FAILED = "FAILED";
-
- private boolean succeeded;
-
- // Package private. TODO: investigate better encapsulation.
- String description = "";
- long startTime;
- long finishTime;
- String result = "";
- Thread thread;
-
- public boolean checkSucceeded() { return succeeded; }
-
- void recordSuccess(String msg) {
- maybeFixupTimes();
- succeeded = true;
- result = SUCCEEDED + ": " + msg;
- if (mCountDownLatch != null) {
- mCountDownLatch.countDown();
- }
- }
-
- void recordFailure(String msg) {
- maybeFixupTimes();
- succeeded = false;
- result = FAILED + ": " + msg;
- if (mCountDownLatch != null) {
- mCountDownLatch.countDown();
- }
- }
-
- private void maybeFixupTimes() {
- // Allows the caller to just set success/failure and not worry
- // about also setting the correct finishing time.
- if (finishTime == 0) { finishTime = now(); }
-
- // In cases where, for example, a failure has occurred before the
- // measurement even began, fixup the start time to reflect as much.
- if (startTime == 0) { startTime = finishTime; }
- }
-
- @Override
- public String toString() {
- return description + ": " + result + " (" + (finishTime - startTime) + "ms)";
- }
- }
-
- private final Map<InetAddress, Measurement> mIcmpChecks = new HashMap<>();
- private final Map<Pair<InetAddress, InetAddress>, Measurement> mExplicitSourceIcmpChecks =
- new HashMap<>();
- private final Map<InetAddress, Measurement> mDnsUdpChecks = new HashMap<>();
- private final Map<InetAddress, Measurement> mDnsTlsChecks = new HashMap<>();
- private final String mDescription;
-
-
- public NetworkDiagnostics(Network network, LinkProperties lp,
- @NonNull PrivateDnsConfig privateDnsCfg, long timeoutMs) {
- mNetwork = network;
- mLinkProperties = lp;
- mPrivateDnsCfg = privateDnsCfg;
- mInterfaceIndex = getInterfaceIndex(mLinkProperties.getInterfaceName());
- mTimeoutMs = timeoutMs;
- mStartTime = now();
- mDeadlineTime = mStartTime + mTimeoutMs;
-
- // Hardcode measurements to TEST_DNS4 and TEST_DNS6 in order to test off-link connectivity.
- // We are free to modify mLinkProperties with impunity because ConnectivityService passes us
- // a copy and not the original object. It's easier to do it this way because we don't need
- // to check whether the LinkProperties already contains these DNS servers because
- // LinkProperties#addDnsServer checks for duplicates.
- if (mLinkProperties.isReachable(TEST_DNS4)) {
- mLinkProperties.addDnsServer(TEST_DNS4);
- }
- // TODO: we could use mLinkProperties.isReachable(TEST_DNS6) here, because we won't set any
- // DNS servers for which isReachable() is false, but since this is diagnostic code, be extra
- // careful.
- if (mLinkProperties.hasGlobalIpv6Address() || mLinkProperties.hasIpv6DefaultRoute()) {
- mLinkProperties.addDnsServer(TEST_DNS6);
- }
-
- for (RouteInfo route : mLinkProperties.getRoutes()) {
- if (route.hasGateway()) {
- InetAddress gateway = route.getGateway();
- prepareIcmpMeasurement(gateway);
- if (route.isIPv6Default()) {
- prepareExplicitSourceIcmpMeasurements(gateway);
- }
- }
- }
- for (InetAddress nameserver : mLinkProperties.getDnsServers()) {
- prepareIcmpMeasurement(nameserver);
- prepareDnsMeasurement(nameserver);
-
- // Unlike the DnsResolver which doesn't do certificate validation in opportunistic mode,
- // DoT probes to the DNS servers will fail if certificate validation fails.
- prepareDnsTlsMeasurement(null /* hostname */, nameserver);
- }
-
- for (InetAddress tlsNameserver : mPrivateDnsCfg.ips) {
- // Reachability check is necessary since when resolving the strict mode hostname,
- // NetworkMonitor always queries for both A and AAAA records, even if the network
- // is IPv4-only or IPv6-only.
- if (mLinkProperties.isReachable(tlsNameserver)) {
- // If there are IPs, there must have been a name that resolved to them.
- prepareDnsTlsMeasurement(mPrivateDnsCfg.hostname, tlsNameserver);
- }
- }
-
- mCountDownLatch = new CountDownLatch(totalMeasurementCount());
-
- startMeasurements();
-
- mDescription = "ifaces{" + TextUtils.join(",", mLinkProperties.getAllInterfaceNames()) + "}"
- + " index{" + mInterfaceIndex + "}"
- + " network{" + mNetwork + "}"
- + " nethandle{" + mNetwork.getNetworkHandle() + "}";
- }
-
- private static Integer getInterfaceIndex(String ifname) {
- try {
- NetworkInterface ni = NetworkInterface.getByName(ifname);
- return ni.getIndex();
- } catch (NullPointerException | SocketException e) {
- return null;
- }
- }
-
- private static String socketAddressToString(@NonNull SocketAddress sockAddr) {
- // The default toString() implementation is not the prettiest.
- InetSocketAddress inetSockAddr = (InetSocketAddress) sockAddr;
- InetAddress localAddr = inetSockAddr.getAddress();
- return String.format(
- (localAddr instanceof Inet6Address ? "[%s]:%d" : "%s:%d"),
- localAddr.getHostAddress(), inetSockAddr.getPort());
- }
-
- private void prepareIcmpMeasurement(InetAddress target) {
- if (!mIcmpChecks.containsKey(target)) {
- Measurement measurement = new Measurement();
- measurement.thread = new Thread(new IcmpCheck(target, measurement));
- mIcmpChecks.put(target, measurement);
- }
- }
-
- private void prepareExplicitSourceIcmpMeasurements(InetAddress target) {
- for (LinkAddress l : mLinkProperties.getLinkAddresses()) {
- InetAddress source = l.getAddress();
- if (source instanceof Inet6Address && l.isGlobalPreferred()) {
- Pair<InetAddress, InetAddress> srcTarget = new Pair<>(source, target);
- if (!mExplicitSourceIcmpChecks.containsKey(srcTarget)) {
- Measurement measurement = new Measurement();
- measurement.thread = new Thread(new IcmpCheck(source, target, measurement));
- mExplicitSourceIcmpChecks.put(srcTarget, measurement);
- }
- }
- }
- }
-
- private void prepareDnsMeasurement(InetAddress target) {
- if (!mDnsUdpChecks.containsKey(target)) {
- Measurement measurement = new Measurement();
- measurement.thread = new Thread(new DnsUdpCheck(target, measurement));
- mDnsUdpChecks.put(target, measurement);
- }
- }
-
- private void prepareDnsTlsMeasurement(@Nullable String hostname, @NonNull InetAddress target) {
- // This might overwrite an existing entry in mDnsTlsChecks, because |target| can be an IP
- // address configured by the network as well as an IP address learned by resolving the
- // strict mode DNS hostname. If the entry is overwritten, the overwritten measurement
- // thread will not execute.
- Measurement measurement = new Measurement();
- measurement.thread = new Thread(new DnsTlsCheck(hostname, target, measurement));
- mDnsTlsChecks.put(target, measurement);
- }
-
- private int totalMeasurementCount() {
- return mIcmpChecks.size() + mExplicitSourceIcmpChecks.size() + mDnsUdpChecks.size()
- + mDnsTlsChecks.size();
- }
-
- private void startMeasurements() {
- for (Measurement measurement : mIcmpChecks.values()) {
- measurement.thread.start();
- }
- for (Measurement measurement : mExplicitSourceIcmpChecks.values()) {
- measurement.thread.start();
- }
- for (Measurement measurement : mDnsUdpChecks.values()) {
- measurement.thread.start();
- }
- for (Measurement measurement : mDnsTlsChecks.values()) {
- measurement.thread.start();
- }
- }
-
- public void waitForMeasurements() {
- try {
- mCountDownLatch.await(mDeadlineTime - now(), TimeUnit.MILLISECONDS);
- } catch (InterruptedException ignored) {}
- }
-
- public List<Measurement> getMeasurements() {
- // TODO: Consider moving waitForMeasurements() in here to minimize the
- // chance of caller errors.
-
- ArrayList<Measurement> measurements = new ArrayList(totalMeasurementCount());
-
- // Sort measurements IPv4 first.
- for (Map.Entry<InetAddress, Measurement> entry : mIcmpChecks.entrySet()) {
- if (entry.getKey() instanceof Inet4Address) {
- measurements.add(entry.getValue());
- }
- }
- for (Map.Entry<Pair<InetAddress, InetAddress>, Measurement> entry :
- mExplicitSourceIcmpChecks.entrySet()) {
- if (entry.getKey().first instanceof Inet4Address) {
- measurements.add(entry.getValue());
- }
- }
- for (Map.Entry<InetAddress, Measurement> entry : mDnsUdpChecks.entrySet()) {
- if (entry.getKey() instanceof Inet4Address) {
- measurements.add(entry.getValue());
- }
- }
- for (Map.Entry<InetAddress, Measurement> entry : mDnsTlsChecks.entrySet()) {
- if (entry.getKey() instanceof Inet4Address) {
- measurements.add(entry.getValue());
- }
- }
-
- // IPv6 measurements second.
- for (Map.Entry<InetAddress, Measurement> entry : mIcmpChecks.entrySet()) {
- if (entry.getKey() instanceof Inet6Address) {
- measurements.add(entry.getValue());
- }
- }
- for (Map.Entry<Pair<InetAddress, InetAddress>, Measurement> entry :
- mExplicitSourceIcmpChecks.entrySet()) {
- if (entry.getKey().first instanceof Inet6Address) {
- measurements.add(entry.getValue());
- }
- }
- for (Map.Entry<InetAddress, Measurement> entry : mDnsUdpChecks.entrySet()) {
- if (entry.getKey() instanceof Inet6Address) {
- measurements.add(entry.getValue());
- }
- }
- for (Map.Entry<InetAddress, Measurement> entry : mDnsTlsChecks.entrySet()) {
- if (entry.getKey() instanceof Inet6Address) {
- measurements.add(entry.getValue());
- }
- }
-
- return measurements;
- }
-
- public void dump(IndentingPrintWriter pw) {
- pw.println(TAG + ":" + mDescription);
- final long unfinished = mCountDownLatch.getCount();
- if (unfinished > 0) {
- // This can't happen unless a caller forgets to call waitForMeasurements()
- // or a measurement isn't implemented to correctly honor the timeout.
- pw.println("WARNING: countdown wait incomplete: "
- + unfinished + " unfinished measurements");
- }
-
- pw.increaseIndent();
-
- String prefix;
- for (Measurement m : getMeasurements()) {
- prefix = m.checkSucceeded() ? "." : "F";
- pw.println(prefix + " " + m.toString());
- }
-
- pw.decreaseIndent();
- }
-
-
- private class SimpleSocketCheck implements Closeable {
- protected final InetAddress mSource; // Usually null.
- protected final InetAddress mTarget;
- protected final int mAddressFamily;
- protected final Measurement mMeasurement;
- protected FileDescriptor mFileDescriptor;
- protected SocketAddress mSocketAddress;
-
- protected SimpleSocketCheck(
- InetAddress source, InetAddress target, Measurement measurement) {
- mMeasurement = measurement;
-
- if (target instanceof Inet6Address) {
- Inet6Address targetWithScopeId = null;
- if (target.isLinkLocalAddress() && mInterfaceIndex != null) {
- try {
- targetWithScopeId = Inet6Address.getByAddress(
- null, target.getAddress(), mInterfaceIndex);
- } catch (UnknownHostException e) {
- mMeasurement.recordFailure(e.toString());
- }
- }
- mTarget = (targetWithScopeId != null) ? targetWithScopeId : target;
- mAddressFamily = AF_INET6;
- } else {
- mTarget = target;
- mAddressFamily = AF_INET;
- }
-
- // We don't need to check the scope ID here because we currently only do explicit-source
- // measurements from global IPv6 addresses.
- mSource = source;
- }
-
- protected SimpleSocketCheck(InetAddress target, Measurement measurement) {
- this(null, target, measurement);
- }
-
- protected void setupSocket(
- int sockType, int protocol, long writeTimeout, long readTimeout, int dstPort)
- throws ErrnoException, IOException {
- final int oldTag = TrafficStats.getAndSetThreadStatsTag(
- NetworkStackConstants.TAG_SYSTEM_PROBE);
- try {
- mFileDescriptor = Os.socket(mAddressFamily, sockType, protocol);
- } finally {
- // TODO: The tag should remain set until all traffic is sent and received.
- // Consider tagging the socket after the measurement thread is started.
- TrafficStats.setThreadStatsTag(oldTag);
- }
- // Setting SNDTIMEO is purely for defensive purposes.
- Os.setsockoptTimeval(mFileDescriptor,
- SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(writeTimeout));
- Os.setsockoptTimeval(mFileDescriptor,
- SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(readTimeout));
- // TODO: Use IP_RECVERR/IPV6_RECVERR, pending OsContants availability.
- mNetwork.bindSocket(mFileDescriptor);
- if (mSource != null) {
- Os.bind(mFileDescriptor, mSource, 0);
- }
- Os.connect(mFileDescriptor, mTarget, dstPort);
- mSocketAddress = Os.getsockname(mFileDescriptor);
- }
-
- protected boolean ensureMeasurementNecessary() {
- if (mMeasurement.finishTime == 0) return false;
-
- // Countdown latch was not decremented when the measurement failed during setup.
- mCountDownLatch.countDown();
- return true;
- }
-
- @Override
- public void close() {
- IoUtils.closeQuietly(mFileDescriptor);
- }
- }
-
-
- private class IcmpCheck extends SimpleSocketCheck implements Runnable {
- private static final int TIMEOUT_SEND = 100;
- private static final int TIMEOUT_RECV = 300;
- private static final int PACKET_BUFSIZE = 512;
- private final int mProtocol;
- private final int mIcmpType;
-
- public IcmpCheck(InetAddress source, InetAddress target, Measurement measurement) {
- super(source, target, measurement);
-
- if (mAddressFamily == AF_INET6) {
- mProtocol = IPPROTO_ICMPV6;
- mIcmpType = NetworkConstants.ICMPV6_ECHO_REQUEST_TYPE;
- mMeasurement.description = "ICMPv6";
- } else {
- mProtocol = IPPROTO_ICMP;
- mIcmpType = NetworkConstants.ICMPV4_ECHO_REQUEST_TYPE;
- mMeasurement.description = "ICMPv4";
- }
-
- mMeasurement.description += " dst{" + mTarget.getHostAddress() + "}";
- }
-
- public IcmpCheck(InetAddress target, Measurement measurement) {
- this(null, target, measurement);
- }
-
- @Override
- public void run() {
- if (ensureMeasurementNecessary()) return;
-
- try {
- setupSocket(SOCK_DGRAM, mProtocol, TIMEOUT_SEND, TIMEOUT_RECV, 0);
- } catch (ErrnoException | IOException e) {
- mMeasurement.recordFailure(e.toString());
- return;
- }
- mMeasurement.description += " src{" + socketAddressToString(mSocketAddress) + "}";
-
- // Build a trivial ICMP packet.
- final byte[] icmpPacket = {
- (byte) mIcmpType, 0, 0, 0, 0, 0, 0, 0 // ICMP header
- };
-
- int count = 0;
- mMeasurement.startTime = now();
- while (now() < mDeadlineTime - (TIMEOUT_SEND + TIMEOUT_RECV)) {
- count++;
- icmpPacket[icmpPacket.length - 1] = (byte) count;
- try {
- Os.write(mFileDescriptor, icmpPacket, 0, icmpPacket.length);
- } catch (ErrnoException | InterruptedIOException e) {
- mMeasurement.recordFailure(e.toString());
- break;
- }
-
- try {
- ByteBuffer reply = ByteBuffer.allocate(PACKET_BUFSIZE);
- Os.read(mFileDescriptor, reply);
- // TODO: send a few pings back to back to guesstimate packet loss.
- mMeasurement.recordSuccess("1/" + count);
- break;
- } catch (ErrnoException | InterruptedIOException e) {
- continue;
- }
- }
- if (mMeasurement.finishTime == 0) {
- mMeasurement.recordFailure("0/" + count);
- }
-
- close();
- }
- }
-
-
- private class DnsUdpCheck extends SimpleSocketCheck implements Runnable {
- private static final int TIMEOUT_SEND = 100;
- private static final int TIMEOUT_RECV = 500;
- private static final int RR_TYPE_A = 1;
- private static final int RR_TYPE_AAAA = 28;
- private static final int PACKET_BUFSIZE = 512;
-
- protected final Random mRandom = new Random();
-
- // Should be static, but the compiler mocks our puny, human attempts at reason.
- protected String responseCodeStr(int rcode) {
- try {
- return DnsResponseCode.values()[rcode].toString();
- } catch (IndexOutOfBoundsException e) {
- return String.valueOf(rcode);
- }
- }
-
- protected final int mQueryType;
-
- public DnsUdpCheck(InetAddress target, Measurement measurement) {
- super(target, measurement);
-
- // TODO: Ideally, query the target for both types regardless of address family.
- if (mAddressFamily == AF_INET6) {
- mQueryType = RR_TYPE_AAAA;
- } else {
- mQueryType = RR_TYPE_A;
- }
-
- mMeasurement.description = "DNS UDP dst{" + mTarget.getHostAddress() + "}";
- }
-
- @Override
- public void run() {
- if (ensureMeasurementNecessary()) return;
-
- try {
- setupSocket(SOCK_DGRAM, IPPROTO_UDP, TIMEOUT_SEND, TIMEOUT_RECV,
- NetworkConstants.DNS_SERVER_PORT);
- } catch (ErrnoException | IOException e) {
- mMeasurement.recordFailure(e.toString());
- return;
- }
-
- // This needs to be fixed length so it can be dropped into the pre-canned packet.
- final String sixRandomDigits = String.valueOf(mRandom.nextInt(900000) + 100000);
- appendDnsToMeasurementDescription(sixRandomDigits, mSocketAddress);
-
- // Build a trivial DNS packet.
- final byte[] dnsPacket = getDnsQueryPacket(sixRandomDigits);
-
- int count = 0;
- mMeasurement.startTime = now();
- while (now() < mDeadlineTime - (TIMEOUT_RECV + TIMEOUT_RECV)) {
- count++;
- try {
- Os.write(mFileDescriptor, dnsPacket, 0, dnsPacket.length);
- } catch (ErrnoException | InterruptedIOException e) {
- mMeasurement.recordFailure(e.toString());
- break;
- }
-
- try {
- ByteBuffer reply = ByteBuffer.allocate(PACKET_BUFSIZE);
- Os.read(mFileDescriptor, reply);
- // TODO: more correct and detailed evaluation of the response,
- // possibly adding the returned IP address(es) to the output.
- final String rcodeStr = (reply.limit() > 3)
- ? " " + responseCodeStr((int) (reply.get(3)) & 0x0f)
- : "";
- mMeasurement.recordSuccess("1/" + count + rcodeStr);
- break;
- } catch (ErrnoException | InterruptedIOException e) {
- continue;
- }
- }
- if (mMeasurement.finishTime == 0) {
- mMeasurement.recordFailure("0/" + count);
- }
-
- close();
- }
-
- protected byte[] getDnsQueryPacket(String sixRandomDigits) {
- byte[] rnd = sixRandomDigits.getBytes(StandardCharsets.US_ASCII);
- return new byte[] {
- (byte) mRandom.nextInt(), (byte) mRandom.nextInt(), // [0-1] query ID
- 1, 0, // [2-3] flags; byte[2] = 1 for recursion desired (RD).
- 0, 1, // [4-5] QDCOUNT (number of queries)
- 0, 0, // [6-7] ANCOUNT (number of answers)
- 0, 0, // [8-9] NSCOUNT (number of name server records)
- 0, 0, // [10-11] ARCOUNT (number of additional records)
- 17, rnd[0], rnd[1], rnd[2], rnd[3], rnd[4], rnd[5],
- '-', 'a', 'n', 'd', 'r', 'o', 'i', 'd', '-', 'd', 's',
- 6, 'm', 'e', 't', 'r', 'i', 'c',
- 7, 'g', 's', 't', 'a', 't', 'i', 'c',
- 3, 'c', 'o', 'm',
- 0, // null terminator of FQDN (root TLD)
- 0, (byte) mQueryType, // QTYPE
- 0, 1 // QCLASS, set to 1 = IN (Internet)
- };
- }
-
- protected void appendDnsToMeasurementDescription(
- String sixRandomDigits, SocketAddress sockAddr) {
- mMeasurement.description += " src{" + socketAddressToString(sockAddr) + "}"
- + " qtype{" + mQueryType + "}"
- + " qname{" + sixRandomDigits + "-android-ds.metric.gstatic.com}";
- }
- }
-
- // TODO: Have it inherited from SimpleSocketCheck, and separate common DNS helpers out of
- // DnsUdpCheck.
- private class DnsTlsCheck extends DnsUdpCheck {
- private static final int TCP_CONNECT_TIMEOUT_MS = 2500;
- private static final int TCP_TIMEOUT_MS = 2000;
- private static final int DNS_TLS_PORT = 853;
- private static final int DNS_HEADER_SIZE = 12;
-
- private final String mHostname;
-
- public DnsTlsCheck(@Nullable String hostname, @NonNull InetAddress target,
- @NonNull Measurement measurement) {
- super(target, measurement);
-
- mHostname = hostname;
- mMeasurement.description = "DNS TLS dst{" + mTarget.getHostAddress() + "} hostname{"
- + (mHostname == null ? "" : mHostname) + "}";
- }
-
- private SSLSocket setupSSLSocket() throws IOException {
- // A TrustManager will be created and initialized with a KeyStore containing system
- // CaCerts. During SSL handshake, it will be used to validate the certificates from
- // the server.
- SSLSocket sslSocket = (SSLSocket) SSLSocketFactory.getDefault().createSocket();
- sslSocket.setSoTimeout(TCP_TIMEOUT_MS);
-
- if (!TextUtils.isEmpty(mHostname)) {
- // Set SNI.
- final List<SNIServerName> names =
- Collections.singletonList(new SNIHostName(mHostname));
- SSLParameters params = sslSocket.getSSLParameters();
- params.setServerNames(names);
- sslSocket.setSSLParameters(params);
- }
-
- mNetwork.bindSocket(sslSocket);
- return sslSocket;
- }
-
- private void sendDoTProbe(@Nullable SSLSocket sslSocket) throws IOException {
- final String sixRandomDigits = String.valueOf(mRandom.nextInt(900000) + 100000);
- final byte[] dnsPacket = getDnsQueryPacket(sixRandomDigits);
-
- mMeasurement.startTime = now();
- sslSocket.connect(new InetSocketAddress(mTarget, DNS_TLS_PORT), TCP_CONNECT_TIMEOUT_MS);
-
- // Synchronous call waiting for the TLS handshake complete.
- sslSocket.startHandshake();
- appendDnsToMeasurementDescription(sixRandomDigits, sslSocket.getLocalSocketAddress());
-
- final DataOutputStream output = new DataOutputStream(sslSocket.getOutputStream());
- output.writeShort(dnsPacket.length);
- output.write(dnsPacket, 0, dnsPacket.length);
-
- final DataInputStream input = new DataInputStream(sslSocket.getInputStream());
- final int replyLength = Short.toUnsignedInt(input.readShort());
- final byte[] reply = new byte[replyLength];
- int bytesRead = 0;
- while (bytesRead < replyLength) {
- bytesRead += input.read(reply, bytesRead, replyLength - bytesRead);
- }
-
- if (bytesRead > DNS_HEADER_SIZE && bytesRead == replyLength) {
- mMeasurement.recordSuccess("1/1 " + responseCodeStr((int) (reply[3]) & 0x0f));
- } else {
- mMeasurement.recordFailure("1/1 Read " + bytesRead + " bytes while expected to be "
- + replyLength + " bytes");
- }
- }
-
- @Override
- public void run() {
- if (ensureMeasurementNecessary()) return;
-
- // No need to restore the tag, since this thread is only used for this measurement.
- TrafficStats.getAndSetThreadStatsTag(NetworkStackConstants.TAG_SYSTEM_PROBE);
-
- try (SSLSocket sslSocket = setupSSLSocket()) {
- sendDoTProbe(sslSocket);
- } catch (IOException e) {
- mMeasurement.recordFailure(e.toString());
- }
- }
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/NetworkNotificationManager.java b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkNotificationManager.java
deleted file mode 100644
index 3dc79c5..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/NetworkNotificationManager.java
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-
-import android.annotation.NonNull;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.graphics.drawable.Icon;
-import android.net.ConnectivityResources;
-import android.net.NetworkSpecifier;
-import android.net.TelephonyNetworkSpecifier;
-import android.net.wifi.WifiInfo;
-import android.os.UserHandle;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.widget.Toast;
-
-import com.android.connectivity.resources.R;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-
-public class NetworkNotificationManager {
-
-
- public static enum NotificationType {
- LOST_INTERNET(SystemMessage.NOTE_NETWORK_LOST_INTERNET),
- NETWORK_SWITCH(SystemMessage.NOTE_NETWORK_SWITCH),
- NO_INTERNET(SystemMessage.NOTE_NETWORK_NO_INTERNET),
- PARTIAL_CONNECTIVITY(SystemMessage.NOTE_NETWORK_PARTIAL_CONNECTIVITY),
- SIGN_IN(SystemMessage.NOTE_NETWORK_SIGN_IN),
- PRIVATE_DNS_BROKEN(SystemMessage.NOTE_NETWORK_PRIVATE_DNS_BROKEN);
-
- public final int eventId;
-
- NotificationType(int eventId) {
- this.eventId = eventId;
- Holder.sIdToTypeMap.put(eventId, this);
- }
-
- private static class Holder {
- private static SparseArray<NotificationType> sIdToTypeMap = new SparseArray<>();
- }
-
- public static NotificationType getFromId(int id) {
- return Holder.sIdToTypeMap.get(id);
- }
- };
-
- private static final String TAG = NetworkNotificationManager.class.getSimpleName();
- private static final boolean DBG = true;
-
- // Notification channels used by ConnectivityService mainline module, it should be aligned with
- // SystemNotificationChannels so the channels are the same as the ones used as the system
- // server.
- public static final String NOTIFICATION_CHANNEL_NETWORK_STATUS = "NETWORK_STATUS";
- public static final String NOTIFICATION_CHANNEL_NETWORK_ALERTS = "NETWORK_ALERTS";
-
- // The context is for the current user (system server)
- private final Context mContext;
- private final ConnectivityResources mResources;
- private final TelephonyManager mTelephonyManager;
- // The notification manager is created from a context for User.ALL, so notifications
- // will be sent to all users.
- private final NotificationManager mNotificationManager;
- // Tracks the types of notifications managed by this instance, from creation to cancellation.
- private final SparseIntArray mNotificationTypeMap;
-
- public NetworkNotificationManager(@NonNull final Context c, @NonNull final TelephonyManager t) {
- mContext = c;
- mTelephonyManager = t;
- mNotificationManager =
- (NotificationManager) c.createContextAsUser(UserHandle.ALL, 0 /* flags */)
- .getSystemService(Context.NOTIFICATION_SERVICE);
- mNotificationTypeMap = new SparseIntArray();
- mResources = new ConnectivityResources(mContext);
- }
-
- @VisibleForTesting
- protected static int approximateTransportType(NetworkAgentInfo nai) {
- return nai.isVPN() ? TRANSPORT_VPN : getFirstTransportType(nai);
- }
-
- // TODO: deal more gracefully with multi-transport networks.
- private static int getFirstTransportType(NetworkAgentInfo nai) {
- // TODO: The range is wrong, the safer and correct way is to change the range from
- // MIN_TRANSPORT to MAX_TRANSPORT.
- for (int i = 0; i < 64; i++) {
- if (nai.networkCapabilities.hasTransport(i)) return i;
- }
- return -1;
- }
-
- private String getTransportName(final int transportType) {
- String[] networkTypes = mResources.get().getStringArray(R.array.network_switch_type_name);
- try {
- return networkTypes[transportType];
- } catch (IndexOutOfBoundsException e) {
- return mResources.get().getString(R.string.network_switch_type_name_unknown);
- }
- }
-
- private static int getIcon(int transportType) {
- return (transportType == TRANSPORT_WIFI)
- ? R.drawable.stat_notify_wifi_in_range // TODO: Distinguish ! from ?.
- : R.drawable.stat_notify_rssi_in_range;
- }
-
- /**
- * Show or hide network provisioning notifications.
- *
- * We use notifications for two purposes: to notify that a network requires sign in
- * (NotificationType.SIGN_IN), or to notify that a network does not have Internet access
- * (NotificationType.NO_INTERNET). We display at most one notification per ID, so on a
- * particular network we can display the notification type that was most recently requested.
- * So for example if a captive portal fails to reply within a few seconds of connecting, we
- * might first display NO_INTERNET, and then when the captive portal check completes, display
- * SIGN_IN.
- *
- * @param id an identifier that uniquely identifies this notification. This must match
- * between show and hide calls. We use the NetID value but for legacy callers
- * we concatenate the range of types with the range of NetIDs.
- * @param notifyType the type of the notification.
- * @param nai the network with which the notification is associated. For a SIGN_IN, NO_INTERNET,
- * or LOST_INTERNET notification, this is the network we're connecting to. For a
- * NETWORK_SWITCH notification it's the network that we switched from. When this network
- * disconnects the notification is removed.
- * @param switchToNai for a NETWORK_SWITCH notification, the network we are switching to. Null
- * in all other cases. Only used to determine the text of the notification.
- */
- public void showNotification(int id, NotificationType notifyType, NetworkAgentInfo nai,
- NetworkAgentInfo switchToNai, PendingIntent intent, boolean highPriority) {
- final String tag = tagFor(id);
- final int eventId = notifyType.eventId;
- final int transportType;
- final CharSequence name;
- if (nai != null) {
- transportType = approximateTransportType(nai);
- final String extraInfo = nai.networkInfo.getExtraInfo();
- if (nai.linkProperties != null && nai.linkProperties.getCaptivePortalData() != null
- && !TextUtils.isEmpty(nai.linkProperties.getCaptivePortalData()
- .getVenueFriendlyName())) {
- name = nai.linkProperties.getCaptivePortalData().getVenueFriendlyName();
- } else {
- name = TextUtils.isEmpty(extraInfo)
- ? WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()) : extraInfo;
- }
- // Only notify for Internet-capable networks.
- if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)) return;
- } else {
- // Legacy notifications.
- transportType = TRANSPORT_CELLULAR;
- name = "";
- }
-
- // Clear any previous notification with lower priority, otherwise return. http://b/63676954.
- // A new SIGN_IN notification with a new intent should override any existing one.
- final int previousEventId = mNotificationTypeMap.get(id);
- final NotificationType previousNotifyType = NotificationType.getFromId(previousEventId);
- if (priority(previousNotifyType) > priority(notifyType)) {
- Log.d(TAG, String.format(
- "ignoring notification %s for network %s with existing notification %s",
- notifyType, id, previousNotifyType));
- return;
- }
- clearNotification(id);
-
- if (DBG) {
- Log.d(TAG, String.format(
- "showNotification tag=%s event=%s transport=%s name=%s highPriority=%s",
- tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
- }
-
- final Resources r = mResources.get();
- final CharSequence title;
- final CharSequence details;
- Icon icon = Icon.createWithResource(
- mResources.getResourcesContext(), getIcon(transportType));
- if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
- title = r.getString(R.string.wifi_no_internet, name);
- details = r.getString(R.string.wifi_no_internet_detailed);
- } else if (notifyType == NotificationType.PRIVATE_DNS_BROKEN) {
- if (transportType == TRANSPORT_CELLULAR) {
- title = r.getString(R.string.mobile_no_internet);
- } else if (transportType == TRANSPORT_WIFI) {
- title = r.getString(R.string.wifi_no_internet, name);
- } else {
- title = r.getString(R.string.other_networks_no_internet);
- }
- details = r.getString(R.string.private_dns_broken_detailed);
- } else if (notifyType == NotificationType.PARTIAL_CONNECTIVITY
- && transportType == TRANSPORT_WIFI) {
- title = r.getString(R.string.network_partial_connectivity, name);
- details = r.getString(R.string.network_partial_connectivity_detailed);
- } else if (notifyType == NotificationType.LOST_INTERNET &&
- transportType == TRANSPORT_WIFI) {
- title = r.getString(R.string.wifi_no_internet, name);
- details = r.getString(R.string.wifi_no_internet_detailed);
- } else if (notifyType == NotificationType.SIGN_IN) {
- switch (transportType) {
- case TRANSPORT_WIFI:
- title = r.getString(R.string.wifi_available_sign_in, 0);
- details = r.getString(R.string.network_available_sign_in_detailed, name);
- break;
- case TRANSPORT_CELLULAR:
- title = r.getString(R.string.network_available_sign_in, 0);
- // TODO: Change this to pull from NetworkInfo once a printable
- // name has been added to it
- NetworkSpecifier specifier = nai.networkCapabilities.getNetworkSpecifier();
- int subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
- if (specifier instanceof TelephonyNetworkSpecifier) {
- subId = ((TelephonyNetworkSpecifier) specifier).getSubscriptionId();
- }
-
- details = mTelephonyManager.createForSubscriptionId(subId)
- .getNetworkOperatorName();
- break;
- default:
- title = r.getString(R.string.network_available_sign_in, 0);
- details = r.getString(R.string.network_available_sign_in_detailed, name);
- break;
- }
- } else if (notifyType == NotificationType.NETWORK_SWITCH) {
- String fromTransport = getTransportName(transportType);
- String toTransport = getTransportName(approximateTransportType(switchToNai));
- title = r.getString(R.string.network_switch_metered, toTransport);
- details = r.getString(R.string.network_switch_metered_detail, toTransport,
- fromTransport);
- } else if (notifyType == NotificationType.NO_INTERNET
- || notifyType == NotificationType.PARTIAL_CONNECTIVITY) {
- // NO_INTERNET and PARTIAL_CONNECTIVITY notification for non-WiFi networks
- // are sent, but they are not implemented yet.
- return;
- } else {
- Log.wtf(TAG, "Unknown notification type " + notifyType + " on network transport "
- + getTransportName(transportType));
- return;
- }
- // When replacing an existing notification for a given network, don't alert, just silently
- // update the existing notification. Note that setOnlyAlertOnce() will only work for the
- // same id, and the id used here is the NotificationType which is different in every type of
- // notification. This is required because the notification metrics only track the ID but not
- // the tag.
- final boolean hasPreviousNotification = previousNotifyType != null;
- final String channelId = (highPriority && !hasPreviousNotification)
- ? NOTIFICATION_CHANNEL_NETWORK_ALERTS : NOTIFICATION_CHANNEL_NETWORK_STATUS;
- Notification.Builder builder = new Notification.Builder(mContext, channelId)
- .setWhen(System.currentTimeMillis())
- .setShowWhen(notifyType == NotificationType.NETWORK_SWITCH)
- .setSmallIcon(icon)
- .setAutoCancel(true)
- .setTicker(title)
- .setColor(mContext.getColor(android.R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentIntent(intent)
- .setLocalOnly(true)
- .setOnlyAlertOnce(true)
- // TODO: consider having action buttons to disconnect on the sign-in notification
- // especially if it is ongoing
- .setOngoing(notifyType == NotificationType.SIGN_IN
- && r.getBoolean(R.bool.config_ongoingSignInNotification));
-
- if (notifyType == NotificationType.NETWORK_SWITCH) {
- builder.setStyle(new Notification.BigTextStyle().bigText(details));
- } else {
- builder.setContentText(details);
- }
-
- if (notifyType == NotificationType.SIGN_IN) {
- builder.extend(new Notification.TvExtender().setChannelId(channelId));
- }
-
- Notification notification = builder.build();
-
- mNotificationTypeMap.put(id, eventId);
- try {
- mNotificationManager.notify(tag, eventId, notification);
- } catch (NullPointerException npe) {
- Log.d(TAG, "setNotificationVisible: visible notificationManager error", npe);
- }
- }
-
- /**
- * Clear the notification with the given id, only if it matches the given type.
- */
- public void clearNotification(int id, NotificationType notifyType) {
- final int previousEventId = mNotificationTypeMap.get(id);
- final NotificationType previousNotifyType = NotificationType.getFromId(previousEventId);
- if (notifyType != previousNotifyType) {
- return;
- }
- clearNotification(id);
- }
-
- public void clearNotification(int id) {
- if (mNotificationTypeMap.indexOfKey(id) < 0) {
- return;
- }
- final String tag = tagFor(id);
- final int eventId = mNotificationTypeMap.get(id);
- if (DBG) {
- Log.d(TAG, String.format("clearing notification tag=%s event=%s", tag,
- nameOf(eventId)));
- }
- try {
- mNotificationManager.cancel(tag, eventId);
- } catch (NullPointerException npe) {
- Log.d(TAG, String.format(
- "failed to clear notification tag=%s event=%s", tag, nameOf(eventId)), npe);
- }
- mNotificationTypeMap.delete(id);
- }
-
- /**
- * Legacy provisioning notifications coming directly from DcTracker.
- */
- public void setProvNotificationVisible(boolean visible, int id, String action) {
- if (visible) {
- // For legacy purposes, action is sent as the action + the phone ID from DcTracker.
- // Split the string here and send the phone ID as an extra instead.
- String[] splitAction = action.split(":");
- Intent intent = new Intent(splitAction[0]);
- try {
- intent.putExtra("provision.phone.id", Integer.parseInt(splitAction[1]));
- } catch (NumberFormatException ignored) { }
- PendingIntent pendingIntent = PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE);
- showNotification(id, NotificationType.SIGN_IN, null, null, pendingIntent, false);
- } else {
- clearNotification(id);
- }
- }
-
- public void showToast(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
- String fromTransport = getTransportName(approximateTransportType(fromNai));
- String toTransport = getTransportName(approximateTransportType(toNai));
- String text = mResources.get().getString(
- R.string.network_switch_metered_toast, fromTransport, toTransport);
- Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
- }
-
- @VisibleForTesting
- static String tagFor(int id) {
- return String.format("ConnectivityNotification:%d", id);
- }
-
- @VisibleForTesting
- static String nameOf(int eventId) {
- NotificationType t = NotificationType.getFromId(eventId);
- return (t != null) ? t.name() : "UNKNOWN";
- }
-
- /**
- * A notification with a higher number will take priority over a notification with a lower
- * number.
- */
- private static int priority(NotificationType t) {
- if (t == null) {
- return 0;
- }
- switch (t) {
- case SIGN_IN:
- return 6;
- case PARTIAL_CONNECTIVITY:
- return 5;
- case PRIVATE_DNS_BROKEN:
- return 4;
- case NO_INTERNET:
- return 3;
- case NETWORK_SWITCH:
- return 2;
- case LOST_INTERNET:
- return 1;
- default:
- return 0;
- }
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/NetworkOffer.java b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkOffer.java
deleted file mode 100644
index 8285e7a..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/NetworkOffer.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import android.annotation.NonNull;
-import android.net.INetworkOfferCallback;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
-import android.os.RemoteException;
-
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * Represents an offer made by a NetworkProvider to create a network if a need arises.
- *
- * This class contains the prospective score and capabilities of the network. The provider
- * is not obligated to caps able to create a network satisfying this, nor to build a network
- * with the exact score and/or capabilities passed ; after all, not all providers know in
- * advance what a network will look like after it's connected. Instead, this is meant as a
- * filter to limit requests sent to the provider by connectivity to those that this offer stands
- * a chance to fulfill.
- *
- * @see NetworkProvider#offerNetwork.
- *
- * @hide
- */
-public class NetworkOffer implements NetworkRanker.Scoreable {
- @NonNull public final FullScore score;
- @NonNull public final NetworkCapabilities caps;
- @NonNull public final INetworkOfferCallback callback;
- @NonNull public final int providerId;
- // While this could, in principle, be deduced from the old values of the satisfying networks,
- // doing so would add a lot of complexity and performance penalties. For each request, the
- // ranker would have to run again to figure out if this offer used to be able to beat the
- // previous satisfier to know if there is a change in whether this offer is now needed ;
- // besides, there would be a need to handle an edge case when a new request comes online,
- // where it's not satisfied before the first rematch, where starting to satisfy a request
- // should not result in sending unneeded to this offer. This boolean, while requiring that
- // the offers are only ever manipulated on the CS thread, is by far a simpler and
- // economical solution.
- private final Set<NetworkRequest> mCurrentlyNeeded = new HashSet<>();
-
- public NetworkOffer(@NonNull final FullScore score,
- @NonNull final NetworkCapabilities caps,
- @NonNull final INetworkOfferCallback callback,
- @NonNull final int providerId) {
- this.score = Objects.requireNonNull(score);
- this.caps = Objects.requireNonNull(caps);
- this.callback = Objects.requireNonNull(callback);
- this.providerId = providerId;
- }
-
- /**
- * Get the score filter of this offer
- */
- @Override @NonNull public FullScore getScore() {
- return score;
- }
-
- /**
- * Get the capabilities filter of this offer
- */
- @Override @NonNull public NetworkCapabilities getCapsNoCopy() {
- return caps;
- }
-
- /**
- * Tell the provider for this offer that the network is needed for a request.
- * @param request the request for which the offer is needed
- */
- public void onNetworkNeeded(@NonNull final NetworkRequest request) {
- if (mCurrentlyNeeded.contains(request)) {
- throw new IllegalStateException("Network already needed");
- }
- mCurrentlyNeeded.add(request);
- try {
- callback.onNetworkNeeded(request);
- } catch (final RemoteException e) {
- // The provider is dead. It will be removed by the death recipient.
- }
- }
-
- /**
- * Tell the provider for this offer that the network is no longer needed for this request.
- *
- * onNetworkNeeded will have been called with the same request before.
- *
- * @param request the request
- */
- public void onNetworkUnneeded(@NonNull final NetworkRequest request) {
- if (!mCurrentlyNeeded.contains(request)) {
- throw new IllegalStateException("Network already unneeded");
- }
- mCurrentlyNeeded.remove(request);
- try {
- callback.onNetworkUnneeded(request);
- } catch (final RemoteException e) {
- // The provider is dead. It will be removed by the death recipient.
- }
- }
-
- /**
- * Returns whether this offer is currently needed for this request.
- * @param request the request
- * @return whether the offer is currently considered needed
- */
- public boolean neededFor(@NonNull final NetworkRequest request) {
- return mCurrentlyNeeded.contains(request);
- }
-
- /**
- * Migrate from, and take over, a previous offer.
- *
- * When an updated offer is sent from a provider, call this method on the new offer, passing
- * the old one, to take over the state.
- *
- * @param previousOffer the previous offer
- */
- public void migrateFrom(@NonNull final NetworkOffer previousOffer) {
- if (!callback.asBinder().equals(previousOffer.callback.asBinder())) {
- throw new IllegalArgumentException("Can only migrate from a previous version of"
- + " the same offer");
- }
- mCurrentlyNeeded.clear();
- mCurrentlyNeeded.addAll(previousOffer.mCurrentlyNeeded);
- }
-
- @Override
- public String toString() {
- return "NetworkOffer [ Score " + score + " ]";
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/NetworkRanker.java b/packages/Connectivity/service/src/com/android/server/connectivity/NetworkRanker.java
deleted file mode 100644
index d7eb9c8..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/NetworkRanker.java
+++ /dev/null
@@ -1,351 +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 com.android.server.connectivity;
-
-import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static android.net.NetworkScore.POLICY_EXITING;
-import static android.net.NetworkScore.POLICY_TRANSPORT_PRIMARY;
-import static android.net.NetworkScore.POLICY_YIELD_TO_BAD_WIFI;
-
-import static com.android.net.module.util.CollectionUtils.filter;
-import static com.android.server.connectivity.FullScore.POLICY_ACCEPT_UNVALIDATED;
-import static com.android.server.connectivity.FullScore.POLICY_EVER_USER_SELECTED;
-import static com.android.server.connectivity.FullScore.POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD;
-import static com.android.server.connectivity.FullScore.POLICY_IS_INVINCIBLE;
-import static com.android.server.connectivity.FullScore.POLICY_IS_VALIDATED;
-import static com.android.server.connectivity.FullScore.POLICY_IS_VPN;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
-
-import com.android.net.module.util.CollectionUtils;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.function.Predicate;
-
-/**
- * A class that knows how to find the best network matching a request out of a list of networks.
- */
-public class NetworkRanker {
- // Historically the legacy ints have been 0~100 in principle (though the highest score in
- // AOSP has always been 90). This is relied on by VPNs that send a legacy score of 101.
- public static final int LEGACY_INT_MAX = 100;
-
- /**
- * A class that can be scored against other scoreables.
- */
- public interface Scoreable {
- /** Get score of this scoreable */
- FullScore getScore();
- /** Get capabilities of this scoreable */
- NetworkCapabilities getCapsNoCopy();
- }
-
- private static final boolean USE_POLICY_RANKING = true;
-
- public NetworkRanker() { }
-
- /**
- * Find the best network satisfying this request among the list of passed networks.
- */
- @Nullable
- public NetworkAgentInfo getBestNetwork(@NonNull final NetworkRequest request,
- @NonNull final Collection<NetworkAgentInfo> nais,
- @Nullable final NetworkAgentInfo currentSatisfier) {
- final ArrayList<NetworkAgentInfo> candidates = filter(nais, nai -> nai.satisfies(request));
- if (candidates.size() == 1) return candidates.get(0); // Only one potential satisfier
- if (candidates.size() <= 0) return null; // No network can satisfy this request
- if (USE_POLICY_RANKING) {
- return getBestNetworkByPolicy(candidates, currentSatisfier);
- } else {
- return getBestNetworkByLegacyInt(candidates);
- }
- }
-
- // Transport preference order, if it comes down to that.
- private static final int[] PREFERRED_TRANSPORTS_ORDER = { TRANSPORT_ETHERNET, TRANSPORT_WIFI,
- TRANSPORT_BLUETOOTH, TRANSPORT_CELLULAR };
-
- // Function used to partition a list into two working areas depending on whether they
- // satisfy a predicate. All items satisfying the predicate will be put in |positive|, all
- // items that don't will be put in |negative|.
- // This is useful in this file because many of the ranking checks will retain only networks that
- // satisfy a predicate if any of them do, but keep them all if all of them do. Having working
- // areas is uncustomary in Java, but this function is called in a fairly intensive manner
- // and doing allocation quite that often might affect performance quite badly.
- private static <T> void partitionInto(@NonNull final List<T> source, @NonNull Predicate<T> test,
- @NonNull final List<T> positive, @NonNull final List<T> negative) {
- positive.clear();
- negative.clear();
- for (final T item : source) {
- if (test.test(item)) {
- positive.add(item);
- } else {
- negative.add(item);
- }
- }
- }
-
- private <T extends Scoreable> boolean isBadWiFi(@NonNull final T candidate) {
- return candidate.getScore().hasPolicy(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD)
- && candidate.getCapsNoCopy().hasTransport(TRANSPORT_WIFI);
- }
-
- /**
- * Apply the "yield to bad WiFi" policy.
- *
- * This function must run immediately after the validation policy.
- *
- * If any of the accepted networks has the "yield to bad WiFi" policy AND there are some
- * bad WiFis in the rejected list, then move the networks with the policy to the rejected
- * list. If this leaves no accepted network, then move the bad WiFis back to the accepted list.
- *
- * This function returns nothing, but will have updated accepted and rejected in-place.
- *
- * @param accepted networks accepted by the validation policy
- * @param rejected networks rejected by the validation policy
- */
- private <T extends Scoreable> void applyYieldToBadWifiPolicy(@NonNull ArrayList<T> accepted,
- @NonNull ArrayList<T> rejected) {
- if (!CollectionUtils.any(accepted, n -> n.getScore().hasPolicy(POLICY_YIELD_TO_BAD_WIFI))) {
- // No network with the policy : do nothing.
- return;
- }
- if (!CollectionUtils.any(rejected, n -> isBadWiFi(n))) {
- // No bad WiFi : do nothing.
- return;
- }
- if (CollectionUtils.all(accepted, n -> n.getScore().hasPolicy(POLICY_YIELD_TO_BAD_WIFI))) {
- // All validated networks yield to bad WiFis : keep bad WiFis alongside with the
- // yielders. This is important because the yielders need to be compared to the bad
- // wifis by the following policies (e.g. exiting).
- final ArrayList<T> acceptedYielders = new ArrayList<>(accepted);
- final ArrayList<T> rejectedWithBadWiFis = new ArrayList<>(rejected);
- partitionInto(rejectedWithBadWiFis, n -> isBadWiFi(n), accepted, rejected);
- accepted.addAll(acceptedYielders);
- return;
- }
- // Only some of the validated networks yield to bad WiFi : keep only the ones who don't.
- final ArrayList<T> acceptedWithYielders = new ArrayList<>(accepted);
- partitionInto(acceptedWithYielders, n -> !n.getScore().hasPolicy(POLICY_YIELD_TO_BAD_WIFI),
- accepted, rejected);
- }
-
- /**
- * Get the best network among a list of candidates according to policy.
- * @param candidates the candidates
- * @param currentSatisfier the current satisfier, or null if none
- * @return the best network
- */
- @Nullable public <T extends Scoreable> T getBestNetworkByPolicy(
- @NonNull List<T> candidates,
- @Nullable final T currentSatisfier) {
- // Used as working areas.
- final ArrayList<T> accepted =
- new ArrayList<>(candidates.size() /* initialCapacity */);
- final ArrayList<T> rejected =
- new ArrayList<>(candidates.size() /* initialCapacity */);
-
- // The following tests will search for a network matching a given criterion. They all
- // function the same way : if any network matches the criterion, drop from consideration
- // all networks that don't. To achieve this, the tests below :
- // 1. partition the list of remaining candidates into accepted and rejected networks.
- // 2. if only one candidate remains, that's the winner : if accepted.size == 1 return [0]
- // 3. if multiple remain, keep only the accepted networks and go on to the next criterion.
- // Because the working areas will be wiped, a copy of the accepted networks needs to be
- // made.
- // 4. if none remain, the criterion did not help discriminate so keep them all. As an
- // optimization, skip creating a new array and go on to the next criterion.
-
- // If a network is invincible, use it.
- partitionInto(candidates, nai -> nai.getScore().hasPolicy(POLICY_IS_INVINCIBLE),
- accepted, rejected);
- if (accepted.size() == 1) return accepted.get(0);
- if (accepted.size() > 0 && rejected.size() > 0) candidates = new ArrayList<>(accepted);
-
- // If there is a connected VPN, use it.
- partitionInto(candidates, nai -> nai.getScore().hasPolicy(POLICY_IS_VPN),
- accepted, rejected);
- if (accepted.size() == 1) return accepted.get(0);
- if (accepted.size() > 0 && rejected.size() > 0) candidates = new ArrayList<>(accepted);
-
- // Selected & Accept-unvalidated policy : if any network has both of these, then don't
- // choose one that doesn't.
- partitionInto(candidates, nai -> nai.getScore().hasPolicy(POLICY_EVER_USER_SELECTED)
- && nai.getScore().hasPolicy(POLICY_ACCEPT_UNVALIDATED),
- accepted, rejected);
- if (accepted.size() == 1) return accepted.get(0);
- if (accepted.size() > 0 && rejected.size() > 0) candidates = new ArrayList<>(accepted);
-
- // If any network is validated (or should be accepted even if it's not validated), then
- // don't choose one that isn't.
- partitionInto(candidates, nai -> nai.getScore().hasPolicy(POLICY_IS_VALIDATED)
- || nai.getScore().hasPolicy(POLICY_ACCEPT_UNVALIDATED),
- accepted, rejected);
- // Yield to bad wifi policy : if any network has the "yield to bad WiFi" policy and
- // there are bad WiFis connected, then accept the bad WiFis and reject the networks with
- // the policy.
- applyYieldToBadWifiPolicy(accepted, rejected);
- if (accepted.size() == 1) return accepted.get(0);
- if (accepted.size() > 0 && rejected.size() > 0) candidates = new ArrayList<>(accepted);
-
- // If any network is not exiting, don't choose one that is.
- partitionInto(candidates, nai -> !nai.getScore().hasPolicy(POLICY_EXITING),
- accepted, rejected);
- if (accepted.size() == 1) return accepted.get(0);
- if (accepted.size() > 0 && rejected.size() > 0) candidates = new ArrayList<>(accepted);
-
- // TODO : If any network is unmetered, don't choose a metered network.
- // This can't be implemented immediately because prospective networks are always
- // considered unmetered because factories don't know if the network will be metered.
- // Saying an unmetered network always beats a metered one would mean that when metered wifi
- // is connected, the offer for telephony would beat WiFi but the actual metered network
- // would lose, so we'd have an infinite loop where telephony would continually bring up
- // a network that is immediately torn down.
- // Fix this by getting the agent to tell connectivity whether the network they will
- // bring up is metered. Cell knows that in advance, while WiFi has a good estimate and
- // can revise it if the network later turns out to be metered.
- // partitionInto(candidates, nai -> nai.getScore().hasPolicy(POLICY_IS_UNMETERED),
- // accepted, rejected);
- // if (accepted.size() == 1) return accepted.get(0);
- // if (accepted.size() > 0 && rejected.size() > 0) candidates = new ArrayList<>(accepted);
-
- // If any network is for the default subscription, don't choose a network for another
- // subscription with the same transport.
- partitionInto(candidates, nai -> nai.getScore().hasPolicy(POLICY_TRANSPORT_PRIMARY),
- accepted, rejected);
- if (accepted.size() > 0) {
- // Some networks are primary for their transport. For each transport, keep only the
- // primary, but also keep all networks for which there isn't a primary (which are now
- // in the |rejected| array).
- // So for each primary network, remove from |rejected| all networks with the same
- // transports as one of the primary networks. The remaining networks should be accepted.
- for (final T defaultSubNai : accepted) {
- final int[] transports = defaultSubNai.getCapsNoCopy().getTransportTypes();
- rejected.removeIf(
- nai -> Arrays.equals(transports, nai.getCapsNoCopy().getTransportTypes()));
- }
- // Now the |rejected| list contains networks with transports for which there isn't
- // a primary network. Add them back to the candidates.
- accepted.addAll(rejected);
- candidates = new ArrayList<>(accepted);
- }
- if (1 == candidates.size()) return candidates.get(0);
- // If there were no primary network, then candidates.size() > 0 because it didn't
- // change from the previous result. If there were, it's guaranteed candidates.size() > 0
- // because accepted.size() > 0 above.
-
- // If some of the networks have a better transport than others, keep only the ones with
- // the best transports.
- for (final int transport : PREFERRED_TRANSPORTS_ORDER) {
- partitionInto(candidates, nai -> nai.getCapsNoCopy().hasTransport(transport),
- accepted, rejected);
- if (accepted.size() == 1) return accepted.get(0);
- if (accepted.size() > 0 && rejected.size() > 0) {
- candidates = new ArrayList<>(accepted);
- break;
- }
- }
-
- // At this point there are still multiple networks passing all the tests above. If any
- // of them is the previous satisfier, keep it.
- if (candidates.contains(currentSatisfier)) return currentSatisfier;
-
- // If there are still multiple options at this point but none of them is any of the
- // transports above, it doesn't matter which is returned. They are all the same.
- return candidates.get(0);
- }
-
- // TODO : switch to the policy implementation and remove
- // Almost equivalent to Collections.max(nais), but allows returning null if no network
- // satisfies the request.
- private NetworkAgentInfo getBestNetworkByLegacyInt(
- @NonNull final Collection<NetworkAgentInfo> nais) {
- NetworkAgentInfo bestNetwork = null;
- int bestScore = Integer.MIN_VALUE;
- for (final NetworkAgentInfo nai : nais) {
- final int naiScore = nai.getCurrentScore();
- if (naiScore > bestScore) {
- bestNetwork = nai;
- bestScore = naiScore;
- }
- }
- return bestNetwork;
- }
-
- /**
- * Returns whether a {@link Scoreable} has a chance to beat a champion network for a request.
- *
- * Offers are sent by network providers when they think they might be able to make a network
- * with the characteristics contained in the offer. If the offer has no chance to beat
- * the currently best network for a given request, there is no point in the provider spending
- * power trying to find and bring up such a network.
- *
- * Note that having an offer up does not constitute a commitment from the provider part
- * to be able to bring up a network with these characteristics, or a network at all for
- * that matter. This is only used to save power by letting providers know when they can't
- * beat a current champion.
- *
- * @param request The request to evaluate against.
- * @param champion The currently best network for this request.
- * @param contestant The offer.
- * @return Whether the offer stands a chance to beat the champion.
- */
- public boolean mightBeat(@NonNull final NetworkRequest request,
- @Nullable final NetworkAgentInfo champion,
- @NonNull final Scoreable contestant) {
- // If this network can't even satisfy the request then it can't beat anything, not
- // even an absence of network. It can't satisfy it anyway.
- if (!request.canBeSatisfiedBy(contestant.getCapsNoCopy())) return false;
- // If there is no satisfying network, then this network can beat, because some network
- // is always better than no network.
- if (null == champion) return true;
- if (USE_POLICY_RANKING) {
- // If there is no champion, the offer can always beat.
- // Otherwise rank them.
- final ArrayList<Scoreable> candidates = new ArrayList<>();
- candidates.add(champion);
- candidates.add(contestant);
- return contestant == getBestNetworkByPolicy(candidates, champion);
- } else {
- return mightBeatByLegacyInt(champion.getScore(), contestant);
- }
- }
-
- /**
- * Returns whether a contestant might beat a champion according to the legacy int.
- */
- private boolean mightBeatByLegacyInt(@Nullable final FullScore championScore,
- @NonNull final Scoreable contestant) {
- final int offerIntScore;
- if (contestant.getCapsNoCopy().hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
- // If the offer might have Internet access, then it might validate.
- offerIntScore = contestant.getScore().getLegacyIntAsValidated();
- } else {
- offerIntScore = contestant.getScore().getLegacyInt();
- }
- return championScore.getLegacyInt() < offerIntScore;
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/OsCompat.java b/packages/Connectivity/service/src/com/android/server/connectivity/OsCompat.java
deleted file mode 100644
index 57e3dcd..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/OsCompat.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import android.system.ErrnoException;
-import android.system.Os;
-
-import java.io.FileDescriptor;
-
-/**
- * Compatibility utility for android.system.Os core platform APIs.
- *
- * Connectivity has access to such APIs, but they are not part of the module_current stubs yet
- * (only core_current). Most stable core platform APIs are included manually in the connectivity
- * build rules, but because Os is also part of the base java SDK that is earlier on the
- * classpath, the extra core platform APIs are not seen.
- *
- * TODO (b/157639992, b/183097033): remove as soon as core_current is part of system_server_current
- * @hide
- */
-public class OsCompat {
- // This value should be correct on all architectures supported by Android, but hardcoding ioctl
- // numbers should be avoided.
- /**
- * @see android.system.OsConstants#TIOCOUTQ
- */
- public static final int TIOCOUTQ = 0x5411;
-
- /**
- * @see android.system.Os#getsockoptInt(FileDescriptor, int, int)
- */
- public static int getsockoptInt(FileDescriptor fd, int level, int option) throws
- ErrnoException {
- try {
- return (int) Os.class.getMethod(
- "getsockoptInt", FileDescriptor.class, int.class, int.class)
- .invoke(null, fd, level, option);
- } catch (ReflectiveOperationException e) {
- if (e.getCause() instanceof ErrnoException) {
- throw (ErrnoException) e.getCause();
- }
- throw new IllegalStateException("Error calling getsockoptInt", e);
- }
- }
-
- /**
- * @see android.system.Os#ioctlInt(FileDescriptor, int)
- */
- public static int ioctlInt(FileDescriptor fd, int cmd) throws
- ErrnoException {
- try {
- return (int) Os.class.getMethod(
- "ioctlInt", FileDescriptor.class, int.class).invoke(null, fd, cmd);
- } catch (ReflectiveOperationException e) {
- if (e.getCause() instanceof ErrnoException) {
- throw (ErrnoException) e.getCause();
- }
- throw new IllegalStateException("Error calling ioctlInt", e);
- }
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/PermissionMonitor.java b/packages/Connectivity/service/src/com/android/server/connectivity/PermissionMonitor.java
deleted file mode 100644
index 9bda59c..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/PermissionMonitor.java
+++ /dev/null
@@ -1,829 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.Manifest.permission.CHANGE_NETWORK_STATE;
-import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
-import static android.Manifest.permission.INTERNET;
-import static android.Manifest.permission.NETWORK_STACK;
-import static android.Manifest.permission.UPDATE_DEVICE_STATS;
-import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
-import static android.content.pm.PackageManager.GET_PERMISSIONS;
-import static android.content.pm.PackageManager.MATCH_ANY_USER;
-import static android.net.ConnectivitySettingsManager.APPS_ALLOWED_ON_RESTRICTED_NETWORKS;
-import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
-import static android.os.Process.INVALID_UID;
-import static android.os.Process.SYSTEM_UID;
-
-import static com.android.net.module.util.CollectionUtils.toIntArray;
-
-import android.annotation.NonNull;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.database.ContentObserver;
-import android.net.ConnectivitySettingsManager;
-import android.net.INetd;
-import android.net.UidRange;
-import android.net.Uri;
-import android.os.Build;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.os.SystemConfigManager;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.system.OsConstants;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.net.module.util.CollectionUtils;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-/**
- * A utility class to inform Netd of UID permisisons.
- * Does a mass update at boot and then monitors for app install/remove.
- *
- * @hide
- */
-public class PermissionMonitor {
- private static final String TAG = "PermissionMonitor";
- private static final boolean DBG = true;
- protected static final Boolean SYSTEM = Boolean.TRUE;
- protected static final Boolean NETWORK = Boolean.FALSE;
- private static final int VERSION_Q = Build.VERSION_CODES.Q;
-
- private final PackageManager mPackageManager;
- private final UserManager mUserManager;
- private final SystemConfigManager mSystemConfigManager;
- private final INetd mNetd;
- private final Dependencies mDeps;
- private final Context mContext;
-
- @GuardedBy("this")
- private final Set<UserHandle> mUsers = new HashSet<>();
-
- // Keys are app uids. Values are true for SYSTEM permission and false for NETWORK permission.
- @GuardedBy("this")
- private final Map<Integer, Boolean> mApps = new HashMap<>();
-
- // Keys are active non-bypassable and fully-routed VPN's interface name, Values are uid ranges
- // for apps under the VPN
- @GuardedBy("this")
- private final Map<String, Set<UidRange>> mVpnUidRanges = new HashMap<>();
-
- // A set of appIds for apps across all users on the device. We track appIds instead of uids
- // directly to reduce its size and also eliminate the need to update this set when user is
- // added/removed.
- @GuardedBy("this")
- private final Set<Integer> mAllApps = new HashSet<>();
-
- // A set of apps which are allowed to use restricted networks. These apps can't hold the
- // CONNECTIVITY_USE_RESTRICTED_NETWORKS permission because they can't be signature|privileged
- // apps. However, these apps should still be able to use restricted networks under certain
- // conditions (e.g. government app using emergency services). So grant netd system permission
- // to uids whose package name is listed in APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting.
- @GuardedBy("this")
- private final Set<String> mAppsAllowedOnRestrictedNetworks = new ArraySet<>();
-
- private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- final Uri packageData = intent.getData();
- final String packageName =
- packageData != null ? packageData.getSchemeSpecificPart() : null;
-
- if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
- onPackageAdded(packageName, uid);
- } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- onPackageRemoved(packageName, uid);
- } else {
- Log.wtf(TAG, "received unexpected intent: " + action);
- }
- }
- };
-
- /**
- * Dependencies of PermissionMonitor, for injection in tests.
- */
- @VisibleForTesting
- public static class Dependencies {
- /**
- * Get device first sdk version.
- */
- public int getDeviceFirstSdkInt() {
- return Build.VERSION.DEVICE_INITIAL_SDK_INT;
- }
-
- /**
- * Get apps allowed to use restricted networks via ConnectivitySettingsManager.
- */
- public Set<String> getAppsAllowedOnRestrictedNetworks(@NonNull Context context) {
- return ConnectivitySettingsManager.getAppsAllowedOnRestrictedNetworks(context);
- }
-
- /**
- * Register ContentObserver for given Uri.
- */
- public void registerContentObserver(@NonNull Context context, @NonNull Uri uri,
- boolean notifyForDescendants, @NonNull ContentObserver observer) {
- context.getContentResolver().registerContentObserver(
- uri, notifyForDescendants, observer);
- }
- }
-
- public PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd) {
- this(context, netd, new Dependencies());
- }
-
- @VisibleForTesting
- PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd,
- @NonNull final Dependencies deps) {
- mPackageManager = context.getPackageManager();
- mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
- mSystemConfigManager = context.getSystemService(SystemConfigManager.class);
- mNetd = netd;
- mDeps = deps;
- mContext = context;
- }
-
- // Intended to be called only once at startup, after the system is ready. Installs a broadcast
- // receiver to monitor ongoing UID changes, so this shouldn't/needn't be called again.
- public synchronized void startMonitoring() {
- log("Monitoring");
-
- final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
- final IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- intentFilter.addDataScheme("package");
- userAllContext.registerReceiver(
- mIntentReceiver, intentFilter, null /* broadcastPermission */,
- null /* scheduler */);
-
- // Register APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting observer
- mDeps.registerContentObserver(
- userAllContext,
- Settings.Secure.getUriFor(APPS_ALLOWED_ON_RESTRICTED_NETWORKS),
- false /* notifyForDescendants */,
- new ContentObserver(null) {
- @Override
- public void onChange(boolean selfChange) {
- onSettingChanged();
- }
- });
-
- // Read APPS_ALLOWED_ON_RESTRICTED_NETWORKS setting and update
- // mAppsAllowedOnRestrictedNetworks.
- updateAppsAllowedOnRestrictedNetworks(mDeps.getAppsAllowedOnRestrictedNetworks(mContext));
-
- List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS
- | MATCH_ANY_USER);
- if (apps == null) {
- loge("No apps");
- return;
- }
-
- SparseIntArray netdPermsUids = new SparseIntArray();
-
- for (PackageInfo app : apps) {
- int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID;
- if (uid < 0) {
- continue;
- }
- mAllApps.add(UserHandle.getAppId(uid));
-
- boolean isNetwork = hasNetworkPermission(app);
- boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
-
- if (isNetwork || hasRestrictedPermission) {
- Boolean permission = mApps.get(uid);
- // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
- // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
- if (permission == null || permission == NETWORK) {
- mApps.put(uid, hasRestrictedPermission);
- }
- }
-
- //TODO: unify the management of the permissions into one codepath.
- int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions,
- app.requestedPermissionsFlags);
- netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
- }
-
- mUsers.addAll(mUserManager.getUserHandles(true /* excludeDying */));
-
- final SparseArray<String> netdPermToSystemPerm = new SparseArray<>();
- netdPermToSystemPerm.put(INetd.PERMISSION_INTERNET, INTERNET);
- netdPermToSystemPerm.put(INetd.PERMISSION_UPDATE_DEVICE_STATS, UPDATE_DEVICE_STATS);
- for (int i = 0; i < netdPermToSystemPerm.size(); i++) {
- final int netdPermission = netdPermToSystemPerm.keyAt(i);
- final String systemPermission = netdPermToSystemPerm.valueAt(i);
- final int[] hasPermissionUids =
- mSystemConfigManager.getSystemPermissionUids(systemPermission);
- for (int j = 0; j < hasPermissionUids.length; j++) {
- final int uid = hasPermissionUids[j];
- netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
- }
- }
- log("Users: " + mUsers.size() + ", Apps: " + mApps.size());
- update(mUsers, mApps, true);
- sendPackagePermissionsToNetd(netdPermsUids);
- }
-
- @VisibleForTesting
- void updateAppsAllowedOnRestrictedNetworks(final Set<String> apps) {
- mAppsAllowedOnRestrictedNetworks.clear();
- mAppsAllowedOnRestrictedNetworks.addAll(apps);
- }
-
- @VisibleForTesting
- static boolean isVendorApp(@NonNull ApplicationInfo appInfo) {
- return appInfo.isVendor() || appInfo.isOem() || appInfo.isProduct();
- }
-
- @VisibleForTesting
- boolean isCarryoverPackage(final ApplicationInfo appInfo) {
- if (appInfo == null) return false;
- return (appInfo.targetSdkVersion < VERSION_Q && isVendorApp(appInfo))
- // Backward compatibility for b/114245686, on devices that launched before Q daemons
- // and apps running as the system UID are exempted from this check.
- || (appInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q);
- }
-
- @VisibleForTesting
- boolean isAppAllowedOnRestrictedNetworks(@NonNull final PackageInfo app) {
- // Check whether package name is in allowed on restricted networks app list. If so, this app
- // can have netd system permission.
- return mAppsAllowedOnRestrictedNetworks.contains(app.packageName);
- }
-
- @VisibleForTesting
- boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) {
- if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
- return false;
- }
- final int index = CollectionUtils.indexOf(app.requestedPermissions, permission);
- if (index < 0 || index >= app.requestedPermissionsFlags.length) return false;
- return (app.requestedPermissionsFlags[index] & REQUESTED_PERMISSION_GRANTED) != 0;
- }
-
- @VisibleForTesting
- boolean hasNetworkPermission(@NonNull final PackageInfo app) {
- return hasPermission(app, CHANGE_NETWORK_STATE);
- }
-
- @VisibleForTesting
- boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) {
- // TODO : remove carryover package check in the future(b/31479477). All apps should just
- // request the appropriate permission for their use case since android Q.
- return isCarryoverPackage(app.applicationInfo) || isAppAllowedOnRestrictedNetworks(app)
- || hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK)
- || hasPermission(app, NETWORK_STACK)
- || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
- }
-
- /** Returns whether the given uid has using background network permission. */
- public synchronized boolean hasUseBackgroundNetworksPermission(final int uid) {
- // Apps with any of the CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_INTERNAL or
- // CONNECTIVITY_USE_RESTRICTED_NETWORKS permission has the permission to use background
- // networks. mApps contains the result of checks for both hasNetworkPermission and
- // hasRestrictedNetworkPermission. If uid is in the mApps list that means uid has one of
- // permissions at least.
- return mApps.containsKey(uid);
- }
-
- /**
- * Returns whether the given uid has permission to use restricted networks.
- */
- public synchronized boolean hasRestrictedNetworksPermission(int uid) {
- return Boolean.TRUE.equals(mApps.get(uid));
- }
-
- private void update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add) {
- List<Integer> network = new ArrayList<>();
- List<Integer> system = new ArrayList<>();
- for (Entry<Integer, Boolean> app : apps.entrySet()) {
- List<Integer> list = app.getValue() ? system : network;
- for (UserHandle user : users) {
- if (user == null) continue;
-
- list.add(user.getUid(app.getKey()));
- }
- }
- try {
- if (add) {
- mNetd.networkSetPermissionForUser(INetd.PERMISSION_NETWORK, toIntArray(network));
- mNetd.networkSetPermissionForUser(INetd.PERMISSION_SYSTEM, toIntArray(system));
- } else {
- mNetd.networkClearPermissionForUser(toIntArray(network));
- mNetd.networkClearPermissionForUser(toIntArray(system));
- }
- } catch (RemoteException e) {
- loge("Exception when updating permissions: " + e);
- }
- }
-
- /**
- * Called when a user is added. See {link #ACTION_USER_ADDED}.
- *
- * @param user The integer userHandle of the added user. See {@link #EXTRA_USER_HANDLE}.
- *
- * @hide
- */
- public synchronized void onUserAdded(@NonNull UserHandle user) {
- mUsers.add(user);
-
- Set<UserHandle> users = new HashSet<>();
- users.add(user);
- update(users, mApps, true);
- }
-
- /**
- * Called when an user is removed. See {link #ACTION_USER_REMOVED}.
- *
- * @param user The integer userHandle of the removed user. See {@link #EXTRA_USER_HANDLE}.
- *
- * @hide
- */
- public synchronized void onUserRemoved(@NonNull UserHandle user) {
- mUsers.remove(user);
-
- Set<UserHandle> users = new HashSet<>();
- users.add(user);
- update(users, mApps, false);
- }
-
- @VisibleForTesting
- protected Boolean highestPermissionForUid(Boolean currentPermission, String name) {
- if (currentPermission == SYSTEM) {
- return currentPermission;
- }
- try {
- final PackageInfo app = mPackageManager.getPackageInfo(name,
- GET_PERMISSIONS | MATCH_ANY_USER);
- final boolean isNetwork = hasNetworkPermission(app);
- final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
- if (isNetwork || hasRestrictedPermission) {
- currentPermission = hasRestrictedPermission;
- }
- } catch (NameNotFoundException e) {
- // App not found.
- loge("NameNotFoundException " + name);
- }
- return currentPermission;
- }
-
- private int getPermissionForUid(final int uid) {
- int permission = INetd.PERMISSION_NONE;
- // Check all the packages for this UID. The UID has the permission if any of the
- // packages in it has the permission.
- final String[] packages = mPackageManager.getPackagesForUid(uid);
- if (packages != null && packages.length > 0) {
- for (String name : packages) {
- final PackageInfo app = getPackageInfo(name);
- if (app != null && app.requestedPermissions != null) {
- permission |= getNetdPermissionMask(app.requestedPermissions,
- app.requestedPermissionsFlags);
- }
- }
- } else {
- // The last package of this uid is removed from device. Clean the package up.
- permission = INetd.PERMISSION_UNINSTALLED;
- }
- return permission;
- }
-
- /**
- * Called when a package is added.
- *
- * @param packageName The name of the new package.
- * @param uid The uid of the new package.
- *
- * @hide
- */
- public synchronized void onPackageAdded(@NonNull final String packageName, final int uid) {
- // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
- // using appId instead of uid actually
- sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));
-
- // If multiple packages share a UID (cf: android:sharedUserId) and ask for different
- // permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
- final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName);
- if (permission != mApps.get(uid)) {
- mApps.put(uid, permission);
-
- Map<Integer, Boolean> apps = new HashMap<>();
- apps.put(uid, permission);
- update(mUsers, apps, true);
- }
-
- // If the newly-installed package falls within some VPN's uid range, update Netd with it.
- // This needs to happen after the mApps update above, since removeBypassingUids() depends
- // on mApps to check if the package can bypass VPN.
- for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
- if (UidRange.containsUid(vpn.getValue(), uid)) {
- final Set<Integer> changedUids = new HashSet<>();
- changedUids.add(uid);
- removeBypassingUids(changedUids, /* vpnAppUid */ -1);
- updateVpnUids(vpn.getKey(), changedUids, true);
- }
- }
- mAllApps.add(UserHandle.getAppId(uid));
- }
-
- private Boolean highestUidNetworkPermission(int uid) {
- Boolean permission = null;
- final String[] packages = mPackageManager.getPackagesForUid(uid);
- if (!CollectionUtils.isEmpty(packages)) {
- for (String name : packages) {
- permission = highestPermissionForUid(permission, name);
- if (permission == SYSTEM) {
- break;
- }
- }
- }
- return permission;
- }
-
- /**
- * Called when a package is removed.
- *
- * @param packageName The name of the removed package or null.
- * @param uid containing the integer uid previously assigned to the package.
- *
- * @hide
- */
- public synchronized void onPackageRemoved(@NonNull final String packageName, final int uid) {
- // TODO: Netd is using appId for checking traffic permission. Correct the methods that are
- // using appId instead of uid actually
- sendPackagePermissionsForUid(UserHandle.getAppId(uid), getPermissionForUid(uid));
-
- // If the newly-removed package falls within some VPN's uid range, update Netd with it.
- // This needs to happen before the mApps update below, since removeBypassingUids() depends
- // on mApps to check if the package can bypass VPN.
- for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
- if (UidRange.containsUid(vpn.getValue(), uid)) {
- final Set<Integer> changedUids = new HashSet<>();
- changedUids.add(uid);
- removeBypassingUids(changedUids, /* vpnAppUid */ -1);
- updateVpnUids(vpn.getKey(), changedUids, false);
- }
- }
- // If the package has been removed from all users on the device, clear it form mAllApps.
- if (mPackageManager.getNameForUid(uid) == null) {
- mAllApps.remove(UserHandle.getAppId(uid));
- }
-
- Map<Integer, Boolean> apps = new HashMap<>();
- final Boolean permission = highestUidNetworkPermission(uid);
- if (permission == SYSTEM) {
- // An app with this UID still has the SYSTEM permission.
- // Therefore, this UID must already have the SYSTEM permission.
- // Nothing to do.
- return;
- }
-
- if (permission == mApps.get(uid)) {
- // The permissions of this UID have not changed. Nothing to do.
- return;
- } else if (permission != null) {
- mApps.put(uid, permission);
- apps.put(uid, permission);
- update(mUsers, apps, true);
- } else {
- mApps.remove(uid);
- apps.put(uid, NETWORK); // doesn't matter which permission we pick here
- update(mUsers, apps, false);
- }
- }
-
- private static int getNetdPermissionMask(String[] requestedPermissions,
- int[] requestedPermissionsFlags) {
- int permissions = 0;
- if (requestedPermissions == null || requestedPermissionsFlags == null) return permissions;
- for (int i = 0; i < requestedPermissions.length; i++) {
- if (requestedPermissions[i].equals(INTERNET)
- && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
- permissions |= INetd.PERMISSION_INTERNET;
- }
- if (requestedPermissions[i].equals(UPDATE_DEVICE_STATS)
- && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
- permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS;
- }
- }
- return permissions;
- }
-
- private PackageInfo getPackageInfo(String packageName) {
- try {
- PackageInfo app = mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS
- | MATCH_ANY_USER);
- return app;
- } catch (NameNotFoundException e) {
- return null;
- }
- }
-
- /**
- * Called when a new set of UID ranges are added to an active VPN network
- *
- * @param iface The active VPN network's interface name
- * @param rangesToAdd The new UID ranges to be added to the network
- * @param vpnAppUid The uid of the VPN app
- */
- public synchronized void onVpnUidRangesAdded(@NonNull String iface, Set<UidRange> rangesToAdd,
- int vpnAppUid) {
- // Calculate the list of new app uids under the VPN due to the new UID ranges and update
- // Netd about them. Because mAllApps only contains appIds instead of uids, the result might
- // be an overestimation if an app is not installed on the user on which the VPN is running,
- // but that's safe.
- final Set<Integer> changedUids = intersectUids(rangesToAdd, mAllApps);
- removeBypassingUids(changedUids, vpnAppUid);
- updateVpnUids(iface, changedUids, true);
- if (mVpnUidRanges.containsKey(iface)) {
- mVpnUidRanges.get(iface).addAll(rangesToAdd);
- } else {
- mVpnUidRanges.put(iface, new HashSet<UidRange>(rangesToAdd));
- }
- }
-
- /**
- * Called when a set of UID ranges are removed from an active VPN network
- *
- * @param iface The VPN network's interface name
- * @param rangesToRemove Existing UID ranges to be removed from the VPN network
- * @param vpnAppUid The uid of the VPN app
- */
- public synchronized void onVpnUidRangesRemoved(@NonNull String iface,
- Set<UidRange> rangesToRemove, int vpnAppUid) {
- // Calculate the list of app uids that are no longer under the VPN due to the removed UID
- // ranges and update Netd about them.
- final Set<Integer> changedUids = intersectUids(rangesToRemove, mAllApps);
- removeBypassingUids(changedUids, vpnAppUid);
- updateVpnUids(iface, changedUids, false);
- Set<UidRange> existingRanges = mVpnUidRanges.getOrDefault(iface, null);
- if (existingRanges == null) {
- loge("Attempt to remove unknown vpn uid Range iface = " + iface);
- return;
- }
- existingRanges.removeAll(rangesToRemove);
- if (existingRanges.size() == 0) {
- mVpnUidRanges.remove(iface);
- }
- }
-
- /**
- * Compute the intersection of a set of UidRanges and appIds. Returns a set of uids
- * that satisfies:
- * 1. falls into one of the UidRange
- * 2. matches one of the appIds
- */
- private Set<Integer> intersectUids(Set<UidRange> ranges, Set<Integer> appIds) {
- Set<Integer> result = new HashSet<>();
- for (UidRange range : ranges) {
- for (int userId = range.getStartUser(); userId <= range.getEndUser(); userId++) {
- for (int appId : appIds) {
- final UserHandle handle = UserHandle.of(userId);
- if (handle == null) continue;
-
- final int uid = handle.getUid(appId);
- if (range.contains(uid)) {
- result.add(uid);
- }
- }
- }
- }
- return result;
- }
-
- /**
- * Remove all apps which can elect to bypass the VPN from the list of uids
- *
- * An app can elect to bypass the VPN if it hold SYSTEM permission, or if its the active VPN
- * app itself.
- *
- * @param uids The list of uids to operate on
- * @param vpnAppUid The uid of the VPN app
- */
- private void removeBypassingUids(Set<Integer> uids, int vpnAppUid) {
- uids.remove(vpnAppUid);
- uids.removeIf(uid -> mApps.getOrDefault(uid, NETWORK) == SYSTEM);
- }
-
- /**
- * Update netd about the list of uids that are under an active VPN connection which they cannot
- * bypass.
- *
- * This is to instruct netd to set up appropriate filtering rules for these uids, such that they
- * can only receive ingress packets from the VPN's tunnel interface (and loopback).
- *
- * @param iface the interface name of the active VPN connection
- * @param add {@code true} if the uids are to be added to the interface, {@code false} if they
- * are to be removed from the interface.
- */
- private void updateVpnUids(String iface, Set<Integer> uids, boolean add) {
- if (uids.size() == 0) {
- return;
- }
- try {
- if (add) {
- mNetd.firewallAddUidInterfaceRules(iface, toIntArray(uids));
- } else {
- mNetd.firewallRemoveUidInterfaceRules(toIntArray(uids));
- }
- } catch (ServiceSpecificException e) {
- // Silently ignore exception when device does not support eBPF, otherwise just log
- // the exception and do not crash
- if (e.errorCode != OsConstants.EOPNOTSUPP) {
- loge("Exception when updating permissions: ", e);
- }
- } catch (RemoteException e) {
- loge("Exception when updating permissions: ", e);
- }
- }
-
- /**
- * Called by PackageListObserver when a package is installed/uninstalled. Send the updated
- * permission information to netd.
- *
- * @param uid the app uid of the package installed
- * @param permissions the permissions the app requested and netd cares about.
- *
- * @hide
- */
- @VisibleForTesting
- void sendPackagePermissionsForUid(int uid, int permissions) {
- SparseIntArray netdPermissionsAppIds = new SparseIntArray();
- netdPermissionsAppIds.put(uid, permissions);
- sendPackagePermissionsToNetd(netdPermissionsAppIds);
- }
-
- /**
- * Called by packageManagerService to send IPC to netd. Grant or revoke the INTERNET
- * and/or UPDATE_DEVICE_STATS permission of the uids in array.
- *
- * @param netdPermissionsAppIds integer pairs of uids and the permission granted to it. If the
- * permission is 0, revoke all permissions of that uid.
- *
- * @hide
- */
- @VisibleForTesting
- void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
- if (mNetd == null) {
- Log.e(TAG, "Failed to get the netd service");
- return;
- }
- ArrayList<Integer> allPermissionAppIds = new ArrayList<>();
- ArrayList<Integer> internetPermissionAppIds = new ArrayList<>();
- ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
- ArrayList<Integer> noPermissionAppIds = new ArrayList<>();
- ArrayList<Integer> uninstalledAppIds = new ArrayList<>();
- for (int i = 0; i < netdPermissionsAppIds.size(); i++) {
- int permissions = netdPermissionsAppIds.valueAt(i);
- switch(permissions) {
- case (INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS):
- allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
- break;
- case INetd.PERMISSION_INTERNET:
- internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
- break;
- case INetd.PERMISSION_UPDATE_DEVICE_STATS:
- updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
- break;
- case INetd.PERMISSION_NONE:
- noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
- break;
- case INetd.PERMISSION_UNINSTALLED:
- uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
- break;
- default:
- Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
- + netdPermissionsAppIds.keyAt(i));
- }
- }
- try {
- // TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids()
- if (allPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(
- INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
- toIntArray(allPermissionAppIds));
- }
- if (internetPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
- toIntArray(internetPermissionAppIds));
- }
- if (updateStatsPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
- toIntArray(updateStatsPermissionAppIds));
- }
- if (noPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE,
- toIntArray(noPermissionAppIds));
- }
- if (uninstalledAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UNINSTALLED,
- toIntArray(uninstalledAppIds));
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Pass appId list of special permission failed." + e);
- }
- }
-
- /** Should only be used by unit tests */
- @VisibleForTesting
- public Set<UidRange> getVpnUidRanges(String iface) {
- return mVpnUidRanges.get(iface);
- }
-
- private synchronized void onSettingChanged() {
- // Step1. Update apps allowed to use restricted networks and compute the set of packages to
- // update.
- final Set<String> packagesToUpdate = new ArraySet<>(mAppsAllowedOnRestrictedNetworks);
- updateAppsAllowedOnRestrictedNetworks(mDeps.getAppsAllowedOnRestrictedNetworks(mContext));
- packagesToUpdate.addAll(mAppsAllowedOnRestrictedNetworks);
-
- final Map<Integer, Boolean> updatedApps = new HashMap<>();
- final Map<Integer, Boolean> removedApps = new HashMap<>();
-
- // Step2. For each package to update, find out its new permission.
- for (String app : packagesToUpdate) {
- final PackageInfo info = getPackageInfo(app);
- if (info == null || info.applicationInfo == null) continue;
-
- final int uid = info.applicationInfo.uid;
- final Boolean permission = highestUidNetworkPermission(uid);
-
- if (null == permission) {
- removedApps.put(uid, NETWORK); // Doesn't matter which permission is set here.
- mApps.remove(uid);
- } else {
- updatedApps.put(uid, permission);
- mApps.put(uid, permission);
- }
- }
-
- // Step3. Update or revoke permission for uids with netd.
- update(mUsers, updatedApps, true /* add */);
- update(mUsers, removedApps, false /* add */);
- }
-
- /** Dump info to dumpsys */
- public void dump(IndentingPrintWriter pw) {
- pw.println("Interface filtering rules:");
- pw.increaseIndent();
- for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
- pw.println("Interface: " + vpn.getKey());
- pw.println("UIDs: " + vpn.getValue().toString());
- pw.println();
- }
- pw.decreaseIndent();
- }
-
- private static void log(String s) {
- if (DBG) {
- Log.d(TAG, s);
- }
- }
-
- private static void loge(String s) {
- Log.e(TAG, s);
- }
-
- private static void loge(String s, Throwable e) {
- Log.e(TAG, s, e);
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/ProfileNetworkPreferences.java b/packages/Connectivity/service/src/com/android/server/connectivity/ProfileNetworkPreferences.java
deleted file mode 100644
index dd2815d..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/ProfileNetworkPreferences.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.NetworkCapabilities;
-import android.os.UserHandle;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * A data class containing all the per-profile network preferences.
- *
- * A given profile can only have one preference.
- */
-public class ProfileNetworkPreferences {
- /**
- * A single preference, as it applies to a given user profile.
- */
- public static class Preference {
- @NonNull public final UserHandle user;
- // Capabilities are only null when sending an object to remove the setting for a user
- @Nullable public final NetworkCapabilities capabilities;
-
- public Preference(@NonNull final UserHandle user,
- @Nullable final NetworkCapabilities capabilities) {
- this.user = user;
- this.capabilities = null == capabilities ? null : new NetworkCapabilities(capabilities);
- }
-
- /** toString */
- public String toString() {
- return "[ProfileNetworkPreference user=" + user + " caps=" + capabilities + "]";
- }
- }
-
- @NonNull public final List<Preference> preferences;
-
- public ProfileNetworkPreferences() {
- preferences = Collections.EMPTY_LIST;
- }
-
- private ProfileNetworkPreferences(@NonNull final List<Preference> list) {
- preferences = Collections.unmodifiableList(list);
- }
-
- /**
- * Returns a new object consisting of this object plus the passed preference.
- *
- * If a preference already exists for the same user, it will be replaced by the passed
- * preference. Passing a Preference object containing a null capabilities object is equivalent
- * to (and indeed, implemented as) removing the preference for this user.
- */
- public ProfileNetworkPreferences plus(@NonNull final Preference pref) {
- final ArrayList<Preference> newPrefs = new ArrayList<>();
- for (final Preference existingPref : preferences) {
- if (!existingPref.user.equals(pref.user)) {
- newPrefs.add(existingPref);
- }
- }
- if (null != pref.capabilities) {
- newPrefs.add(pref);
- }
- return new ProfileNetworkPreferences(newPrefs);
- }
-
- public boolean isEmpty() {
- return preferences.isEmpty();
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/ProxyTracker.java b/packages/Connectivity/service/src/com/android/server/connectivity/ProxyTracker.java
deleted file mode 100644
index bc0929c..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/ProxyTracker.java
+++ /dev/null
@@ -1,358 +0,0 @@
-/**
- * Copyright (c) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_EXCLUSION_LIST;
-import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_HOST;
-import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_PAC;
-import static android.net.ConnectivitySettingsManager.GLOBAL_HTTP_PROXY_PORT;
-import static android.provider.Settings.Global.HTTP_PROXY;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Network;
-import android.net.PacProxyManager;
-import android.net.Proxy;
-import android.net.ProxyInfo;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.net.module.util.ProxyUtils;
-
-import java.util.Collections;
-import java.util.Objects;
-
-/**
- * A class to handle proxy for ConnectivityService.
- *
- * @hide
- */
-public class ProxyTracker {
- private static final String TAG = ProxyTracker.class.getSimpleName();
- private static final boolean DBG = true;
-
- // EXTRA_PROXY_INFO is now @removed. In order to continue sending it, hardcode its value here.
- // The Proxy.EXTRA_PROXY_INFO constant is not visible to this code because android.net.Proxy
- // a hidden platform constant not visible to mainline modules.
- private static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
-
- @NonNull
- private final Context mContext;
-
- @NonNull
- private final Object mProxyLock = new Object();
- // The global proxy is the proxy that is set device-wide, overriding any network-specific
- // proxy. Note however that proxies are hints ; the system does not enforce their use. Hence
- // this value is only for querying.
- @Nullable
- @GuardedBy("mProxyLock")
- private ProxyInfo mGlobalProxy = null;
- // The default proxy is the proxy that applies to no particular network if the global proxy
- // is not set. Individual networks have their own settings that override this. This member
- // is set through setDefaultProxy, which is called when the default network changes proxies
- // in its LinkProperties, or when ConnectivityService switches to a new default network, or
- // when PacProxyService resolves the proxy.
- @Nullable
- @GuardedBy("mProxyLock")
- private volatile ProxyInfo mDefaultProxy = null;
- // Whether the default proxy is enabled.
- @GuardedBy("mProxyLock")
- private boolean mDefaultProxyEnabled = true;
-
- private final Handler mConnectivityServiceHandler;
-
- private final PacProxyManager mPacProxyManager;
-
- private class PacProxyInstalledListener implements PacProxyManager.PacProxyInstalledListener {
- private final int mEvent;
-
- PacProxyInstalledListener(int event) {
- mEvent = event;
- }
-
- public void onPacProxyInstalled(@Nullable Network network, @NonNull ProxyInfo proxy) {
- mConnectivityServiceHandler
- .sendMessage(mConnectivityServiceHandler
- .obtainMessage(mEvent, new Pair<>(network, proxy)));
- }
- }
-
- public ProxyTracker(@NonNull final Context context,
- @NonNull final Handler connectivityServiceInternalHandler, final int pacChangedEvent) {
- mContext = context;
- mConnectivityServiceHandler = connectivityServiceInternalHandler;
- mPacProxyManager = context.getSystemService(PacProxyManager.class);
-
- PacProxyInstalledListener listener = new PacProxyInstalledListener(pacChangedEvent);
- mPacProxyManager.addPacProxyInstalledListener(
- mConnectivityServiceHandler::post, listener);
- }
-
- // Convert empty ProxyInfo's to null as null-checks are used to determine if proxies are present
- // (e.g. if mGlobalProxy==null fall back to network-specific proxy, if network-specific
- // proxy is null then there is no proxy in place).
- @Nullable
- private static ProxyInfo canonicalizeProxyInfo(@Nullable final ProxyInfo proxy) {
- if (proxy != null && TextUtils.isEmpty(proxy.getHost())
- && Uri.EMPTY.equals(proxy.getPacFileUrl())) {
- return null;
- }
- return proxy;
- }
-
- // ProxyInfo equality functions with a couple modifications over ProxyInfo.equals() to make it
- // better for determining if a new proxy broadcast is necessary:
- // 1. Canonicalize empty ProxyInfos to null so an empty proxy compares equal to null so as to
- // avoid unnecessary broadcasts.
- // 2. Make sure all parts of the ProxyInfo's compare true, including the host when a PAC URL
- // is in place. This is important so legacy PAC resolver (see com.android.proxyhandler)
- // changes aren't missed. The legacy PAC resolver pretends to be a simple HTTP proxy but
- // actually uses the PAC to resolve; this results in ProxyInfo's with PAC URL, host and port
- // all set.
- public static boolean proxyInfoEqual(@Nullable final ProxyInfo a, @Nullable final ProxyInfo b) {
- final ProxyInfo pa = canonicalizeProxyInfo(a);
- final ProxyInfo pb = canonicalizeProxyInfo(b);
- // ProxyInfo.equals() doesn't check hosts when PAC URLs are present, but we need to check
- // hosts even when PAC URLs are present to account for the legacy PAC resolver.
- return Objects.equals(pa, pb) && (pa == null || Objects.equals(pa.getHost(), pb.getHost()));
- }
-
- /**
- * Gets the default system-wide proxy.
- *
- * This will return the global proxy if set, otherwise the default proxy if in use. Note
- * that this is not necessarily the proxy that any given process should use, as the right
- * proxy for a process is the proxy for the network this process will use, which may be
- * different from this value. This value is simply the default in case there is no proxy set
- * in the network that will be used by a specific process.
- * @return The default system-wide proxy or null if none.
- */
- @Nullable
- public ProxyInfo getDefaultProxy() {
- // This information is already available as a world read/writable jvm property.
- synchronized (mProxyLock) {
- if (mGlobalProxy != null) return mGlobalProxy;
- if (mDefaultProxyEnabled) return mDefaultProxy;
- return null;
- }
- }
-
- /**
- * Gets the global proxy.
- *
- * @return The global proxy or null if none.
- */
- @Nullable
- public ProxyInfo getGlobalProxy() {
- // This information is already available as a world read/writable jvm property.
- synchronized (mProxyLock) {
- return mGlobalProxy;
- }
- }
-
- /**
- * Read the global proxy settings and cache them in memory.
- */
- public void loadGlobalProxy() {
- if (loadDeprecatedGlobalHttpProxy()) {
- return;
- }
- ContentResolver res = mContext.getContentResolver();
- String host = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_HOST);
- int port = Settings.Global.getInt(res, GLOBAL_HTTP_PROXY_PORT, 0);
- String exclList = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
- String pacFileUrl = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_PAC);
- if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
- ProxyInfo proxyProperties;
- if (!TextUtils.isEmpty(pacFileUrl)) {
- proxyProperties = ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
- } else {
- proxyProperties = ProxyInfo.buildDirectProxy(host, port,
- ProxyUtils.exclusionStringAsList(exclList));
- }
- if (!proxyProperties.isValid()) {
- if (DBG) Log.d(TAG, "Invalid proxy properties, ignoring: " + proxyProperties);
- return;
- }
-
- synchronized (mProxyLock) {
- mGlobalProxy = proxyProperties;
- }
-
- if (!TextUtils.isEmpty(pacFileUrl)) {
- mConnectivityServiceHandler.post(
- () -> mPacProxyManager.setCurrentProxyScriptUrl(proxyProperties));
- }
- }
- }
-
- /**
- * Read the global proxy from the deprecated Settings.Global.HTTP_PROXY setting and apply it.
- * Returns {@code true} when global proxy was set successfully from deprecated setting.
- */
- public boolean loadDeprecatedGlobalHttpProxy() {
- final String proxy = Settings.Global.getString(mContext.getContentResolver(), HTTP_PROXY);
- if (!TextUtils.isEmpty(proxy)) {
- String data[] = proxy.split(":");
- if (data.length == 0) {
- return false;
- }
-
- final String proxyHost = data[0];
- int proxyPort = 8080;
- if (data.length > 1) {
- try {
- proxyPort = Integer.parseInt(data[1]);
- } catch (NumberFormatException e) {
- return false;
- }
- }
- final ProxyInfo p = ProxyInfo.buildDirectProxy(proxyHost, proxyPort,
- Collections.emptyList());
- setGlobalProxy(p);
- return true;
- }
- return false;
- }
-
- /**
- * Sends the system broadcast informing apps about a new proxy configuration.
- *
- * Confusingly this method also sets the PAC file URL. TODO : separate this, it has nothing
- * to do in a "sendProxyBroadcast" method.
- */
- public void sendProxyBroadcast() {
- final ProxyInfo defaultProxy = getDefaultProxy();
- final ProxyInfo proxyInfo = null != defaultProxy ?
- defaultProxy : ProxyInfo.buildDirectProxy("", 0, Collections.emptyList());
- mPacProxyManager.setCurrentProxyScriptUrl(proxyInfo);
-
- if (!shouldSendBroadcast(proxyInfo)) {
- return;
- }
- if (DBG) Log.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
- Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
- Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- intent.putExtra(EXTRA_PROXY_INFO, proxyInfo);
- final long ident = Binder.clearCallingIdentity();
- try {
- mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- private boolean shouldSendBroadcast(ProxyInfo proxy) {
- return Uri.EMPTY.equals(proxy.getPacFileUrl()) || proxy.getPort() > 0;
- }
-
- /**
- * Sets the global proxy in memory. Also writes the values to the global settings of the device.
- *
- * @param proxyInfo the proxy spec, or null for no proxy.
- */
- public void setGlobalProxy(@Nullable ProxyInfo proxyInfo) {
- synchronized (mProxyLock) {
- // ProxyInfo#equals is not commutative :( and is public API, so it can't be fixed.
- if (proxyInfo == mGlobalProxy) return;
- if (proxyInfo != null && proxyInfo.equals(mGlobalProxy)) return;
- if (mGlobalProxy != null && mGlobalProxy.equals(proxyInfo)) return;
-
- final String host;
- final int port;
- final String exclList;
- final String pacFileUrl;
- if (proxyInfo != null && (!TextUtils.isEmpty(proxyInfo.getHost()) ||
- !Uri.EMPTY.equals(proxyInfo.getPacFileUrl()))) {
- if (!proxyInfo.isValid()) {
- if (DBG) Log.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
- return;
- }
- mGlobalProxy = new ProxyInfo(proxyInfo);
- host = mGlobalProxy.getHost();
- port = mGlobalProxy.getPort();
- exclList = ProxyUtils.exclusionListAsString(mGlobalProxy.getExclusionList());
- pacFileUrl = Uri.EMPTY.equals(proxyInfo.getPacFileUrl())
- ? "" : proxyInfo.getPacFileUrl().toString();
- } else {
- host = "";
- port = 0;
- exclList = "";
- pacFileUrl = "";
- mGlobalProxy = null;
- }
- final ContentResolver res = mContext.getContentResolver();
- final long token = Binder.clearCallingIdentity();
- try {
- Settings.Global.putString(res, GLOBAL_HTTP_PROXY_HOST, host);
- Settings.Global.putInt(res, GLOBAL_HTTP_PROXY_PORT, port);
- Settings.Global.putString(res, GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclList);
- Settings.Global.putString(res, GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
-
- sendProxyBroadcast();
- }
- }
-
- /**
- * Sets the default proxy for the device.
- *
- * The default proxy is the proxy used for networks that do not have a specific proxy.
- * @param proxyInfo the proxy spec, or null for no proxy.
- */
- public void setDefaultProxy(@Nullable ProxyInfo proxyInfo) {
- synchronized (mProxyLock) {
- if (Objects.equals(mDefaultProxy, proxyInfo)) return;
- if (proxyInfo != null && !proxyInfo.isValid()) {
- if (DBG) Log.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
- return;
- }
-
- // This call could be coming from the PacProxyService, containing the port of the
- // local proxy. If this new proxy matches the global proxy then copy this proxy to the
- // global (to get the correct local port), and send a broadcast.
- // TODO: Switch PacProxyService to have its own message to send back rather than
- // reusing EVENT_HAS_CHANGED_PROXY and this call to handleApplyDefaultProxy.
- if ((mGlobalProxy != null) && (proxyInfo != null)
- && (!Uri.EMPTY.equals(proxyInfo.getPacFileUrl()))
- && proxyInfo.getPacFileUrl().equals(mGlobalProxy.getPacFileUrl())) {
- mGlobalProxy = proxyInfo;
- sendProxyBroadcast();
- return;
- }
- mDefaultProxy = proxyInfo;
-
- if (mGlobalProxy != null) return;
- if (mDefaultProxyEnabled) {
- sendProxyBroadcast();
- }
- }
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/QosCallbackAgentConnection.java b/packages/Connectivity/service/src/com/android/server/connectivity/QosCallbackAgentConnection.java
deleted file mode 100644
index 534dbe7..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/QosCallbackAgentConnection.java
+++ /dev/null
@@ -1,199 +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 com.android.server.connectivity;
-
-import static android.net.QosCallbackException.EX_TYPE_FILTER_NONE;
-
-import android.annotation.NonNull;
-import android.net.IQosCallback;
-import android.net.Network;
-import android.net.QosCallbackException;
-import android.net.QosFilter;
-import android.net.QosSession;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.telephony.data.EpsBearerQosSessionAttributes;
-import android.telephony.data.NrQosSessionAttributes;
-import android.util.Log;
-
-import java.util.Objects;
-
-/**
- * Wraps callback related information and sends messages between network agent and the application.
- * <p/>
- * This is a satellite class of {@link com.android.server.ConnectivityService} and not meant
- * to be used in other contexts.
- *
- * @hide
- */
-class QosCallbackAgentConnection implements IBinder.DeathRecipient {
- private static final String TAG = QosCallbackAgentConnection.class.getSimpleName();
- private static final boolean DBG = false;
-
- private final int mAgentCallbackId;
- @NonNull private final QosCallbackTracker mQosCallbackTracker;
- @NonNull private final IQosCallback mCallback;
- @NonNull private final IBinder mBinder;
- @NonNull private final QosFilter mFilter;
- @NonNull private final NetworkAgentInfo mNetworkAgentInfo;
-
- private final int mUid;
-
- /**
- * Gets the uid
- * @return uid
- */
- int getUid() {
- return mUid;
- }
-
- /**
- * Gets the binder
- * @return binder
- */
- @NonNull
- IBinder getBinder() {
- return mBinder;
- }
-
- /**
- * Gets the callback id
- *
- * @return callback id
- */
- int getAgentCallbackId() {
- return mAgentCallbackId;
- }
-
- /**
- * Gets the network tied to the callback of this connection
- *
- * @return network
- */
- @NonNull
- Network getNetwork() {
- return mFilter.getNetwork();
- }
-
- QosCallbackAgentConnection(@NonNull final QosCallbackTracker qosCallbackTracker,
- final int agentCallbackId,
- @NonNull final IQosCallback callback,
- @NonNull final QosFilter filter,
- final int uid,
- @NonNull final NetworkAgentInfo networkAgentInfo) {
- Objects.requireNonNull(qosCallbackTracker, "qosCallbackTracker must be non-null");
- Objects.requireNonNull(callback, "callback must be non-null");
- Objects.requireNonNull(filter, "filter must be non-null");
- Objects.requireNonNull(networkAgentInfo, "networkAgentInfo must be non-null");
-
- mQosCallbackTracker = qosCallbackTracker;
- mAgentCallbackId = agentCallbackId;
- mCallback = callback;
- mFilter = filter;
- mUid = uid;
- mBinder = mCallback.asBinder();
- mNetworkAgentInfo = networkAgentInfo;
- }
-
- @Override
- public void binderDied() {
- logw("binderDied: binder died with callback id: " + mAgentCallbackId);
- mQosCallbackTracker.unregisterCallback(mCallback);
- }
-
- void unlinkToDeathRecipient() {
- mBinder.unlinkToDeath(this, 0);
- }
-
- // Returns false if the NetworkAgent was never notified.
- boolean sendCmdRegisterCallback() {
- final int exceptionType = mFilter.validate();
- if (exceptionType != EX_TYPE_FILTER_NONE) {
- try {
- if (DBG) log("sendCmdRegisterCallback: filter validation failed");
- mCallback.onError(exceptionType);
- } catch (final RemoteException e) {
- loge("sendCmdRegisterCallback:", e);
- }
- return false;
- }
-
- try {
- mBinder.linkToDeath(this, 0);
- } catch (final RemoteException e) {
- loge("failed linking to death recipient", e);
- return false;
- }
- mNetworkAgentInfo.onQosFilterCallbackRegistered(mAgentCallbackId, mFilter);
- return true;
- }
-
- void sendCmdUnregisterCallback() {
- if (DBG) log("sendCmdUnregisterCallback: unregistering");
- mNetworkAgentInfo.onQosCallbackUnregistered(mAgentCallbackId);
- }
-
- void sendEventEpsQosSessionAvailable(final QosSession session,
- final EpsBearerQosSessionAttributes attributes) {
- try {
- if (DBG) log("sendEventEpsQosSessionAvailable: sending...");
- mCallback.onQosEpsBearerSessionAvailable(session, attributes);
- } catch (final RemoteException e) {
- loge("sendEventEpsQosSessionAvailable: remote exception", e);
- }
- }
-
- void sendEventNrQosSessionAvailable(final QosSession session,
- final NrQosSessionAttributes attributes) {
- try {
- if (DBG) log("sendEventNrQosSessionAvailable: sending...");
- mCallback.onNrQosSessionAvailable(session, attributes);
- } catch (final RemoteException e) {
- loge("sendEventNrQosSessionAvailable: remote exception", e);
- }
- }
-
- void sendEventQosSessionLost(@NonNull final QosSession session) {
- try {
- if (DBG) log("sendEventQosSessionLost: sending...");
- mCallback.onQosSessionLost(session);
- } catch (final RemoteException e) {
- loge("sendEventQosSessionLost: remote exception", e);
- }
- }
-
- void sendEventQosCallbackError(@QosCallbackException.ExceptionType final int exceptionType) {
- try {
- if (DBG) log("sendEventQosCallbackError: sending...");
- mCallback.onError(exceptionType);
- } catch (final RemoteException e) {
- loge("sendEventQosCallbackError: remote exception", e);
- }
- }
-
- private static void log(@NonNull final String msg) {
- Log.d(TAG, msg);
- }
-
- private static void logw(@NonNull final String msg) {
- Log.w(TAG, msg);
- }
-
- private static void loge(@NonNull final String msg, final Throwable t) {
- Log.e(TAG, msg, t);
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/QosCallbackTracker.java b/packages/Connectivity/service/src/com/android/server/connectivity/QosCallbackTracker.java
deleted file mode 100644
index b6ab47b..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/QosCallbackTracker.java
+++ /dev/null
@@ -1,292 +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 com.android.server.connectivity;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.IQosCallback;
-import android.net.Network;
-import android.net.QosCallbackException;
-import android.net.QosFilter;
-import android.net.QosSession;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.telephony.data.EpsBearerQosSessionAttributes;
-import android.telephony.data.NrQosSessionAttributes;
-import android.util.Log;
-
-import com.android.net.module.util.CollectionUtils;
-import com.android.server.ConnectivityService;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tracks qos callbacks and handles the communication between the network agent and application.
- * <p/>
- * Any method prefixed by handle must be called from the
- * {@link com.android.server.ConnectivityService} handler thread.
- *
- * @hide
- */
-public class QosCallbackTracker {
- private static final String TAG = QosCallbackTracker.class.getSimpleName();
- private static final boolean DBG = true;
-
- @NonNull
- private final Handler mConnectivityServiceHandler;
-
- @NonNull
- private final ConnectivityService.PerUidCounter mNetworkRequestCounter;
-
- /**
- * Each agent gets a unique callback id that is used to proxy messages back to the original
- * callback.
- * <p/>
- * Note: The fact that this is initialized to 0 is to ensure that the thread running
- * {@link #handleRegisterCallback(IQosCallback, QosFilter, int, NetworkAgentInfo)} sees the
- * initialized value. This would not necessarily be the case if the value was initialized to
- * the non-default value.
- * <p/>
- * Note: The term previous does not apply to the first callback id that is assigned.
- */
- private int mPreviousAgentCallbackId = 0;
-
- @NonNull
- private final List<QosCallbackAgentConnection> mConnections = new ArrayList<>();
-
- /**
- *
- * @param connectivityServiceHandler must be the same handler used with
- * {@link com.android.server.ConnectivityService}
- * @param networkRequestCounter keeps track of the number of open requests under a given
- * uid
- */
- public QosCallbackTracker(@NonNull final Handler connectivityServiceHandler,
- final ConnectivityService.PerUidCounter networkRequestCounter) {
- mConnectivityServiceHandler = connectivityServiceHandler;
- mNetworkRequestCounter = networkRequestCounter;
- }
-
- /**
- * Registers the callback with the tracker
- *
- * @param callback the callback to register
- * @param filter the filter being registered alongside the callback
- */
- public void registerCallback(@NonNull final IQosCallback callback,
- @NonNull final QosFilter filter, @NonNull final NetworkAgentInfo networkAgentInfo) {
- final int uid = Binder.getCallingUid();
-
- // Enforce that the number of requests under this uid has exceeded the allowed number
- mNetworkRequestCounter.incrementCountOrThrow(uid);
-
- mConnectivityServiceHandler.post(
- () -> handleRegisterCallback(callback, filter, uid, networkAgentInfo));
- }
-
- private void handleRegisterCallback(@NonNull final IQosCallback callback,
- @NonNull final QosFilter filter, final int uid,
- @NonNull final NetworkAgentInfo networkAgentInfo) {
- final QosCallbackAgentConnection ac =
- handleRegisterCallbackInternal(callback, filter, uid, networkAgentInfo);
- if (ac != null) {
- if (DBG) log("handleRegisterCallback: added callback " + ac.getAgentCallbackId());
- mConnections.add(ac);
- } else {
- mNetworkRequestCounter.decrementCount(uid);
- }
- }
-
- private QosCallbackAgentConnection handleRegisterCallbackInternal(
- @NonNull final IQosCallback callback,
- @NonNull final QosFilter filter, final int uid,
- @NonNull final NetworkAgentInfo networkAgentInfo) {
- final IBinder binder = callback.asBinder();
- if (CollectionUtils.any(mConnections, c -> c.getBinder().equals(binder))) {
- // A duplicate registration would have only made this far due to a programming error.
- logwtf("handleRegisterCallback: Callbacks can only be register once.");
- return null;
- }
-
- mPreviousAgentCallbackId = mPreviousAgentCallbackId + 1;
- final int newCallbackId = mPreviousAgentCallbackId;
-
- final QosCallbackAgentConnection ac =
- new QosCallbackAgentConnection(this, newCallbackId, callback,
- filter, uid, networkAgentInfo);
-
- final int exceptionType = filter.validate();
- if (exceptionType != QosCallbackException.EX_TYPE_FILTER_NONE) {
- ac.sendEventQosCallbackError(exceptionType);
- return null;
- }
-
- // Only add to the callback maps if the NetworkAgent successfully registered it
- if (!ac.sendCmdRegisterCallback()) {
- // There was an issue when registering the agent
- if (DBG) log("handleRegisterCallback: error sending register callback");
- mNetworkRequestCounter.decrementCount(uid);
- return null;
- }
- return ac;
- }
-
- /**
- * Unregisters callback
- * @param callback callback to unregister
- */
- public void unregisterCallback(@NonNull final IQosCallback callback) {
- mConnectivityServiceHandler.post(() -> handleUnregisterCallback(callback.asBinder(), true));
- }
-
- private void handleUnregisterCallback(@NonNull final IBinder binder,
- final boolean sendToNetworkAgent) {
- final int connIndex =
- CollectionUtils.indexOf(mConnections, c -> c.getBinder().equals(binder));
- if (connIndex < 0) {
- logw("handleUnregisterCallback: no matching agentConnection");
- return;
- }
- final QosCallbackAgentConnection agentConnection = mConnections.get(connIndex);
-
- if (DBG) {
- log("handleUnregisterCallback: unregister "
- + agentConnection.getAgentCallbackId());
- }
-
- mNetworkRequestCounter.decrementCount(agentConnection.getUid());
- mConnections.remove(agentConnection);
-
- if (sendToNetworkAgent) {
- agentConnection.sendCmdUnregisterCallback();
- }
- agentConnection.unlinkToDeathRecipient();
- }
-
- /**
- * Called when the NetworkAgent sends the qos session available event for EPS
- *
- * @param qosCallbackId the callback id that the qos session is now available to
- * @param session the qos session that is now available
- * @param attributes the qos attributes that are now available on the qos session
- */
- public void sendEventEpsQosSessionAvailable(final int qosCallbackId,
- final QosSession session,
- final EpsBearerQosSessionAttributes attributes) {
- runOnAgentConnection(qosCallbackId, "sendEventEpsQosSessionAvailable: ",
- ac -> ac.sendEventEpsQosSessionAvailable(session, attributes));
- }
-
- /**
- * Called when the NetworkAgent sends the qos session available event for NR
- *
- * @param qosCallbackId the callback id that the qos session is now available to
- * @param session the qos session that is now available
- * @param attributes the qos attributes that are now available on the qos session
- */
- public void sendEventNrQosSessionAvailable(final int qosCallbackId,
- final QosSession session,
- final NrQosSessionAttributes attributes) {
- runOnAgentConnection(qosCallbackId, "sendEventNrQosSessionAvailable: ",
- ac -> ac.sendEventNrQosSessionAvailable(session, attributes));
- }
-
- /**
- * Called when the NetworkAgent sends the qos session lost event
- *
- * @param qosCallbackId the callback id that lost the qos session
- * @param session the corresponding qos session
- */
- public void sendEventQosSessionLost(final int qosCallbackId,
- final QosSession session) {
- runOnAgentConnection(qosCallbackId, "sendEventQosSessionLost: ",
- ac -> ac.sendEventQosSessionLost(session));
- }
-
- /**
- * Called when the NetworkAgent sends the qos session on error event
- *
- * @param qosCallbackId the callback id that should receive the exception
- * @param exceptionType the type of exception that caused the callback to error
- */
- public void sendEventQosCallbackError(final int qosCallbackId,
- @QosCallbackException.ExceptionType final int exceptionType) {
- runOnAgentConnection(qosCallbackId, "sendEventQosCallbackError: ",
- ac -> {
- ac.sendEventQosCallbackError(exceptionType);
- handleUnregisterCallback(ac.getBinder(), false);
- });
- }
-
- /**
- * Unregisters all callbacks associated to this network agent
- *
- * Note: Must be called on the connectivity service handler thread
- *
- * @param network the network that was released
- */
- public void handleNetworkReleased(@Nullable final Network network) {
- // Iterate in reverse order as agent connections will be removed when unregistering
- for (int i = mConnections.size() - 1; i >= 0; i--) {
- final QosCallbackAgentConnection agentConnection = mConnections.get(i);
- if (!agentConnection.getNetwork().equals(network)) continue;
- agentConnection.sendEventQosCallbackError(
- QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
-
- // Call unregister workflow w\o sending anything to agent since it is disconnected.
- handleUnregisterCallback(agentConnection.getBinder(), false);
- }
- }
-
- private interface AgentConnectionAction {
- void execute(@NonNull QosCallbackAgentConnection agentConnection);
- }
-
- @Nullable
- private void runOnAgentConnection(final int qosCallbackId,
- @NonNull final String logPrefix,
- @NonNull final AgentConnectionAction action) {
- mConnectivityServiceHandler.post(() -> {
- final int acIndex = CollectionUtils.indexOf(mConnections,
- c -> c.getAgentCallbackId() == qosCallbackId);
- if (acIndex == -1) {
- loge(logPrefix + ": " + qosCallbackId + " missing callback id");
- return;
- }
-
- action.execute(mConnections.get(acIndex));
- });
- }
-
- private static void log(final String msg) {
- Log.d(TAG, msg);
- }
-
- private static void logw(final String msg) {
- Log.w(TAG, msg);
- }
-
- private static void loge(final String msg) {
- Log.e(TAG, msg);
- }
-
- private static void logwtf(final String msg) {
- Log.wtf(TAG, msg);
- }
-}
diff --git a/packages/Connectivity/service/src/com/android/server/connectivity/TcpKeepaliveController.java b/packages/Connectivity/service/src/com/android/server/connectivity/TcpKeepaliveController.java
deleted file mode 100644
index 73f3475..0000000
--- a/packages/Connectivity/service/src/com/android/server/connectivity/TcpKeepaliveController.java
+++ /dev/null
@@ -1,340 +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.server.connectivity;
-
-import static android.net.SocketKeepalive.DATA_RECEIVED;
-import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
-import static android.net.SocketKeepalive.ERROR_SOCKET_NOT_IDLE;
-import static android.net.SocketKeepalive.ERROR_UNSUPPORTED;
-import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
-import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
-import static android.system.OsConstants.ENOPROTOOPT;
-import static android.system.OsConstants.FIONREAD;
-import static android.system.OsConstants.IPPROTO_IP;
-import static android.system.OsConstants.IPPROTO_TCP;
-import static android.system.OsConstants.IP_TOS;
-import static android.system.OsConstants.IP_TTL;
-
-import static com.android.server.connectivity.OsCompat.TIOCOUTQ;
-
-import android.annotation.NonNull;
-import android.net.InvalidPacketException;
-import android.net.NetworkUtils;
-import android.net.SocketKeepalive.InvalidSocketException;
-import android.net.TcpKeepalivePacketData;
-import android.net.TcpKeepalivePacketDataParcelable;
-import android.net.TcpRepairWindow;
-import android.net.util.KeepalivePacketDataUtil;
-import android.os.Handler;
-import android.os.MessageQueue;
-import android.os.Messenger;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.server.connectivity.KeepaliveTracker.KeepaliveInfo;
-
-import java.io.FileDescriptor;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.net.SocketException;
-
-/**
- * Manage tcp socket which offloads tcp keepalive.
- *
- * The input socket will be changed to repair mode and the application
- * will not have permission to read/write data. If the application wants
- * to write data, it must stop tcp keepalive offload to leave repair mode
- * first. If a remote packet arrives, repair mode will be turned off and
- * offload will be stopped. The application will receive a callback to know
- * it can start reading data.
- *
- * {start,stop}SocketMonitor are thread-safe, but care must be taken in the
- * order in which they are called. Please note that while calling
- * {@link #startSocketMonitor(FileDescriptor, Messenger, int)} multiple times
- * with either the same slot or the same FileDescriptor without stopping it in
- * between will result in an exception, calling {@link #stopSocketMonitor(int)}
- * multiple times with the same int is explicitly a no-op.
- * Please also note that switching the socket to repair mode is not synchronized
- * with either of these operations and has to be done in an orderly fashion
- * with stopSocketMonitor. Take care in calling these in the right order.
- * @hide
- */
-public class TcpKeepaliveController {
- private static final String TAG = "TcpKeepaliveController";
- private static final boolean DBG = false;
-
- private final MessageQueue mFdHandlerQueue;
-
- private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR;
-
- // Reference include/uapi/linux/tcp.h
- private static final int TCP_REPAIR = 19;
- private static final int TCP_REPAIR_QUEUE = 20;
- private static final int TCP_QUEUE_SEQ = 21;
- private static final int TCP_NO_QUEUE = 0;
- private static final int TCP_RECV_QUEUE = 1;
- private static final int TCP_SEND_QUEUE = 2;
- private static final int TCP_REPAIR_OFF = 0;
- private static final int TCP_REPAIR_ON = 1;
- // Reference include/uapi/linux/sockios.h
- private static final int SIOCINQ = FIONREAD;
- private static final int SIOCOUTQ = TIOCOUTQ;
-
- /**
- * Keeps track of packet listeners.
- * Key: slot number of keepalive offload.
- * Value: {@link FileDescriptor} being listened to.
- */
- @GuardedBy("mListeners")
- private final SparseArray<FileDescriptor> mListeners = new SparseArray<>();
-
- public TcpKeepaliveController(final Handler connectivityServiceHandler) {
- mFdHandlerQueue = connectivityServiceHandler.getLooper().getQueue();
- }
-
- /** Build tcp keepalive packet. */
- public static TcpKeepalivePacketData getTcpKeepalivePacket(@NonNull FileDescriptor fd)
- throws InvalidPacketException, InvalidSocketException {
- try {
- final TcpKeepalivePacketDataParcelable tcpDetails = switchToRepairMode(fd);
- return KeepalivePacketDataUtil.fromStableParcelable(tcpDetails);
- } catch (InvalidPacketException | InvalidSocketException e) {
- switchOutOfRepairMode(fd);
- throw e;
- }
- }
- /**
- * Switch the tcp socket to repair mode and query detail tcp information.
- *
- * @param fd the fd of socket on which to use keepalive offload.
- * @return a {@link TcpKeepalivePacketDataParcelable} object for current
- * tcp/ip information.
- */
- private static TcpKeepalivePacketDataParcelable switchToRepairMode(FileDescriptor fd)
- throws InvalidSocketException {
- if (DBG) Log.i(TAG, "switchToRepairMode to start tcp keepalive : " + fd);
- final TcpKeepalivePacketDataParcelable tcpDetails = new TcpKeepalivePacketDataParcelable();
- final SocketAddress srcSockAddr;
- final SocketAddress dstSockAddr;
- final TcpRepairWindow trw;
-
- // Query source address and port.
- try {
- srcSockAddr = Os.getsockname(fd);
- } catch (ErrnoException e) {
- Log.e(TAG, "Get sockname fail: ", e);
- throw new InvalidSocketException(ERROR_INVALID_SOCKET, e);
- }
- if (srcSockAddr instanceof InetSocketAddress) {
- tcpDetails.srcAddress = getAddress((InetSocketAddress) srcSockAddr);
- tcpDetails.srcPort = getPort((InetSocketAddress) srcSockAddr);
- } else {
- Log.e(TAG, "Invalid or mismatched SocketAddress");
- throw new InvalidSocketException(ERROR_INVALID_SOCKET);
- }
- // Query destination address and port.
- try {
- dstSockAddr = Os.getpeername(fd);
- } catch (ErrnoException e) {
- Log.e(TAG, "Get peername fail: ", e);
- throw new InvalidSocketException(ERROR_INVALID_SOCKET, e);
- }
- if (dstSockAddr instanceof InetSocketAddress) {
- tcpDetails.dstAddress = getAddress((InetSocketAddress) dstSockAddr);
- tcpDetails.dstPort = getPort((InetSocketAddress) dstSockAddr);
- } else {
- Log.e(TAG, "Invalid or mismatched peer SocketAddress");
- throw new InvalidSocketException(ERROR_INVALID_SOCKET);
- }
-
- // Query sequence and ack number
- dropAllIncomingPackets(fd, true);
- try {
- // Switch to tcp repair mode.
- Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR, TCP_REPAIR_ON);
-
- // Check if socket is idle.
- if (!isSocketIdle(fd)) {
- Log.e(TAG, "Socket is not idle");
- throw new InvalidSocketException(ERROR_SOCKET_NOT_IDLE);
- }
- // Query write sequence number from SEND_QUEUE.
- Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_SEND_QUEUE);
- tcpDetails.seq = OsCompat.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
- // Query read sequence number from RECV_QUEUE.
- Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_RECV_QUEUE);
- tcpDetails.ack = OsCompat.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
- // Switch to NO_QUEUE to prevent illegal socket read/write in repair mode.
- Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_NO_QUEUE);
- // Finally, check if socket is still idle. TODO : this check needs to move to
- // after starting polling to prevent a race.
- if (!isReceiveQueueEmpty(fd)) {
- Log.e(TAG, "Fatal: receive queue of this socket is not empty");
- throw new InvalidSocketException(ERROR_INVALID_SOCKET);
- }
- if (!isSendQueueEmpty(fd)) {
- Log.e(TAG, "Socket is not idle");
- throw new InvalidSocketException(ERROR_SOCKET_NOT_IDLE);
- }
-
- // Query tcp window size.
- trw = NetworkUtils.getTcpRepairWindow(fd);
- tcpDetails.rcvWnd = trw.rcvWnd;
- tcpDetails.rcvWndScale = trw.rcvWndScale;
- if (tcpDetails.srcAddress.length == 4 /* V4 address length */) {
- // Query TOS.
- tcpDetails.tos = OsCompat.getsockoptInt(fd, IPPROTO_IP, IP_TOS);
- // Query TTL.
- tcpDetails.ttl = OsCompat.getsockoptInt(fd, IPPROTO_IP, IP_TTL);
- }
- } catch (ErrnoException e) {
- Log.e(TAG, "Exception reading TCP state from socket", e);
- if (e.errno == ENOPROTOOPT) {
- // ENOPROTOOPT may happen in kernel version lower than 4.8.
- // Treat it as ERROR_UNSUPPORTED.
- throw new InvalidSocketException(ERROR_UNSUPPORTED, e);
- } else {
- throw new InvalidSocketException(ERROR_INVALID_SOCKET, e);
- }
- } finally {
- dropAllIncomingPackets(fd, false);
- }
-
- // Keepalive sequence number is last sequence number - 1. If it couldn't be retrieved,
- // then it must be set to -1, so decrement in all cases.
- tcpDetails.seq = tcpDetails.seq - 1;
-
- return tcpDetails;
- }
-
- /**
- * Switch the tcp socket out of repair mode.
- *
- * @param fd the fd of socket to switch back to normal.
- */
- private static void switchOutOfRepairMode(@NonNull final FileDescriptor fd) {
- try {
- Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR, TCP_REPAIR_OFF);
- } catch (ErrnoException e) {
- Log.e(TAG, "Cannot switch socket out of repair mode", e);
- // Well, there is not much to do here to recover
- }
- }
-
- /**
- * Start monitoring incoming packets.
- *
- * @param fd socket fd to monitor.
- * @param ki a {@link KeepaliveInfo} that tracks information about a socket keepalive.
- * @param slot keepalive slot.
- */
- public void startSocketMonitor(@NonNull final FileDescriptor fd,
- @NonNull final KeepaliveInfo ki, final int slot)
- throws IllegalArgumentException, InvalidSocketException {
- synchronized (mListeners) {
- if (null != mListeners.get(slot)) {
- throw new IllegalArgumentException("This slot is already taken");
- }
- for (int i = 0; i < mListeners.size(); ++i) {
- if (fd.equals(mListeners.valueAt(i))) {
- Log.e(TAG, "This fd is already registered.");
- throw new InvalidSocketException(ERROR_INVALID_SOCKET);
- }
- }
- mFdHandlerQueue.addOnFileDescriptorEventListener(fd, FD_EVENTS, (readyFd, events) -> {
- // This can't be called twice because the queue guarantees that once the listener
- // is unregistered it can't be called again, even for a message that arrived
- // before it was unregistered.
- final int reason;
- if (0 != (events & EVENT_ERROR)) {
- reason = ERROR_INVALID_SOCKET;
- } else {
- reason = DATA_RECEIVED;
- }
- ki.onFileDescriptorInitiatedStop(reason);
- // The listener returns the new set of events to listen to. Because 0 means no
- // event, the listener gets unregistered.
- return 0;
- });
- mListeners.put(slot, fd);
- }
- }
-
- /** Stop socket monitor */
- // This slot may have been stopped automatically already because the socket received data,
- // was closed on the other end or otherwise suffered some error. In this case, this function
- // is a no-op.
- public void stopSocketMonitor(final int slot) {
- final FileDescriptor fd;
- synchronized (mListeners) {
- fd = mListeners.get(slot);
- if (null == fd) return;
- mListeners.remove(slot);
- }
- mFdHandlerQueue.removeOnFileDescriptorEventListener(fd);
- if (DBG) Log.d(TAG, "Moving socket out of repair mode for stop : " + fd);
- switchOutOfRepairMode(fd);
- }
-
- private static byte [] getAddress(InetSocketAddress inetAddr) {
- return inetAddr.getAddress().getAddress();
- }
-
- private static int getPort(InetSocketAddress inetAddr) {
- return inetAddr.getPort();
- }
-
- private static boolean isSocketIdle(FileDescriptor fd) throws ErrnoException {
- return isReceiveQueueEmpty(fd) && isSendQueueEmpty(fd);
- }
-
- private static boolean isReceiveQueueEmpty(FileDescriptor fd)
- throws ErrnoException {
- final int result = OsCompat.ioctlInt(fd, SIOCINQ);
- if (result != 0) {
- Log.e(TAG, "Read queue has data");
- return false;
- }
- return true;
- }
-
- private static boolean isSendQueueEmpty(FileDescriptor fd)
- throws ErrnoException {
- final int result = OsCompat.ioctlInt(fd, SIOCOUTQ);
- if (result != 0) {
- Log.e(TAG, "Write queue has data");
- return false;
- }
- return true;
- }
-
- private static void dropAllIncomingPackets(FileDescriptor fd, boolean enable)
- throws InvalidSocketException {
- try {
- if (enable) {
- NetworkUtils.attachDropAllBPFFilter(fd);
- } else {
- NetworkUtils.detachBPFFilter(fd);
- }
- } catch (SocketException e) {
- Log.e(TAG, "Socket Exception: ", e);
- throw new InvalidSocketException(ERROR_INVALID_SOCKET, e);
- }
- }
-}
diff --git a/packages/Connectivity/tests/OWNERS b/packages/Connectivity/tests/OWNERS
deleted file mode 100644
index d3836d4..0000000
--- a/packages/Connectivity/tests/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-set noparent
-
-codewiz@google.com
-jchalard@google.com
-junyulai@google.com
-lorenzo@google.com
-reminv@google.com
-satk@google.com
diff --git a/packages/Connectivity/tests/TEST_MAPPING b/packages/Connectivity/tests/TEST_MAPPING
deleted file mode 100644
index 502f885..0000000
--- a/packages/Connectivity/tests/TEST_MAPPING
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "presubmit": [
- {
- "name": "FrameworksNetIntegrationTests"
- }
- ],
- "postsubmit": [
- {
- "name": "FrameworksNetDeflakeTest"
- }
- ],
- "auto-postsubmit": [
- // Test tag for automotive targets. These are only running in postsubmit so as to harden the
- // automotive targets to avoid introducing additional test flake and build time. The plan for
- // presubmit testing for auto is to augment the existing tests to cover auto use cases as well.
- // Additionally, this tag is used in targeted test suites to limit resource usage on the test
- // infra during the hardening phase.
- // TODO: this tag to be removed once the above is no longer an issue.
- {
- "name": "FrameworksNetTests"
- },
- {
- "name": "FrameworksNetIntegrationTests"
- },
- {
- "name": "FrameworksNetDeflakeTest"
- }
- ],
- "imports": [
- {
- "path": "packages/modules/Connectivity"
- }
- ]
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/common/Android.bp b/packages/Connectivity/tests/common/Android.bp
deleted file mode 100644
index 7331453..0000000
--- a/packages/Connectivity/tests/common/Android.bp
+++ /dev/null
@@ -1,67 +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.
-//
-
-// Tests in this folder are included both in unit tests and CTS.
-// They must be fast and stable, and exercise public or test APIs.
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-java_library {
- name: "FrameworksNetCommonTests",
- defaults: ["framework-connectivity-test-defaults"],
- srcs: [
- "java/**/*.java",
- "java/**/*.kt",
- ],
- static_libs: [
- "androidx.core_core",
- "androidx.test.rules",
- "junit",
- "mockito-target-minus-junit4",
- "modules-utils-build",
- "net-tests-utils",
- "net-utils-framework-common",
- "platform-test-annotations",
- ],
- libs: [
- "android.test.base.stubs",
- ],
-}
-
-// defaults for tests that need to build against framework-connectivity's @hide APIs
-// Only usable from targets that have visibility on framework-connectivity.impl.
-// Instead of using this, consider avoiding to depend on hidden connectivity APIs in
-// tests.
-java_defaults {
- name: "framework-connectivity-test-defaults",
- sdk_version: "core_platform", // tests can use @CorePlatformApi's
- libs: [
- // order matters: classes in framework-connectivity are resolved before framework,
- // meaning @hide APIs in framework-connectivity are resolved before @SystemApi
- // stubs in framework
- "framework-connectivity.impl",
- "framework",
-
- // if sdk_version="" this gets automatically included, but here we need to add manually.
- "framework-res",
- ],
-}
diff --git a/packages/Connectivity/tests/common/java/ParseExceptionTest.kt b/packages/Connectivity/tests/common/java/ParseExceptionTest.kt
deleted file mode 100644
index b702d61..0000000
--- a/packages/Connectivity/tests/common/java/ParseExceptionTest.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import android.net.ParseException
-import android.os.Build
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.testutils.DevSdkIgnoreRule
-import junit.framework.Assert.assertEquals
-import junit.framework.Assert.assertNull
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class ParseExceptionTest {
- @get:Rule
- val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.R)
-
- @Test
- fun testConstructor_WithCause() {
- val testMessage = "Test message"
- val base = Exception("Test")
- val exception = ParseException(testMessage, base)
-
- assertEquals(testMessage, exception.response)
- assertEquals(base, exception.cause)
- }
-
- @Test
- fun testConstructor_NoCause() {
- val testMessage = "Test message"
- val exception = ParseException(testMessage)
-
- assertEquals(testMessage, exception.response)
- assertNull(exception.cause)
- }
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/common/java/android/net/CaptivePortalDataTest.kt b/packages/Connectivity/tests/common/java/android/net/CaptivePortalDataTest.kt
deleted file mode 100644
index 18a9331..0000000
--- a/packages/Connectivity/tests/common/java/android/net/CaptivePortalDataTest.kt
+++ /dev/null
@@ -1,190 +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 android.net
-
-import android.os.Build
-import androidx.test.filters.SmallTest
-import com.android.modules.utils.build.SdkLevel
-import com.android.testutils.assertParcelSane
-import com.android.testutils.assertParcelingIsLossless
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import com.android.testutils.DevSdkIgnoreRunner
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import kotlin.test.assertEquals
-import kotlin.test.assertNotEquals
-
-@SmallTest
-@RunWith(DevSdkIgnoreRunner::class)
-@IgnoreUpTo(Build.VERSION_CODES.Q)
-class CaptivePortalDataTest {
- @Rule @JvmField
- val ignoreRule = DevSdkIgnoreRule()
-
- private val data = CaptivePortalData.Builder()
- .setRefreshTime(123L)
- .setUserPortalUrl(Uri.parse("https://portal.example.com/test"))
- .setVenueInfoUrl(Uri.parse("https://venue.example.com/test"))
- .setSessionExtendable(true)
- .setBytesRemaining(456L)
- .setExpiryTime(789L)
- .setCaptive(true)
- .apply {
- if (SdkLevel.isAtLeastS()) {
- setVenueFriendlyName("venue friendly name")
- }
- }
- .build()
-
- private val dataFromPasspoint = CaptivePortalData.Builder()
- .setCaptive(true)
- .apply {
- if (SdkLevel.isAtLeastS()) {
- setVenueFriendlyName("venue friendly name")
- setUserPortalUrl(Uri.parse("https://tc.example.com/passpoint"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
- setVenueInfoUrl(Uri.parse("https://venue.example.com/passpoint"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
- }
- }
- .build()
-
- private fun makeBuilder() = CaptivePortalData.Builder(data)
-
- @Test
- fun testParcelUnparcel() {
- val fieldCount = if (SdkLevel.isAtLeastS()) 10 else 7
- assertParcelSane(data, fieldCount)
- assertParcelSane(dataFromPasspoint, fieldCount)
-
- assertParcelingIsLossless(makeBuilder().setUserPortalUrl(null).build())
- assertParcelingIsLossless(makeBuilder().setVenueInfoUrl(null).build())
- }
-
- @Test
- fun testEquals() {
- assertEquals(data, makeBuilder().build())
-
- assertNotEqualsAfterChange { it.setRefreshTime(456L) }
- assertNotEqualsAfterChange { it.setUserPortalUrl(Uri.parse("https://example.com/")) }
- assertNotEqualsAfterChange { it.setUserPortalUrl(null) }
- assertNotEqualsAfterChange { it.setVenueInfoUrl(Uri.parse("https://example.com/")) }
- assertNotEqualsAfterChange { it.setVenueInfoUrl(null) }
- assertNotEqualsAfterChange { it.setSessionExtendable(false) }
- assertNotEqualsAfterChange { it.setBytesRemaining(789L) }
- assertNotEqualsAfterChange { it.setExpiryTime(12L) }
- assertNotEqualsAfterChange { it.setCaptive(false) }
-
- if (SdkLevel.isAtLeastS()) {
- assertNotEqualsAfterChange { it.setVenueFriendlyName("another friendly name") }
- assertNotEqualsAfterChange { it.setVenueFriendlyName(null) }
-
- assertEquals(dataFromPasspoint, CaptivePortalData.Builder(dataFromPasspoint).build())
- assertNotEqualsAfterChange { it.setUserPortalUrl(
- Uri.parse("https://tc.example.com/passpoint")) }
- assertNotEqualsAfterChange { it.setUserPortalUrl(
- Uri.parse("https://tc.example.com/passpoint"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
- assertNotEqualsAfterChange { it.setUserPortalUrl(
- Uri.parse("https://tc.example.com/other"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
- assertNotEqualsAfterChange { it.setUserPortalUrl(
- Uri.parse("https://tc.example.com/passpoint"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
- assertNotEqualsAfterChange { it.setVenueInfoUrl(
- Uri.parse("https://venue.example.com/passpoint")) }
- assertNotEqualsAfterChange { it.setVenueInfoUrl(
- Uri.parse("https://venue.example.com/other"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
- assertNotEqualsAfterChange { it.setVenueInfoUrl(
- Uri.parse("https://venue.example.com/passpoint"),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
- }
- }
-
- @Test
- fun testUserPortalUrl() {
- assertEquals(Uri.parse("https://portal.example.com/test"), data.userPortalUrl)
- }
-
- @Test
- fun testVenueInfoUrl() {
- assertEquals(Uri.parse("https://venue.example.com/test"), data.venueInfoUrl)
- }
-
- @Test
- fun testIsSessionExtendable() {
- assertTrue(data.isSessionExtendable)
- }
-
- @Test
- fun testByteLimit() {
- assertEquals(456L, data.byteLimit)
- // Test byteLimit unset.
- assertEquals(-1L, CaptivePortalData.Builder(null).build().byteLimit)
- }
-
- @Test
- fun testRefreshTimeMillis() {
- assertEquals(123L, data.refreshTimeMillis)
- }
-
- @Test
- fun testExpiryTimeMillis() {
- assertEquals(789L, data.expiryTimeMillis)
- // Test expiryTimeMillis unset.
- assertEquals(-1L, CaptivePortalData.Builder(null).build().expiryTimeMillis)
- }
-
- @Test
- fun testIsCaptive() {
- assertTrue(data.isCaptive)
- assertFalse(makeBuilder().setCaptive(false).build().isCaptive)
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.R)
- fun testVenueFriendlyName() {
- assertEquals("venue friendly name", data.venueFriendlyName)
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.R)
- fun testGetVenueInfoUrlSource() {
- assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER,
- data.venueInfoUrlSource)
- assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT,
- dataFromPasspoint.venueInfoUrlSource)
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.R)
- fun testGetUserPortalUrlSource() {
- assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER,
- data.userPortalUrlSource)
- assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT,
- dataFromPasspoint.userPortalUrlSource)
- }
-
- private fun CaptivePortalData.mutate(mutator: (CaptivePortalData.Builder) -> Unit) =
- CaptivePortalData.Builder(this).apply { mutator(this) }.build()
-
- private fun assertNotEqualsAfterChange(mutator: (CaptivePortalData.Builder) -> Unit) {
- assertNotEquals(data, data.mutate(mutator))
- }
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/common/java/android/net/CaptivePortalTest.java b/packages/Connectivity/tests/common/java/android/net/CaptivePortalTest.java
deleted file mode 100644
index 15d3398..0000000
--- a/packages/Connectivity/tests/common/java/android/net/CaptivePortalTest.java
+++ /dev/null
@@ -1,121 +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 android.net;
-
-import static org.junit.Assert.assertEquals;
-
-import android.os.Build;
-import android.os.RemoteException;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class CaptivePortalTest {
- @Rule
- public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
-
- private static final int DEFAULT_TIMEOUT_MS = 5000;
- private static final String TEST_PACKAGE_NAME = "com.google.android.test";
-
- private final class MyCaptivePortalImpl extends ICaptivePortal.Stub {
- int mCode = -1;
- String mPackageName = null;
-
- @Override
- public void appResponse(final int response) throws RemoteException {
- mCode = response;
- }
-
- @Override
- public void appRequest(final int request) throws RemoteException {
- mCode = request;
- }
-
- // This is only @Override on R-
- public void logEvent(int eventId, String packageName) throws RemoteException {
- mCode = eventId;
- mPackageName = packageName;
- }
- }
-
- private interface TestFunctor {
- void useCaptivePortal(CaptivePortal o);
- }
-
- private MyCaptivePortalImpl runCaptivePortalTest(TestFunctor f) {
- final MyCaptivePortalImpl cp = new MyCaptivePortalImpl();
- f.useCaptivePortal(new CaptivePortal(cp.asBinder()));
- return cp;
- }
-
- @Test
- public void testReportCaptivePortalDismissed() {
- final MyCaptivePortalImpl result =
- runCaptivePortalTest(c -> c.reportCaptivePortalDismissed());
- assertEquals(result.mCode, CaptivePortal.APP_RETURN_DISMISSED);
- }
-
- @Test
- public void testIgnoreNetwork() {
- final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.ignoreNetwork());
- assertEquals(result.mCode, CaptivePortal.APP_RETURN_UNWANTED);
- }
-
- @Test
- public void testUseNetwork() {
- final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.useNetwork());
- assertEquals(result.mCode, CaptivePortal.APP_RETURN_WANTED_AS_IS);
- }
-
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- @Test
- public void testReevaluateNetwork() {
- final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.reevaluateNetwork());
- assertEquals(result.mCode, CaptivePortal.APP_REQUEST_REEVALUATION_REQUIRED);
- }
-
- @IgnoreUpTo(Build.VERSION_CODES.R)
- @Test
- public void testLogEvent() {
- /**
- * From S testLogEvent is expected to do nothing but shouldn't crash (the API
- * logEvent has been deprecated).
- */
- final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent(
- 0,
- TEST_PACKAGE_NAME));
- }
-
- @IgnoreAfter(Build.VERSION_CODES.R)
- @Test
- public void testLogEvent_UntilR() {
- final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent(
- 42, TEST_PACKAGE_NAME));
- assertEquals(result.mCode, 42);
- assertEquals(result.mPackageName, TEST_PACKAGE_NAME);
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/DependenciesTest.java b/packages/Connectivity/tests/common/java/android/net/DependenciesTest.java
deleted file mode 100644
index ac1c28a..0000000
--- a/packages/Connectivity/tests/common/java/android/net/DependenciesTest.java
+++ /dev/null
@@ -1,113 +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.net;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.concurrent.TimeUnit;
-
-/**
- * A simple class that tests dependencies to java standard tools from the
- * Network stack. These tests are not meant to be comprehensive tests of
- * the relevant APIs : such tests belong in the relevant test suite for
- * these dependencies. Instead, this just makes sure coverage is present
- * by calling the methods in the exact way (or a representative way of how)
- * they are called in the network stack.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DependenciesTest {
- // Used to in ipmemorystore's RegularMaintenanceJobService to convert
- // 24 hours into seconds
- @Test
- public void testTimeUnit() {
- final int hours = 24;
- final long inSeconds = TimeUnit.HOURS.toMillis(hours);
- assertEquals(inSeconds, hours * 60 * 60 * 1000);
- }
-
- private byte[] makeTrivialArray(final int size) {
- final byte[] src = new byte[size];
- for (int i = 0; i < size; ++i) {
- src[i] = (byte) i;
- }
- return src;
- }
-
- // Used in ApfFilter to find an IP address from a byte array
- @Test
- public void testArrays() {
- final int size = 128;
- final byte[] src = makeTrivialArray(size);
-
- // Test copy
- final int copySize = 16;
- final int offset = 24;
- final byte[] expected = new byte[copySize];
- for (int i = 0; i < copySize; ++i) {
- expected[i] = (byte) (offset + i);
- }
-
- final byte[] copy = Arrays.copyOfRange(src, offset, offset + copySize);
- assertArrayEquals(expected, copy);
- assertArrayEquals(new byte[0], Arrays.copyOfRange(src, size, size));
- }
-
- // Used mainly in the Dhcp code
- @Test
- public void testCopyOf() {
- final byte[] src = makeTrivialArray(128);
- final byte[] copy = Arrays.copyOf(src, src.length);
- assertArrayEquals(src, copy);
- assertFalse(src == copy);
-
- assertArrayEquals(new byte[0], Arrays.copyOf(src, 0));
-
- final int excess = 16;
- final byte[] biggerCopy = Arrays.copyOf(src, src.length + excess);
- for (int i = src.length; i < src.length + excess; ++i) {
- assertEquals(0, biggerCopy[i]);
- }
- for (int i = src.length - 1; i >= 0; --i) {
- assertEquals(src[i], biggerCopy[i]);
- }
- }
-
- // Used mainly in DnsUtils but also various other places
- @Test
- public void testAsList() {
- final int size = 24;
- final Object[] src = new Object[size];
- final ArrayList<Object> expected = new ArrayList<>(size);
- for (int i = 0; i < size; ++i) {
- final Object o = new Object();
- src[i] = o;
- expected.add(o);
- }
- assertEquals(expected, Arrays.asList(src));
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/DhcpInfoTest.java b/packages/Connectivity/tests/common/java/android/net/DhcpInfoTest.java
deleted file mode 100644
index ab4726b..0000000
--- a/packages/Connectivity/tests/common/java/android/net/DhcpInfoTest.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTL;
-import static com.android.testutils.MiscAsserts.assertFieldCountEquals;
-import static com.android.testutils.ParcelUtils.parcelingRoundTrip;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.annotation.Nullable;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-
-@RunWith(AndroidJUnit4.class)
-public class DhcpInfoTest {
- private static final String STR_ADDR1 = "255.255.255.255";
- private static final String STR_ADDR2 = "127.0.0.1";
- private static final String STR_ADDR3 = "192.168.1.1";
- private static final String STR_ADDR4 = "192.168.1.0";
- private static final int LEASE_TIME = 9999;
-
- private int ipToInteger(String ipString) throws Exception {
- return inet4AddressToIntHTL((Inet4Address) InetAddress.getByName(ipString));
- }
-
- private DhcpInfo createDhcpInfoObject() throws Exception {
- final DhcpInfo dhcpInfo = new DhcpInfo();
- dhcpInfo.ipAddress = ipToInteger(STR_ADDR1);
- dhcpInfo.gateway = ipToInteger(STR_ADDR2);
- dhcpInfo.netmask = ipToInteger(STR_ADDR3);
- dhcpInfo.dns1 = ipToInteger(STR_ADDR4);
- dhcpInfo.dns2 = ipToInteger(STR_ADDR4);
- dhcpInfo.serverAddress = ipToInteger(STR_ADDR2);
- dhcpInfo.leaseDuration = LEASE_TIME;
- return dhcpInfo;
- }
-
- @Test
- public void testConstructor() {
- new DhcpInfo();
- }
-
- @Test
- public void testToString() throws Exception {
- final String expectedDefault = "ipaddr 0.0.0.0 gateway 0.0.0.0 netmask 0.0.0.0 "
- + "dns1 0.0.0.0 dns2 0.0.0.0 DHCP server 0.0.0.0 lease 0 seconds";
-
- DhcpInfo dhcpInfo = new DhcpInfo();
-
- // Test default string.
- assertEquals(expectedDefault, dhcpInfo.toString());
-
- dhcpInfo = createDhcpInfoObject();
-
- final String expected = "ipaddr " + STR_ADDR1 + " gateway " + STR_ADDR2 + " netmask "
- + STR_ADDR3 + " dns1 " + STR_ADDR4 + " dns2 " + STR_ADDR4 + " DHCP server "
- + STR_ADDR2 + " lease " + LEASE_TIME + " seconds";
- // Test with new values
- assertEquals(expected, dhcpInfo.toString());
- }
-
- private boolean dhcpInfoEquals(@Nullable DhcpInfo left, @Nullable DhcpInfo right) {
- if (left == null && right == null) return true;
-
- if (left == null || right == null) return false;
-
- return left.ipAddress == right.ipAddress
- && left.gateway == right.gateway
- && left.netmask == right.netmask
- && left.dns1 == right.dns1
- && left.dns2 == right.dns2
- && left.serverAddress == right.serverAddress
- && left.leaseDuration == right.leaseDuration;
- }
-
- @Test
- public void testParcelDhcpInfo() throws Exception {
- // Cannot use assertParcelSane() here because this requires .equals() to work as
- // defined, but DhcpInfo has a different legacy behavior that we cannot change.
- final DhcpInfo dhcpInfo = createDhcpInfoObject();
- assertFieldCountEquals(7, DhcpInfo.class);
-
- final DhcpInfo dhcpInfoRoundTrip = parcelingRoundTrip(dhcpInfo);
- assertTrue(dhcpInfoEquals(null, null));
- assertFalse(dhcpInfoEquals(null, dhcpInfoRoundTrip));
- assertFalse(dhcpInfoEquals(dhcpInfo, null));
- assertTrue(dhcpInfoEquals(dhcpInfo, dhcpInfoRoundTrip));
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/IpPrefixTest.java b/packages/Connectivity/tests/common/java/android/net/IpPrefixTest.java
deleted file mode 100644
index 50ecb42..0000000
--- a/packages/Connectivity/tests/common/java/android/net/IpPrefixTest.java
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static com.android.testutils.MiscAsserts.assertEqualBothWays;
-import static com.android.testutils.MiscAsserts.assertFieldCountEquals;
-import static com.android.testutils.MiscAsserts.assertNotEqualEitherWay;
-import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.util.Random;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpPrefixTest {
-
- private static InetAddress address(String addr) {
- return InetAddress.parseNumericAddress(addr);
- }
-
- // Explicitly cast everything to byte because "error: possible loss of precision".
- private static final byte[] IPV4_BYTES = { (byte) 192, (byte) 0, (byte) 2, (byte) 4};
- private static final byte[] IPV6_BYTES = {
- (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8,
- (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
- (byte) 0x0f, (byte) 0x00, (byte) 0x00, (byte) 0x00,
- (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xa0
- };
-
- @Test
- public void testConstructor() {
- IpPrefix p;
- try {
- p = new IpPrefix((byte[]) null, 9);
- fail("Expected NullPointerException: null byte array");
- } catch (RuntimeException expected) { }
-
- try {
- p = new IpPrefix((InetAddress) null, 10);
- fail("Expected NullPointerException: null InetAddress");
- } catch (RuntimeException expected) { }
-
- try {
- p = new IpPrefix((String) null);
- fail("Expected NullPointerException: null String");
- } catch (RuntimeException expected) { }
-
-
- try {
- byte[] b2 = {1, 2, 3, 4, 5};
- p = new IpPrefix(b2, 29);
- fail("Expected IllegalArgumentException: invalid array length");
- } catch (IllegalArgumentException expected) { }
-
- try {
- p = new IpPrefix("1.2.3.4");
- fail("Expected IllegalArgumentException: no prefix length");
- } catch (IllegalArgumentException expected) { }
-
- try {
- p = new IpPrefix("1.2.3.4/");
- fail("Expected IllegalArgumentException: empty prefix length");
- } catch (IllegalArgumentException expected) { }
-
- try {
- p = new IpPrefix("foo/32");
- fail("Expected IllegalArgumentException: invalid address");
- } catch (IllegalArgumentException expected) { }
-
- try {
- p = new IpPrefix("1/32");
- fail("Expected IllegalArgumentException: deprecated IPv4 format");
- } catch (IllegalArgumentException expected) { }
-
- try {
- p = new IpPrefix("1.2.3.256/32");
- fail("Expected IllegalArgumentException: invalid IPv4 address");
- } catch (IllegalArgumentException expected) { }
-
- try {
- p = new IpPrefix("foo/32");
- fail("Expected IllegalArgumentException: non-address");
- } catch (IllegalArgumentException expected) { }
-
- try {
- p = new IpPrefix("f00:::/32");
- fail("Expected IllegalArgumentException: invalid IPv6 address");
- } catch (IllegalArgumentException expected) { }
-
- p = new IpPrefix("/64");
- assertEquals("::/64", p.toString());
-
- p = new IpPrefix("/128");
- assertEquals("::1/128", p.toString());
-
- p = new IpPrefix("[2001:db8::123]/64");
- assertEquals("2001:db8::/64", p.toString());
- }
-
- @Test
- public void testTruncation() {
- IpPrefix p;
-
- p = new IpPrefix(IPV4_BYTES, 32);
- assertEquals("192.0.2.4/32", p.toString());
-
- p = new IpPrefix(IPV4_BYTES, 29);
- assertEquals("192.0.2.0/29", p.toString());
-
- p = new IpPrefix(IPV4_BYTES, 8);
- assertEquals("192.0.0.0/8", p.toString());
-
- p = new IpPrefix(IPV4_BYTES, 0);
- assertEquals("0.0.0.0/0", p.toString());
-
- try {
- p = new IpPrefix(IPV4_BYTES, 33);
- fail("Expected IllegalArgumentException: invalid prefix length");
- } catch (RuntimeException expected) { }
-
- try {
- p = new IpPrefix(IPV4_BYTES, 128);
- fail("Expected IllegalArgumentException: invalid prefix length");
- } catch (RuntimeException expected) { }
-
- try {
- p = new IpPrefix(IPV4_BYTES, -1);
- fail("Expected IllegalArgumentException: negative prefix length");
- } catch (RuntimeException expected) { }
-
- p = new IpPrefix(IPV6_BYTES, 128);
- assertEquals("2001:db8:dead:beef:f00::a0/128", p.toString());
-
- p = new IpPrefix(IPV6_BYTES, 122);
- assertEquals("2001:db8:dead:beef:f00::80/122", p.toString());
-
- p = new IpPrefix(IPV6_BYTES, 64);
- assertEquals("2001:db8:dead:beef::/64", p.toString());
-
- p = new IpPrefix(IPV6_BYTES, 3);
- assertEquals("2000::/3", p.toString());
-
- p = new IpPrefix(IPV6_BYTES, 0);
- assertEquals("::/0", p.toString());
-
- try {
- p = new IpPrefix(IPV6_BYTES, -1);
- fail("Expected IllegalArgumentException: negative prefix length");
- } catch (RuntimeException expected) { }
-
- try {
- p = new IpPrefix(IPV6_BYTES, 129);
- fail("Expected IllegalArgumentException: negative prefix length");
- } catch (RuntimeException expected) { }
-
- }
-
- @Test
- public void testEquals() {
- IpPrefix p1, p2;
-
- p1 = new IpPrefix("192.0.2.251/23");
- p2 = new IpPrefix(new byte[]{(byte) 192, (byte) 0, (byte) 2, (byte) 251}, 23);
- assertEqualBothWays(p1, p2);
-
- p1 = new IpPrefix("192.0.2.5/23");
- assertEqualBothWays(p1, p2);
-
- p1 = new IpPrefix("192.0.2.5/24");
- assertNotEqualEitherWay(p1, p2);
-
- p1 = new IpPrefix("192.0.4.5/23");
- assertNotEqualEitherWay(p1, p2);
-
-
- p1 = new IpPrefix("2001:db8:dead:beef:f00::80/122");
- p2 = new IpPrefix(IPV6_BYTES, 122);
- assertEquals("2001:db8:dead:beef:f00::80/122", p2.toString());
- assertEqualBothWays(p1, p2);
-
- p1 = new IpPrefix("2001:db8:dead:beef:f00::bf/122");
- assertEqualBothWays(p1, p2);
-
- p1 = new IpPrefix("2001:db8:dead:beef:f00::8:0/123");
- assertNotEqualEitherWay(p1, p2);
-
- p1 = new IpPrefix("2001:db8:dead:beef::/122");
- assertNotEqualEitherWay(p1, p2);
-
- // 192.0.2.4/32 != c000:0204::/32.
- byte[] ipv6bytes = new byte[16];
- System.arraycopy(IPV4_BYTES, 0, ipv6bytes, 0, IPV4_BYTES.length);
- p1 = new IpPrefix(ipv6bytes, 32);
- assertEqualBothWays(p1, new IpPrefix("c000:0204::/32"));
-
- p2 = new IpPrefix(IPV4_BYTES, 32);
- assertNotEqualEitherWay(p1, p2);
- }
-
- @Test
- public void testContainsInetAddress() {
- IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127");
- assertTrue(p.contains(address("2001:db8:f00::ace:d00c")));
- assertTrue(p.contains(address("2001:db8:f00::ace:d00d")));
- assertFalse(p.contains(address("2001:db8:f00::ace:d00e")));
- assertFalse(p.contains(address("2001:db8:f00::bad:d00d")));
- assertFalse(p.contains(address("2001:4868:4860::8888")));
- assertFalse(p.contains(address("8.8.8.8")));
-
- p = new IpPrefix("192.0.2.0/23");
- assertTrue(p.contains(address("192.0.2.43")));
- assertTrue(p.contains(address("192.0.3.21")));
- assertFalse(p.contains(address("192.0.0.21")));
- assertFalse(p.contains(address("8.8.8.8")));
- assertFalse(p.contains(address("2001:4868:4860::8888")));
-
- IpPrefix ipv6Default = new IpPrefix("::/0");
- assertTrue(ipv6Default.contains(address("2001:db8::f00")));
- assertFalse(ipv6Default.contains(address("192.0.2.1")));
-
- IpPrefix ipv4Default = new IpPrefix("0.0.0.0/0");
- assertTrue(ipv4Default.contains(address("255.255.255.255")));
- assertTrue(ipv4Default.contains(address("192.0.2.1")));
- assertFalse(ipv4Default.contains(address("2001:db8::f00")));
- }
-
- @Test
- public void testContainsIpPrefix() {
- assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("0.0.0.0/0")));
- assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/0")));
- assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/8")));
- assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/24")));
- assertTrue(new IpPrefix("0.0.0.0/0").containsPrefix(new IpPrefix("1.2.3.4/23")));
-
- assertTrue(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("1.2.3.4/8")));
- assertTrue(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("1.254.12.9/8")));
- assertTrue(new IpPrefix("1.2.3.4/21").containsPrefix(new IpPrefix("1.2.3.4/21")));
- assertTrue(new IpPrefix("1.2.3.4/32").containsPrefix(new IpPrefix("1.2.3.4/32")));
-
- assertTrue(new IpPrefix("1.2.3.4/20").containsPrefix(new IpPrefix("1.2.3.0/24")));
-
- assertFalse(new IpPrefix("1.2.3.4/32").containsPrefix(new IpPrefix("1.2.3.5/32")));
- assertFalse(new IpPrefix("1.2.3.4/8").containsPrefix(new IpPrefix("2.2.3.4/8")));
- assertFalse(new IpPrefix("0.0.0.0/16").containsPrefix(new IpPrefix("0.0.0.0/15")));
- assertFalse(new IpPrefix("100.0.0.0/8").containsPrefix(new IpPrefix("99.0.0.0/8")));
-
- assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("::/0")));
- assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/1")));
- assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("3d8a:661:a0::770/8")));
- assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/8")));
- assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/64")));
- assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/113")));
- assertTrue(new IpPrefix("::/0").containsPrefix(new IpPrefix("2001:db8::f00/128")));
-
- assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
- new IpPrefix("2001:db8:f00::ace:d00d/64")));
- assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
- new IpPrefix("2001:db8:f00::ace:d00d/120")));
- assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
- new IpPrefix("2001:db8:f00::ace:d00d/32")));
- assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/64").containsPrefix(
- new IpPrefix("2006:db8:f00::ace:d00d/96")));
-
- assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/128").containsPrefix(
- new IpPrefix("2001:db8:f00::ace:d00d/128")));
- assertTrue(new IpPrefix("2001:db8:f00::ace:d00d/100").containsPrefix(
- new IpPrefix("2001:db8:f00::ace:ccaf/110")));
-
- assertFalse(new IpPrefix("2001:db8:f00::ace:d00d/128").containsPrefix(
- new IpPrefix("2001:db8:f00::ace:d00e/128")));
- assertFalse(new IpPrefix("::/30").containsPrefix(new IpPrefix("::/29")));
- }
-
- @Test
- public void testHashCode() {
- IpPrefix p = new IpPrefix(new byte[4], 0);
- Random random = new Random();
- for (int i = 0; i < 100; i++) {
- final IpPrefix oldP = p;
- if (random.nextBoolean()) {
- // IPv4.
- byte[] b = new byte[4];
- random.nextBytes(b);
- p = new IpPrefix(b, random.nextInt(33));
- } else {
- // IPv6.
- byte[] b = new byte[16];
- random.nextBytes(b);
- p = new IpPrefix(b, random.nextInt(129));
- }
- if (p.equals(oldP)) {
- assertEquals(p.hashCode(), oldP.hashCode());
- }
- if (p.hashCode() != oldP.hashCode()) {
- assertNotEquals(p, oldP);
- }
- }
- }
-
- @Test
- public void testHashCodeIsNotConstant() {
- IpPrefix[] prefixes = {
- new IpPrefix("2001:db8:f00::ace:d00d/127"),
- new IpPrefix("192.0.2.0/23"),
- new IpPrefix("::/0"),
- new IpPrefix("0.0.0.0/0"),
- };
- for (int i = 0; i < prefixes.length; i++) {
- for (int j = i + 1; j < prefixes.length; j++) {
- assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode());
- }
- }
- }
-
- @Test
- public void testMappedAddressesAreBroken() {
- // 192.0.2.0/24 != ::ffff:c000:0204/120, but because we use InetAddress,
- // we are unable to comprehend that.
- byte[] ipv6bytes = {
- (byte) 0, (byte) 0, (byte) 0, (byte) 0,
- (byte) 0, (byte) 0, (byte) 0, (byte) 0,
- (byte) 0, (byte) 0, (byte) 0xff, (byte) 0xff,
- (byte) 192, (byte) 0, (byte) 2, (byte) 0};
- IpPrefix p = new IpPrefix(ipv6bytes, 120);
- assertEquals(16, p.getRawAddress().length); // Fine.
- assertArrayEquals(ipv6bytes, p.getRawAddress()); // Fine.
-
- // Broken.
- assertEquals("192.0.2.0/120", p.toString());
- assertEquals(InetAddress.parseNumericAddress("192.0.2.0"), p.getAddress());
- }
-
- @Test
- public void testParceling() {
- IpPrefix p;
-
- p = new IpPrefix("2001:4860:db8::/64");
- assertParcelingIsLossless(p);
- assertTrue(p.isIPv6());
-
- p = new IpPrefix("192.0.2.0/25");
- assertParcelingIsLossless(p);
- assertTrue(p.isIPv4());
-
- assertFieldCountEquals(2, IpPrefix.class);
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/KeepalivePacketDataTest.kt b/packages/Connectivity/tests/common/java/android/net/KeepalivePacketDataTest.kt
deleted file mode 100644
index f464ec6..0000000
--- a/packages/Connectivity/tests/common/java/android/net/KeepalivePacketDataTest.kt
+++ /dev/null
@@ -1,120 +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.net
-
-import android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS
-import android.net.InvalidPacketException.ERROR_INVALID_PORT
-import android.os.Build
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import java.net.InetAddress
-import java.util.Arrays
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
-import org.junit.Assert.fail
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class KeepalivePacketDataTest {
- @Rule @JvmField
- val ignoreRule: DevSdkIgnoreRule = DevSdkIgnoreRule()
-
- private val INVALID_PORT = 65537
- private val TEST_DST_PORT = 4244
- private val TEST_SRC_PORT = 4243
-
- private val TESTBYTES = byteArrayOf(12, 31, 22, 44)
- private val TEST_SRC_ADDRV4 = "198.168.0.2".address()
- private val TEST_DST_ADDRV4 = "198.168.0.1".address()
- private val TEST_ADDRV6 = "2001:db8::1".address()
-
- private fun String.address() = InetAddresses.parseNumericAddress(this)
-
- // Add for test because constructor of KeepalivePacketData is protected.
- private inner class TestKeepalivePacketData(
- srcAddress: InetAddress? = TEST_SRC_ADDRV4,
- srcPort: Int = TEST_SRC_PORT,
- dstAddress: InetAddress? = TEST_DST_ADDRV4,
- dstPort: Int = TEST_DST_PORT,
- data: ByteArray = TESTBYTES
- ) : KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, data)
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testConstructor() {
- var data: TestKeepalivePacketData
-
- try {
- data = TestKeepalivePacketData(srcAddress = null)
- fail("Null src address should cause exception")
- } catch (e: InvalidPacketException) {
- assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
- }
-
- try {
- data = TestKeepalivePacketData(dstAddress = null)
- fail("Null dst address should cause exception")
- } catch (e: InvalidPacketException) {
- assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
- }
-
- try {
- data = TestKeepalivePacketData(dstAddress = TEST_ADDRV6)
- fail("Ip family mismatched should cause exception")
- } catch (e: InvalidPacketException) {
- assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
- }
-
- try {
- data = TestKeepalivePacketData(srcPort = INVALID_PORT)
- fail("Invalid srcPort should cause exception")
- } catch (e: InvalidPacketException) {
- assertEquals(e.error, ERROR_INVALID_PORT)
- }
-
- try {
- data = TestKeepalivePacketData(dstPort = INVALID_PORT)
- fail("Invalid dstPort should cause exception")
- } catch (e: InvalidPacketException) {
- assertEquals(e.error, ERROR_INVALID_PORT)
- }
- }
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testSrcAddress() = assertEquals(TEST_SRC_ADDRV4, TestKeepalivePacketData().srcAddress)
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testDstAddress() = assertEquals(TEST_DST_ADDRV4, TestKeepalivePacketData().dstAddress)
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testSrcPort() = assertEquals(TEST_SRC_PORT, TestKeepalivePacketData().srcPort)
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testDstPort() = assertEquals(TEST_DST_PORT, TestKeepalivePacketData().dstPort)
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testPacket() = assertTrue(Arrays.equals(TESTBYTES, TestKeepalivePacketData().packet))
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/common/java/android/net/LinkAddressTest.java b/packages/Connectivity/tests/common/java/android/net/LinkAddressTest.java
deleted file mode 100644
index 2cf3cf9..0000000
--- a/packages/Connectivity/tests/common/java/android/net/LinkAddressTest.java
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.system.OsConstants.IFA_F_DADFAILED;
-import static android.system.OsConstants.IFA_F_DEPRECATED;
-import static android.system.OsConstants.IFA_F_OPTIMISTIC;
-import static android.system.OsConstants.IFA_F_PERMANENT;
-import static android.system.OsConstants.IFA_F_TEMPORARY;
-import static android.system.OsConstants.IFA_F_TENTATIVE;
-import static android.system.OsConstants.RT_SCOPE_HOST;
-import static android.system.OsConstants.RT_SCOPE_LINK;
-import static android.system.OsConstants.RT_SCOPE_SITE;
-import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
-
-import static com.android.testutils.MiscAsserts.assertEqualBothWays;
-import static com.android.testutils.MiscAsserts.assertFieldCountEquals;
-import static com.android.testutils.MiscAsserts.assertNotEqualEitherWay;
-import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.os.Build;
-import android.os.SystemClock;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InterfaceAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.util.Arrays;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class LinkAddressTest {
- @Rule
- public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
-
- private static final String V4 = "192.0.2.1";
- private static final String V6 = "2001:db8::1";
- private static final InetAddress V4_ADDRESS = InetAddresses.parseNumericAddress(V4);
- private static final InetAddress V6_ADDRESS = InetAddresses.parseNumericAddress(V6);
-
- @Test
- public void testConstants() {
- // RT_SCOPE_UNIVERSE = 0, but all the other constants should be nonzero.
- assertNotEquals(0, RT_SCOPE_HOST);
- assertNotEquals(0, RT_SCOPE_LINK);
- assertNotEquals(0, RT_SCOPE_SITE);
-
- assertNotEquals(0, IFA_F_DEPRECATED);
- assertNotEquals(0, IFA_F_PERMANENT);
- assertNotEquals(0, IFA_F_TENTATIVE);
- }
-
- @Test
- public void testConstructors() throws SocketException {
- LinkAddress address;
-
- // Valid addresses work as expected.
- address = new LinkAddress(V4_ADDRESS, 25);
- assertEquals(V4_ADDRESS, address.getAddress());
- assertEquals(25, address.getPrefixLength());
- assertEquals(0, address.getFlags());
- assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
- assertTrue(address.isIpv4());
-
- address = new LinkAddress(V6_ADDRESS, 127);
- assertEquals(V6_ADDRESS, address.getAddress());
- assertEquals(127, address.getPrefixLength());
- assertEquals(0, address.getFlags());
- assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
- assertTrue(address.isIpv6());
-
- // Nonsensical flags/scopes or combinations thereof are acceptable.
- address = new LinkAddress(V6 + "/64", IFA_F_DEPRECATED | IFA_F_PERMANENT, RT_SCOPE_LINK);
- assertEquals(V6_ADDRESS, address.getAddress());
- assertEquals(64, address.getPrefixLength());
- assertEquals(IFA_F_DEPRECATED | IFA_F_PERMANENT, address.getFlags());
- assertEquals(RT_SCOPE_LINK, address.getScope());
- assertTrue(address.isIpv6());
-
- address = new LinkAddress(V4 + "/23", 123, 456);
- assertEquals(V4_ADDRESS, address.getAddress());
- assertEquals(23, address.getPrefixLength());
- assertEquals(123, address.getFlags());
- assertEquals(456, address.getScope());
- assertTrue(address.isIpv4());
-
- address = new LinkAddress("/64", 1 /* flags */, 2 /* scope */);
- assertEquals(Inet6Address.LOOPBACK, address.getAddress());
- assertEquals(64, address.getPrefixLength());
- assertEquals(1, address.getFlags());
- assertEquals(2, address.getScope());
- assertTrue(address.isIpv6());
-
- address = new LinkAddress("[2001:db8::123]/64", 3 /* flags */, 4 /* scope */);
- assertEquals(InetAddresses.parseNumericAddress("2001:db8::123"), address.getAddress());
- assertEquals(64, address.getPrefixLength());
- assertEquals(3, address.getFlags());
- assertEquals(4, address.getScope());
- assertTrue(address.isIpv6());
-
- // InterfaceAddress doesn't have a constructor. Fetch some from an interface.
- List<InterfaceAddress> addrs = NetworkInterface.getByName("lo").getInterfaceAddresses();
-
- // We expect to find 127.0.0.1/8 and ::1/128, in any order.
- LinkAddress ipv4Loopback, ipv6Loopback;
- assertEquals(2, addrs.size());
- if (addrs.get(0).getAddress() instanceof Inet4Address) {
- ipv4Loopback = new LinkAddress(addrs.get(0));
- ipv6Loopback = new LinkAddress(addrs.get(1));
- } else {
- ipv4Loopback = new LinkAddress(addrs.get(1));
- ipv6Loopback = new LinkAddress(addrs.get(0));
- }
-
- assertEquals(InetAddresses.parseNumericAddress("127.0.0.1"), ipv4Loopback.getAddress());
- assertEquals(8, ipv4Loopback.getPrefixLength());
-
- assertEquals(InetAddresses.parseNumericAddress("::1"), ipv6Loopback.getAddress());
- assertEquals(128, ipv6Loopback.getPrefixLength());
-
- // Null addresses are rejected.
- try {
- address = new LinkAddress(null, 24);
- fail("Null InetAddress should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
- try {
- address = new LinkAddress((String) null, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
- fail("Null string should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
- try {
- address = new LinkAddress((InterfaceAddress) null);
- fail("Null string should cause NullPointerException");
- } catch(NullPointerException expected) {}
-
- // Invalid prefix lengths are rejected.
- try {
- address = new LinkAddress(V4_ADDRESS, -1);
- fail("Negative IPv4 prefix length should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
- try {
- address = new LinkAddress(V6_ADDRESS, -1);
- fail("Negative IPv6 prefix length should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
- try {
- address = new LinkAddress(V4_ADDRESS, 33);
- fail("/33 IPv4 prefix length should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
- try {
- address = new LinkAddress(V4 + "/33", IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
- fail("/33 IPv4 prefix length should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
-
- try {
- address = new LinkAddress(V6_ADDRESS, 129, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
- fail("/129 IPv6 prefix length should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
- try {
- address = new LinkAddress(V6 + "/129", IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
- fail("/129 IPv6 prefix length should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
- // Multicast addresses are rejected.
- try {
- address = new LinkAddress("224.0.0.2/32");
- fail("IPv4 multicast address should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
-
- try {
- address = new LinkAddress("ff02::1/128");
- fail("IPv6 multicast address should cause IllegalArgumentException");
- } catch(IllegalArgumentException expected) {}
- }
-
- @Test
- public void testAddressScopes() {
- assertEquals(RT_SCOPE_HOST, new LinkAddress("::/128").getScope());
- assertEquals(RT_SCOPE_HOST, new LinkAddress("0.0.0.0/32").getScope());
-
- assertEquals(RT_SCOPE_LINK, new LinkAddress("::1/128").getScope());
- assertEquals(RT_SCOPE_LINK, new LinkAddress("127.0.0.5/8").getScope());
- assertEquals(RT_SCOPE_LINK, new LinkAddress("fe80::ace:d00d/64").getScope());
- assertEquals(RT_SCOPE_LINK, new LinkAddress("169.254.5.12/16").getScope());
-
- assertEquals(RT_SCOPE_SITE, new LinkAddress("fec0::dead/64").getScope());
-
- assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("10.1.2.3/21").getScope());
- assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("192.0.2.1/25").getScope());
- assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("2001:db8::/64").getScope());
- assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("5000::/127").getScope());
- }
-
- private void assertIsSameAddressAs(LinkAddress l1, LinkAddress l2) {
- assertTrue(l1 + " unexpectedly does not have same address as " + l2,
- l1.isSameAddressAs(l2));
- assertTrue(l2 + " unexpectedly does not have same address as " + l1,
- l2.isSameAddressAs(l1));
- }
-
- private void assertIsNotSameAddressAs(LinkAddress l1, LinkAddress l2) {
- assertFalse(l1 + " unexpectedly has same address as " + l2,
- l1.isSameAddressAs(l2));
- assertFalse(l2 + " unexpectedly has same address as " + l1,
- l1.isSameAddressAs(l2));
- }
-
- @Test
- public void testEqualsAndSameAddressAs() {
- LinkAddress l1, l2, l3;
-
- l1 = new LinkAddress("2001:db8::1/64");
- l2 = new LinkAddress("2001:db8::1/64");
- assertEqualBothWays(l1, l2);
- assertIsSameAddressAs(l1, l2);
-
- l2 = new LinkAddress("2001:db8::1/65");
- assertNotEqualEitherWay(l1, l2);
- assertIsNotSameAddressAs(l1, l2);
-
- l2 = new LinkAddress("2001:db8::2/64");
- assertNotEqualEitherWay(l1, l2);
- assertIsNotSameAddressAs(l1, l2);
-
-
- l1 = new LinkAddress("192.0.2.1/24");
- l2 = new LinkAddress("192.0.2.1/24");
- assertEqualBothWays(l1, l2);
- assertIsSameAddressAs(l1, l2);
-
- l2 = new LinkAddress("192.0.2.1/23");
- assertNotEqualEitherWay(l1, l2);
- assertIsNotSameAddressAs(l1, l2);
-
- l2 = new LinkAddress("192.0.2.2/24");
- assertNotEqualEitherWay(l1, l2);
- assertIsNotSameAddressAs(l1, l2);
-
-
- // Check equals() and isSameAddressAs() on identical addresses with different flags.
- l1 = new LinkAddress(V6_ADDRESS, 64);
- l2 = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_UNIVERSE);
- assertEqualBothWays(l1, l2);
- assertIsSameAddressAs(l1, l2);
-
- l2 = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_UNIVERSE);
- assertNotEqualEitherWay(l1, l2);
- assertIsSameAddressAs(l1, l2);
-
- // Check equals() and isSameAddressAs() on identical addresses with different scope.
- l1 = new LinkAddress(V4_ADDRESS, 24);
- l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_UNIVERSE);
- assertEqualBothWays(l1, l2);
- assertIsSameAddressAs(l1, l2);
-
- l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_HOST);
- assertNotEqualEitherWay(l1, l2);
- assertIsSameAddressAs(l1, l2);
-
- // Addresses with the same start or end bytes aren't equal between families.
- l1 = new LinkAddress("32.1.13.184/24");
- l2 = new LinkAddress("2001:db8::1/24");
- l3 = new LinkAddress("::2001:db8/24");
-
- byte[] ipv4Bytes = l1.getAddress().getAddress();
- byte[] l2FirstIPv6Bytes = Arrays.copyOf(l2.getAddress().getAddress(), 4);
- byte[] l3LastIPv6Bytes = Arrays.copyOfRange(l3.getAddress().getAddress(), 12, 16);
- assertTrue(Arrays.equals(ipv4Bytes, l2FirstIPv6Bytes));
- assertTrue(Arrays.equals(ipv4Bytes, l3LastIPv6Bytes));
-
- assertNotEqualEitherWay(l1, l2);
- assertIsNotSameAddressAs(l1, l2);
-
- assertNotEqualEitherWay(l1, l3);
- assertIsNotSameAddressAs(l1, l3);
-
- // Because we use InetAddress, an IPv4 address is equal to its IPv4-mapped address.
- // TODO: Investigate fixing this.
- String addressString = V4 + "/24";
- l1 = new LinkAddress(addressString);
- l2 = new LinkAddress("::ffff:" + addressString);
- assertEqualBothWays(l1, l2);
- assertIsSameAddressAs(l1, l2);
- }
-
- @Test
- public void testHashCode() {
- LinkAddress l1, l2;
-
- l1 = new LinkAddress(V4_ADDRESS, 23);
- l2 = new LinkAddress(V4_ADDRESS, 23, 0, RT_SCOPE_HOST);
- assertNotEquals(l1.hashCode(), l2.hashCode());
-
- l1 = new LinkAddress(V6_ADDRESS, 128);
- l2 = new LinkAddress(V6_ADDRESS, 128, IFA_F_TENTATIVE, RT_SCOPE_UNIVERSE);
- assertNotEquals(l1.hashCode(), l2.hashCode());
- }
-
- @Test
- public void testParceling() {
- LinkAddress l;
-
- l = new LinkAddress(V6_ADDRESS, 64, 123, 456);
- assertParcelingIsLossless(l);
-
- l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK);
- assertParcelingIsLossless(l);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testLifetimeParceling() {
- final LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 123, 456, 1L, 3600000L);
- assertParcelingIsLossless(l);
- }
-
- @Test @IgnoreAfter(Build.VERSION_CODES.Q)
- public void testFieldCount_Q() {
- assertFieldCountEquals(4, LinkAddress.class);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testFieldCount() {
- // Make sure any new field is covered by the above parceling tests when changing this number
- assertFieldCountEquals(6, LinkAddress.class);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testDeprecationTime() {
- try {
- new LinkAddress(V6_ADDRESS, 64, 0, 456,
- LinkAddress.LIFETIME_UNKNOWN, 100000L);
- fail("Only one time provided should cause exception");
- } catch (IllegalArgumentException expected) { }
-
- try {
- new LinkAddress(V6_ADDRESS, 64, 0, 456,
- 200000L, 100000L);
- fail("deprecation time later than expiration time should cause exception");
- } catch (IllegalArgumentException expected) { }
-
- try {
- new LinkAddress(V6_ADDRESS, 64, 0, 456,
- -2, 100000L);
- fail("negative deprecation time should cause exception");
- } catch (IllegalArgumentException expected) { }
-
- LinkAddress addr = new LinkAddress(V6_ADDRESS, 64, 0, 456, 100000L, 200000L);
- assertEquals(100000L, addr.getDeprecationTime());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testExpirationTime() {
- try {
- new LinkAddress(V6_ADDRESS, 64, 0, 456,
- 200000L, LinkAddress.LIFETIME_UNKNOWN);
- fail("Only one time provided should cause exception");
- } catch (IllegalArgumentException expected) { }
-
- try {
- new LinkAddress(V6_ADDRESS, 64, 0, 456,
- 100000L, -2);
- fail("negative expiration time should cause exception");
- } catch (IllegalArgumentException expected) { }
-
- LinkAddress addr = new LinkAddress(V6_ADDRESS, 64, 0, 456, 100000L, 200000L);
- assertEquals(200000L, addr.getExpirationTime());
- }
-
- @Test
- public void testGetFlags() {
- LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 123, RT_SCOPE_HOST);
- assertEquals(123, l.getFlags());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testGetFlags_Deprecation() {
- // Test if deprecated bit was added/remove automatically based on the provided deprecation
- // time
- LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_HOST,
- 1L, LinkAddress.LIFETIME_PERMANENT);
- // Check if the flag is added automatically.
- assertTrue((l.getFlags() & IFA_F_DEPRECATED) != 0);
-
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
- SystemClock.elapsedRealtime() + 100000L, LinkAddress.LIFETIME_PERMANENT);
- // Check if the flag is removed automatically.
- assertTrue((l.getFlags() & IFA_F_DEPRECATED) == 0);
-
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
- LinkAddress.LIFETIME_PERMANENT, LinkAddress.LIFETIME_PERMANENT);
- // Check if the permanent flag is added.
- assertTrue((l.getFlags() & IFA_F_PERMANENT) != 0);
-
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_PERMANENT, RT_SCOPE_HOST,
- 1000L, SystemClock.elapsedRealtime() + 100000L);
- // Check if the permanent flag is removed
- assertTrue((l.getFlags() & IFA_F_PERMANENT) == 0);
- }
-
- private void assertGlobalPreferred(LinkAddress l, String msg) {
- assertTrue(msg, l.isGlobalPreferred());
- }
-
- private void assertNotGlobalPreferred(LinkAddress l, String msg) {
- assertFalse(msg, l.isGlobalPreferred());
- }
-
- @Test
- public void testIsGlobalPreferred() {
- LinkAddress l;
-
- l = new LinkAddress(V4_ADDRESS, 32, 0, RT_SCOPE_UNIVERSE);
- assertGlobalPreferred(l, "v4,global,noflags");
-
- l = new LinkAddress("10.10.1.7/23", 0, RT_SCOPE_UNIVERSE);
- assertGlobalPreferred(l, "v4-rfc1918,global,noflags");
-
- l = new LinkAddress("10.10.1.7/23", 0, RT_SCOPE_SITE);
- assertNotGlobalPreferred(l, "v4-rfc1918,site-local,noflags");
-
- l = new LinkAddress("127.0.0.7/8", 0, RT_SCOPE_HOST);
- assertNotGlobalPreferred(l, "v4-localhost,node-local,noflags");
-
- l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_UNIVERSE);
- assertGlobalPreferred(l, "v6,global,noflags");
-
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE);
- assertGlobalPreferred(l, "v6,global,permanent");
-
- // IPv6 ULAs are not acceptable "global preferred" addresses.
- l = new LinkAddress("fc12::1/64", 0, RT_SCOPE_UNIVERSE);
- assertNotGlobalPreferred(l, "v6,ula1,noflags");
-
- l = new LinkAddress("fd34::1/64", 0, RT_SCOPE_UNIVERSE);
- assertNotGlobalPreferred(l, "v6,ula2,noflags");
-
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_UNIVERSE);
- assertGlobalPreferred(l, "v6,global,tempaddr");
-
- l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_DADFAILED),
- RT_SCOPE_UNIVERSE);
- assertNotGlobalPreferred(l, "v6,global,tempaddr+dadfailed");
-
- l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_DEPRECATED),
- RT_SCOPE_UNIVERSE);
- assertNotGlobalPreferred(l, "v6,global,tempaddr+deprecated");
-
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_SITE);
- assertNotGlobalPreferred(l, "v6,site-local,tempaddr");
-
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_LINK);
- assertNotGlobalPreferred(l, "v6,link-local,tempaddr");
-
- l = new LinkAddress(V6_ADDRESS, 64, IFA_F_TEMPORARY, RT_SCOPE_HOST);
- assertNotGlobalPreferred(l, "v6,node-local,tempaddr");
-
- l = new LinkAddress("::1/128", IFA_F_PERMANENT, RT_SCOPE_HOST);
- assertNotGlobalPreferred(l, "v6-localhost,node-local,permanent");
-
- l = new LinkAddress(V6_ADDRESS, 64, (IFA_F_TEMPORARY|IFA_F_TENTATIVE),
- RT_SCOPE_UNIVERSE);
- assertNotGlobalPreferred(l, "v6,global,tempaddr+tentative");
-
- l = new LinkAddress(V6_ADDRESS, 64,
- (IFA_F_TEMPORARY|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC),
- RT_SCOPE_UNIVERSE);
- assertGlobalPreferred(l, "v6,global,tempaddr+optimistic");
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testIsGlobalPreferred_DeprecatedInFuture() {
- final LinkAddress l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED,
- RT_SCOPE_UNIVERSE, SystemClock.elapsedRealtime() + 100000,
- SystemClock.elapsedRealtime() + 200000);
- // Although the deprecated bit is set, but the deprecation time is in the future, test
- // if the flag is removed automatically.
- assertGlobalPreferred(l, "v6,global,tempaddr+deprecated in the future");
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/LinkPropertiesTest.java b/packages/Connectivity/tests/common/java/android/net/LinkPropertiesTest.java
deleted file mode 100644
index 550953d..0000000
--- a/packages/Connectivity/tests/common/java/android/net/LinkPropertiesTest.java
+++ /dev/null
@@ -1,1271 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.RouteInfo.RTN_THROW;
-import static android.net.RouteInfo.RTN_UNICAST;
-import static android.net.RouteInfo.RTN_UNREACHABLE;
-
-import static com.android.testutils.ParcelUtils.assertParcelSane;
-import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
-import static com.android.testutils.ParcelUtils.parcelingRoundTrip;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.LinkProperties.ProvisioningChange;
-import android.os.Build;
-import android.system.OsConstants;
-import android.util.ArraySet;
-
-import androidx.core.os.BuildCompat;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class LinkPropertiesTest {
- @Rule
- public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
-
- private static final InetAddress ADDRV4 = address("75.208.6.1");
- private static final InetAddress ADDRV6 = address("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
- private static final InetAddress DNS1 = address("75.208.7.1");
- private static final InetAddress DNS2 = address("69.78.7.1");
- private static final InetAddress DNS6 = address("2001:4860:4860::8888");
- private static final InetAddress PRIVDNS1 = address("1.1.1.1");
- private static final InetAddress PRIVDNS2 = address("1.0.0.1");
- private static final InetAddress PRIVDNS6 = address("2606:4700:4700::1111");
- private static final InetAddress PCSCFV4 = address("10.77.25.37");
- private static final InetAddress PCSCFV6 = address("2001:0db8:85a3:0000:0000:8a2e:0370:1");
- private static final InetAddress GATEWAY1 = address("75.208.8.1");
- private static final InetAddress GATEWAY2 = address("69.78.8.1");
- private static final InetAddress GATEWAY61 = address("fe80::6:0000:613");
- private static final InetAddress GATEWAY62 = address("fe80::6:22%lo");
- private static final InetAddress TESTIPV4ADDR = address("192.168.47.42");
- private static final InetAddress TESTIPV6ADDR = address("fe80::7:33%43");
- private static final Inet4Address DHCPSERVER = (Inet4Address) address("192.0.2.1");
- private static final String NAME = "qmi0";
- private static final String DOMAINS = "google.com";
- private static final String PRIV_DNS_SERVER_NAME = "private.dns.com";
- private static final String TCP_BUFFER_SIZES = "524288,1048576,2097152,262144,524288,1048576";
- private static final int MTU = 1500;
- private static final LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32);
- private static final LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
- private static final LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64");
- private static final Uri CAPPORT_API_URL = Uri.parse("https://test.example.com/capportapi");
-
- // CaptivePortalData cannot be in a constant as it does not exist on Q.
- // The test runner also crashes when scanning for tests if it is a return type.
- private static Object getCaptivePortalData() {
- return new CaptivePortalData.Builder()
- .setVenueInfoUrl(Uri.parse("https://test.example.com/venue")).build();
- }
-
- private static InetAddress address(String addrString) {
- return InetAddresses.parseNumericAddress(addrString);
- }
-
- private static boolean isAtLeastR() {
- // BuildCompat.isAtLeastR is documented to return false on release SDKs (including R)
- return Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR();
- }
-
- private void checkEmpty(final LinkProperties lp) {
- assertEquals(0, lp.getAllInterfaceNames().size());
- assertEquals(0, lp.getAllAddresses().size());
- assertEquals(0, lp.getDnsServers().size());
- assertEquals(0, lp.getValidatedPrivateDnsServers().size());
- assertEquals(0, lp.getPcscfServers().size());
- assertEquals(0, lp.getAllRoutes().size());
- assertEquals(0, lp.getAllLinkAddresses().size());
- assertEquals(0, lp.getStackedLinks().size());
- assertEquals(0, lp.getMtu());
- assertNull(lp.getPrivateDnsServerName());
- assertNull(lp.getDomains());
- assertNull(lp.getHttpProxy());
- assertNull(lp.getTcpBufferSizes());
- assertNull(lp.getNat64Prefix());
- assertFalse(lp.isProvisioned());
- assertFalse(lp.isIpv4Provisioned());
- assertFalse(lp.isIpv6Provisioned());
- assertFalse(lp.isPrivateDnsActive());
-
- if (isAtLeastR()) {
- assertNull(lp.getDhcpServerAddress());
- assertFalse(lp.isWakeOnLanSupported());
- assertNull(lp.getCaptivePortalApiUrl());
- assertNull(lp.getCaptivePortalData());
- }
- }
-
- private LinkProperties makeTestObject() {
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(NAME);
- lp.addLinkAddress(LINKADDRV4);
- lp.addLinkAddress(LINKADDRV6);
- lp.addDnsServer(DNS1);
- lp.addDnsServer(DNS2);
- lp.addValidatedPrivateDnsServer(PRIVDNS1);
- lp.addValidatedPrivateDnsServer(PRIVDNS2);
- lp.setUsePrivateDns(true);
- lp.setPrivateDnsServerName(PRIV_DNS_SERVER_NAME);
- lp.addPcscfServer(PCSCFV6);
- lp.setDomains(DOMAINS);
- lp.addRoute(new RouteInfo(GATEWAY1));
- lp.addRoute(new RouteInfo(GATEWAY2));
- lp.setHttpProxy(ProxyInfo.buildDirectProxy("test", 8888));
- lp.setMtu(MTU);
- lp.setTcpBufferSizes(TCP_BUFFER_SIZES);
- lp.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96"));
- if (isAtLeastR()) {
- lp.setDhcpServerAddress(DHCPSERVER);
- lp.setWakeOnLanSupported(true);
- lp.setCaptivePortalApiUrl(CAPPORT_API_URL);
- lp.setCaptivePortalData((CaptivePortalData) getCaptivePortalData());
- }
- return lp;
- }
-
- public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) {
- // Check implementation of equals(), element by element.
- assertTrue(source.isIdenticalInterfaceName(target));
- assertTrue(target.isIdenticalInterfaceName(source));
-
- assertTrue(source.isIdenticalAddresses(target));
- assertTrue(target.isIdenticalAddresses(source));
-
- assertTrue(source.isIdenticalDnses(target));
- assertTrue(target.isIdenticalDnses(source));
-
- assertTrue(source.isIdenticalPrivateDns(target));
- assertTrue(target.isIdenticalPrivateDns(source));
-
- assertTrue(source.isIdenticalValidatedPrivateDnses(target));
- assertTrue(target.isIdenticalValidatedPrivateDnses(source));
-
- assertTrue(source.isIdenticalPcscfs(target));
- assertTrue(target.isIdenticalPcscfs(source));
-
- assertTrue(source.isIdenticalRoutes(target));
- assertTrue(target.isIdenticalRoutes(source));
-
- assertTrue(source.isIdenticalHttpProxy(target));
- assertTrue(target.isIdenticalHttpProxy(source));
-
- assertTrue(source.isIdenticalStackedLinks(target));
- assertTrue(target.isIdenticalStackedLinks(source));
-
- assertTrue(source.isIdenticalMtu(target));
- assertTrue(target.isIdenticalMtu(source));
-
- assertTrue(source.isIdenticalTcpBufferSizes(target));
- assertTrue(target.isIdenticalTcpBufferSizes(source));
-
- if (isAtLeastR()) {
- assertTrue(source.isIdenticalDhcpServerAddress(target));
- assertTrue(source.isIdenticalDhcpServerAddress(source));
-
- assertTrue(source.isIdenticalWakeOnLan(target));
- assertTrue(target.isIdenticalWakeOnLan(source));
-
- assertTrue(source.isIdenticalCaptivePortalApiUrl(target));
- assertTrue(target.isIdenticalCaptivePortalApiUrl(source));
-
- assertTrue(source.isIdenticalCaptivePortalData(target));
- assertTrue(target.isIdenticalCaptivePortalData(source));
- }
-
- // Check result of equals().
- assertTrue(source.equals(target));
- assertTrue(target.equals(source));
-
- // Check hashCode.
- assertEquals(source.hashCode(), target.hashCode());
- }
-
- @Test
- public void testEqualsNull() {
- LinkProperties source = new LinkProperties();
- LinkProperties target = new LinkProperties();
-
- assertFalse(source == target);
- assertLinkPropertiesEqual(source, target);
- }
-
- @Test
- public void testEqualsSameOrder() throws Exception {
- LinkProperties source = new LinkProperties();
- source.setInterfaceName(NAME);
- // set 2 link addresses
- source.addLinkAddress(LINKADDRV4);
- source.addLinkAddress(LINKADDRV6);
- // set 2 dnses
- source.addDnsServer(DNS1);
- source.addDnsServer(DNS2);
- // set 1 pcscf
- source.addPcscfServer(PCSCFV6);
- // set 2 gateways
- source.addRoute(new RouteInfo(GATEWAY1));
- source.addRoute(new RouteInfo(GATEWAY2));
- source.setMtu(MTU);
-
- LinkProperties target = new LinkProperties();
-
- // All fields are same
- target.setInterfaceName(NAME);
- target.addLinkAddress(LINKADDRV4);
- target.addLinkAddress(LINKADDRV6);
- target.addDnsServer(DNS1);
- target.addDnsServer(DNS2);
- target.addPcscfServer(PCSCFV6);
- target.addRoute(new RouteInfo(GATEWAY1));
- target.addRoute(new RouteInfo(GATEWAY2));
- target.setMtu(MTU);
-
- assertLinkPropertiesEqual(source, target);
-
- target.clear();
- // change Interface Name
- target.setInterfaceName("qmi1");
- target.addLinkAddress(LINKADDRV4);
- target.addLinkAddress(LINKADDRV6);
- target.addDnsServer(DNS1);
- target.addDnsServer(DNS2);
- target.addPcscfServer(PCSCFV6);
- target.addRoute(new RouteInfo(GATEWAY1));
- target.addRoute(new RouteInfo(GATEWAY2));
- target.setMtu(MTU);
- assertFalse(source.equals(target));
-
- target.clear();
- target.setInterfaceName(NAME);
- // change link addresses
- target.addLinkAddress(new LinkAddress(address("75.208.6.2"), 32));
- target.addLinkAddress(LINKADDRV6);
- target.addDnsServer(DNS1);
- target.addDnsServer(DNS2);
- target.addPcscfServer(PCSCFV6);
- target.addRoute(new RouteInfo(GATEWAY1));
- target.addRoute(new RouteInfo(GATEWAY2));
- target.setMtu(MTU);
- assertFalse(source.equals(target));
-
- target.clear();
- target.setInterfaceName(NAME);
- target.addLinkAddress(LINKADDRV4);
- target.addLinkAddress(LINKADDRV6);
- // change dnses
- target.addDnsServer(address("75.208.7.2"));
- target.addDnsServer(DNS2);
- target.addPcscfServer(PCSCFV6);
- target.addRoute(new RouteInfo(GATEWAY1));
- target.addRoute(new RouteInfo(GATEWAY2));
- target.setMtu(MTU);
- assertFalse(source.equals(target));
-
- target.clear();
- target.setInterfaceName(NAME);
- target.addLinkAddress(LINKADDRV4);
- target.addLinkAddress(LINKADDRV6);
- target.addDnsServer(address("75.208.7.2"));
- target.addDnsServer(DNS2);
- // change pcscf
- target.addPcscfServer(address("2001::1"));
- target.addRoute(new RouteInfo(GATEWAY1));
- target.addRoute(new RouteInfo(GATEWAY2));
- target.setMtu(MTU);
- assertFalse(source.equals(target));
-
- target.clear();
- target.setInterfaceName(NAME);
- target.addLinkAddress(LINKADDRV4);
- target.addLinkAddress(LINKADDRV6);
- target.addDnsServer(DNS1);
- target.addDnsServer(DNS2);
- // change gateway
- target.addRoute(new RouteInfo(address("75.208.8.2")));
- target.setMtu(MTU);
- target.addRoute(new RouteInfo(GATEWAY2));
- assertFalse(source.equals(target));
-
- target.clear();
- target.setInterfaceName(NAME);
- target.addLinkAddress(LINKADDRV4);
- target.addLinkAddress(LINKADDRV6);
- target.addDnsServer(DNS1);
- target.addDnsServer(DNS2);
- target.addRoute(new RouteInfo(GATEWAY1));
- target.addRoute(new RouteInfo(GATEWAY2));
- // change mtu
- target.setMtu(1440);
- assertFalse(source.equals(target));
- }
-
- @Test
- public void testEqualsDifferentOrder() throws Exception {
- LinkProperties source = new LinkProperties();
- source.setInterfaceName(NAME);
- // set 2 link addresses
- source.addLinkAddress(LINKADDRV4);
- source.addLinkAddress(LINKADDRV6);
- // set 2 dnses
- source.addDnsServer(DNS1);
- source.addDnsServer(DNS2);
- // set 2 gateways
- source.addRoute(new RouteInfo(LINKADDRV4, GATEWAY1));
- source.addRoute(new RouteInfo(GATEWAY2));
- source.setMtu(MTU);
-
- LinkProperties target = new LinkProperties();
- // Exchange order
- target.setInterfaceName(NAME);
- target.addLinkAddress(LINKADDRV6);
- target.addLinkAddress(LINKADDRV4);
- target.addDnsServer(DNS2);
- target.addDnsServer(DNS1);
- target.addRoute(new RouteInfo(GATEWAY2));
- target.addRoute(new RouteInfo(LINKADDRV4, GATEWAY1));
- target.setMtu(MTU);
-
- assertLinkPropertiesEqual(source, target);
- }
-
- @Test
- public void testEqualsDuplicated() throws Exception {
- LinkProperties source = new LinkProperties();
- // set 3 link addresses, eg, [A, A, B]
- source.addLinkAddress(LINKADDRV4);
- source.addLinkAddress(LINKADDRV4);
- source.addLinkAddress(LINKADDRV6);
-
- LinkProperties target = new LinkProperties();
- // set 3 link addresses, eg, [A, B, B]
- target.addLinkAddress(LINKADDRV4);
- target.addLinkAddress(LINKADDRV6);
- target.addLinkAddress(LINKADDRV6);
-
- assertLinkPropertiesEqual(source, target);
- }
-
- private void assertAllRoutesHaveInterface(String iface, LinkProperties lp) {
- for (RouteInfo r : lp.getRoutes()) {
- assertEquals(iface, r.getInterface());
- }
- }
-
- private void assertAllRoutesNotHaveInterface(String iface, LinkProperties lp) {
- for (RouteInfo r : lp.getRoutes()) {
- assertNotEquals(iface, r.getInterface());
- }
- }
-
- @Test
- public void testRouteInterfaces() {
- LinkAddress prefix1 = new LinkAddress(address("2001:db8:1::"), 48);
- LinkAddress prefix2 = new LinkAddress(address("2001:db8:2::"), 48);
- InetAddress address = ADDRV6;
-
- // Add a route with no interface to a LinkProperties with no interface. No errors.
- LinkProperties lp = new LinkProperties();
- RouteInfo r = new RouteInfo(prefix1, address, null);
- assertTrue(lp.addRoute(r));
- assertEquals(1, lp.getRoutes().size());
- assertAllRoutesHaveInterface(null, lp);
-
- // Adding the same route twice has no effect.
- assertFalse(lp.addRoute(r));
- assertEquals(1, lp.getRoutes().size());
-
- // Add a route with an interface. Expect an exception.
- r = new RouteInfo(prefix2, address, "wlan0");
- try {
- lp.addRoute(r);
- fail("Adding wlan0 route to LP with no interface, expect exception");
- } catch (IllegalArgumentException expected) {}
-
- // Change the interface name. All the routes should change their interface name too.
- lp.setInterfaceName("rmnet0");
- assertAllRoutesHaveInterface("rmnet0", lp);
- assertAllRoutesNotHaveInterface(null, lp);
- assertAllRoutesNotHaveInterface("wlan0", lp);
-
- // Now add a route with the wrong interface. This causes an exception too.
- try {
- lp.addRoute(r);
- fail("Adding wlan0 route to rmnet0 LP, expect exception");
- } catch (IllegalArgumentException expected) {}
-
- // If the interface name matches, the route is added.
- r = new RouteInfo(prefix2, null, "wlan0");
- lp.setInterfaceName("wlan0");
- lp.addRoute(r);
- assertEquals(2, lp.getRoutes().size());
- assertAllRoutesHaveInterface("wlan0", lp);
- assertAllRoutesNotHaveInterface("rmnet0", lp);
-
- // Routes with null interfaces are converted to wlan0.
- r = RouteInfo.makeHostRoute(ADDRV6, null);
- lp.addRoute(r);
- assertEquals(3, lp.getRoutes().size());
- assertAllRoutesHaveInterface("wlan0", lp);
-
- // Check routes are updated correctly when calling setInterfaceName.
- LinkProperties lp2 = new LinkProperties(lp);
- assertAllRoutesHaveInterface("wlan0", lp2);
- final CompareResult<RouteInfo> cr1 =
- new CompareResult<>(lp.getAllRoutes(), lp2.getAllRoutes());
- assertEquals(0, cr1.added.size());
- assertEquals(0, cr1.removed.size());
-
- lp2.setInterfaceName("p2p0");
- assertAllRoutesHaveInterface("p2p0", lp2);
- assertAllRoutesNotHaveInterface("wlan0", lp2);
- final CompareResult<RouteInfo> cr2 =
- new CompareResult<>(lp.getAllRoutes(), lp2.getAllRoutes());
- assertEquals(3, cr2.added.size());
- assertEquals(3, cr2.removed.size());
-
- // Remove route with incorrect interface, no route removed.
- lp.removeRoute(new RouteInfo(prefix2, null, null));
- assertEquals(3, lp.getRoutes().size());
-
- // Check remove works when interface is correct.
- lp.removeRoute(new RouteInfo(prefix2, null, "wlan0"));
- assertEquals(2, lp.getRoutes().size());
- assertAllRoutesHaveInterface("wlan0", lp);
- assertAllRoutesNotHaveInterface("p2p0", lp);
- }
-
- @Test
- public void testStackedInterfaces() {
- LinkProperties rmnet0 = new LinkProperties();
- rmnet0.setInterfaceName("rmnet0");
- rmnet0.addLinkAddress(LINKADDRV6);
-
- LinkProperties clat4 = new LinkProperties();
- clat4.setInterfaceName("clat4");
- clat4.addLinkAddress(LINKADDRV4);
-
- assertEquals(0, rmnet0.getStackedLinks().size());
- assertEquals(1, rmnet0.getAddresses().size());
- assertEquals(1, rmnet0.getLinkAddresses().size());
- assertEquals(1, rmnet0.getAllAddresses().size());
- assertEquals(1, rmnet0.getAllLinkAddresses().size());
- assertEquals(1, rmnet0.getAllInterfaceNames().size());
- assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
-
- rmnet0.addStackedLink(clat4);
- assertEquals(1, rmnet0.getStackedLinks().size());
- assertEquals(1, rmnet0.getAddresses().size());
- assertEquals(1, rmnet0.getLinkAddresses().size());
- assertEquals(2, rmnet0.getAllAddresses().size());
- assertEquals(2, rmnet0.getAllLinkAddresses().size());
- assertEquals(2, rmnet0.getAllInterfaceNames().size());
- assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
- assertEquals("clat4", rmnet0.getAllInterfaceNames().get(1));
-
- rmnet0.addStackedLink(clat4);
- assertEquals(1, rmnet0.getStackedLinks().size());
- assertEquals(1, rmnet0.getAddresses().size());
- assertEquals(1, rmnet0.getLinkAddresses().size());
- assertEquals(2, rmnet0.getAllAddresses().size());
- assertEquals(2, rmnet0.getAllLinkAddresses().size());
- assertEquals(2, rmnet0.getAllInterfaceNames().size());
- assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
- assertEquals("clat4", rmnet0.getAllInterfaceNames().get(1));
-
- assertEquals(0, clat4.getStackedLinks().size());
-
- // Modify an item in the returned collection to see what happens.
- for (LinkProperties link : rmnet0.getStackedLinks()) {
- if (link.getInterfaceName().equals("clat4")) {
- link.setInterfaceName("newname");
- }
- }
- for (LinkProperties link : rmnet0.getStackedLinks()) {
- assertFalse("newname".equals(link.getInterfaceName()));
- }
-
- assertTrue(rmnet0.removeStackedLink("clat4"));
- assertEquals(0, rmnet0.getStackedLinks().size());
- assertEquals(1, rmnet0.getAddresses().size());
- assertEquals(1, rmnet0.getLinkAddresses().size());
- assertEquals(1, rmnet0.getAllAddresses().size());
- assertEquals(1, rmnet0.getAllLinkAddresses().size());
- assertEquals(1, rmnet0.getAllInterfaceNames().size());
- assertEquals("rmnet0", rmnet0.getAllInterfaceNames().get(0));
-
- assertFalse(rmnet0.removeStackedLink("clat4"));
- }
-
- private LinkAddress getFirstLinkAddress(LinkProperties lp) {
- return lp.getLinkAddresses().iterator().next();
- }
-
- @Test
- public void testAddressMethods() {
- LinkProperties lp = new LinkProperties();
-
- // No addresses.
- assertFalse(lp.hasIpv4Address());
- assertFalse(lp.hasGlobalIpv6Address());
-
- // Addresses on stacked links don't count.
- LinkProperties stacked = new LinkProperties();
- stacked.setInterfaceName("stacked");
- lp.addStackedLink(stacked);
- stacked.addLinkAddress(LINKADDRV4);
- stacked.addLinkAddress(LINKADDRV6);
- assertTrue(stacked.hasIpv4Address());
- assertTrue(stacked.hasGlobalIpv6Address());
- assertFalse(lp.hasIpv4Address());
- assertFalse(lp.hasGlobalIpv6Address());
- lp.removeStackedLink("stacked");
- assertFalse(lp.hasIpv4Address());
- assertFalse(lp.hasGlobalIpv6Address());
-
- // Addresses on the base link.
- // Check the return values of hasIpvXAddress and ensure the add/remove methods return true
- // iff something changes.
- assertEquals(0, lp.getLinkAddresses().size());
- assertTrue(lp.addLinkAddress(LINKADDRV6));
- assertEquals(1, lp.getLinkAddresses().size());
- assertFalse(lp.hasIpv4Address());
- assertTrue(lp.hasGlobalIpv6Address());
-
- assertTrue(lp.removeLinkAddress(LINKADDRV6));
- assertEquals(0, lp.getLinkAddresses().size());
-
- assertTrue(lp.addLinkAddress(LINKADDRV6LINKLOCAL));
- assertEquals(1, lp.getLinkAddresses().size());
- assertFalse(lp.hasGlobalIpv6Address());
-
- assertTrue(lp.addLinkAddress(LINKADDRV4));
- assertEquals(2, lp.getLinkAddresses().size());
- assertTrue(lp.hasIpv4Address());
- assertFalse(lp.hasGlobalIpv6Address());
-
- assertTrue(lp.addLinkAddress(LINKADDRV6));
- assertEquals(3, lp.getLinkAddresses().size());
- assertTrue(lp.hasIpv4Address());
- assertTrue(lp.hasGlobalIpv6Address());
-
- assertTrue(lp.removeLinkAddress(LINKADDRV6LINKLOCAL));
- assertEquals(2, lp.getLinkAddresses().size());
- assertTrue(lp.hasIpv4Address());
- assertTrue(lp.hasGlobalIpv6Address());
-
- // Adding an address twice has no effect.
- // Removing an address that's not present has no effect.
- assertFalse(lp.addLinkAddress(LINKADDRV4));
- assertEquals(2, lp.getLinkAddresses().size());
- assertTrue(lp.hasIpv4Address());
- assertTrue(lp.removeLinkAddress(LINKADDRV4));
- assertEquals(1, lp.getLinkAddresses().size());
- assertFalse(lp.hasIpv4Address());
- assertFalse(lp.removeLinkAddress(LINKADDRV4));
- assertEquals(1, lp.getLinkAddresses().size());
-
- // Adding an address that's already present but with different properties causes the
- // existing address to be updated and returns true.
- // Start with only LINKADDRV6.
- assertEquals(1, lp.getLinkAddresses().size());
- assertEquals(LINKADDRV6, getFirstLinkAddress(lp));
-
- // Create a LinkAddress object for the same address, but with different flags.
- LinkAddress deprecated = new LinkAddress(ADDRV6, 128,
- OsConstants.IFA_F_DEPRECATED, OsConstants.RT_SCOPE_UNIVERSE);
- assertTrue(deprecated.isSameAddressAs(LINKADDRV6));
- assertFalse(deprecated.equals(LINKADDRV6));
-
- // Check that adding it updates the existing address instead of adding a new one.
- assertTrue(lp.addLinkAddress(deprecated));
- assertEquals(1, lp.getLinkAddresses().size());
- assertEquals(deprecated, getFirstLinkAddress(lp));
- assertFalse(LINKADDRV6.equals(getFirstLinkAddress(lp)));
-
- // Removing LINKADDRV6 removes deprecated, because removing addresses ignores properties.
- assertTrue(lp.removeLinkAddress(LINKADDRV6));
- assertEquals(0, lp.getLinkAddresses().size());
- }
-
- @Test
- public void testLinkAddresses() {
- final LinkProperties lp = new LinkProperties();
- lp.addLinkAddress(LINKADDRV4);
- lp.addLinkAddress(LINKADDRV6);
-
- final LinkProperties lp2 = new LinkProperties();
- lp2.addLinkAddress(LINKADDRV6);
-
- final LinkProperties lp3 = new LinkProperties();
- final List<LinkAddress> linkAddresses = Arrays.asList(LINKADDRV4);
- lp3.setLinkAddresses(linkAddresses);
-
- assertFalse(lp.equals(lp2));
- assertFalse(lp2.equals(lp3));
-
- lp.removeLinkAddress(LINKADDRV4);
- assertTrue(lp.equals(lp2));
-
- lp2.setLinkAddresses(lp3.getLinkAddresses());
- assertTrue(lp2.equals(lp3));
- }
-
- @Test
- public void testNat64Prefix() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.addLinkAddress(LINKADDRV4);
- lp.addLinkAddress(LINKADDRV6);
-
- assertNull(lp.getNat64Prefix());
-
- IpPrefix p = new IpPrefix("64:ff9b::/96");
- lp.setNat64Prefix(p);
- assertEquals(p, lp.getNat64Prefix());
-
- p = new IpPrefix("2001:db8:a:b:1:2:3::/96");
- lp.setNat64Prefix(p);
- assertEquals(p, lp.getNat64Prefix());
-
- p = new IpPrefix("2001:db8:a:b:1:2::/80");
- try {
- lp.setNat64Prefix(p);
- } catch (IllegalArgumentException expected) {
- }
-
- p = new IpPrefix("64:ff9b::/64");
- try {
- lp.setNat64Prefix(p);
- } catch (IllegalArgumentException expected) {
- }
-
- assertEquals(new IpPrefix("2001:db8:a:b:1:2:3::/96"), lp.getNat64Prefix());
-
- lp.setNat64Prefix(null);
- assertNull(lp.getNat64Prefix());
- }
-
- @Test
- public void testIsProvisioned() {
- LinkProperties lp4 = new LinkProperties();
- assertFalse("v4only:empty", lp4.isProvisioned());
- lp4.addLinkAddress(LINKADDRV4);
- assertFalse("v4only:addr-only", lp4.isProvisioned());
- lp4.addDnsServer(DNS1);
- assertFalse("v4only:addr+dns", lp4.isProvisioned());
- lp4.addRoute(new RouteInfo(GATEWAY1));
- assertTrue("v4only:addr+dns+route", lp4.isProvisioned());
- assertTrue("v4only:addr+dns+route", lp4.isIpv4Provisioned());
- assertFalse("v4only:addr+dns+route", lp4.isIpv6Provisioned());
-
- LinkProperties lp6 = new LinkProperties();
- assertFalse("v6only:empty", lp6.isProvisioned());
- lp6.addLinkAddress(LINKADDRV6LINKLOCAL);
- assertFalse("v6only:fe80-only", lp6.isProvisioned());
- lp6.addDnsServer(DNS6);
- assertFalse("v6only:fe80+dns", lp6.isProvisioned());
- lp6.addRoute(new RouteInfo(GATEWAY61));
- assertFalse("v6only:fe80+dns+route", lp6.isProvisioned());
- lp6.addLinkAddress(LINKADDRV6);
- assertTrue("v6only:fe80+global+dns+route", lp6.isIpv6Provisioned());
- assertTrue("v6only:fe80+global+dns+route", lp6.isProvisioned());
- lp6.removeLinkAddress(LINKADDRV6LINKLOCAL);
- assertFalse("v6only:global+dns+route", lp6.isIpv4Provisioned());
- assertTrue("v6only:global+dns+route", lp6.isIpv6Provisioned());
- assertTrue("v6only:global+dns+route", lp6.isProvisioned());
-
- LinkProperties lp46 = new LinkProperties();
- lp46.addLinkAddress(LINKADDRV4);
- lp46.addLinkAddress(LINKADDRV6);
- lp46.addDnsServer(DNS1);
- lp46.addDnsServer(DNS6);
- assertFalse("dualstack:missing-routes", lp46.isProvisioned());
- lp46.addRoute(new RouteInfo(GATEWAY1));
- assertTrue("dualstack:v4-provisioned", lp46.isIpv4Provisioned());
- assertFalse("dualstack:v4-provisioned", lp46.isIpv6Provisioned());
- assertTrue("dualstack:v4-provisioned", lp46.isProvisioned());
- lp46.addRoute(new RouteInfo(GATEWAY61));
- assertTrue("dualstack:both-provisioned", lp46.isIpv4Provisioned());
- assertTrue("dualstack:both-provisioned", lp46.isIpv6Provisioned());
- assertTrue("dualstack:both-provisioned", lp46.isProvisioned());
-
- // A link with an IPv6 address and default route, but IPv4 DNS server.
- LinkProperties mixed = new LinkProperties();
- mixed.addLinkAddress(LINKADDRV6);
- mixed.addDnsServer(DNS1);
- mixed.addRoute(new RouteInfo(GATEWAY61));
- assertFalse("mixed:addr6+route6+dns4", mixed.isIpv4Provisioned());
- assertFalse("mixed:addr6+route6+dns4", mixed.isIpv6Provisioned());
- assertFalse("mixed:addr6+route6+dns4", mixed.isProvisioned());
- }
-
- @Test
- public void testCompareProvisioning() {
- LinkProperties v4lp = new LinkProperties();
- v4lp.addLinkAddress(LINKADDRV4);
- v4lp.addRoute(new RouteInfo(GATEWAY1));
- v4lp.addDnsServer(DNS1);
- assertTrue(v4lp.isProvisioned());
-
- LinkProperties v4r = new LinkProperties(v4lp);
- v4r.removeDnsServer(DNS1);
- assertFalse(v4r.isProvisioned());
-
- assertEquals(ProvisioningChange.STILL_NOT_PROVISIONED,
- LinkProperties.compareProvisioning(v4r, v4r));
- assertEquals(ProvisioningChange.LOST_PROVISIONING,
- LinkProperties.compareProvisioning(v4lp, v4r));
- assertEquals(ProvisioningChange.GAINED_PROVISIONING,
- LinkProperties.compareProvisioning(v4r, v4lp));
- assertEquals(ProvisioningChange.STILL_PROVISIONED,
- LinkProperties.compareProvisioning(v4lp, v4lp));
-
- // Check that losing IPv4 provisioning on a dualstack network is
- // seen as a total loss of provisioning.
- LinkProperties v6lp = new LinkProperties();
- v6lp.addLinkAddress(LINKADDRV6);
- v6lp.addRoute(new RouteInfo(GATEWAY61));
- v6lp.addDnsServer(DNS6);
- assertFalse(v6lp.isIpv4Provisioned());
- assertTrue(v6lp.isIpv6Provisioned());
- assertTrue(v6lp.isProvisioned());
-
- LinkProperties v46lp = new LinkProperties(v6lp);
- v46lp.addLinkAddress(LINKADDRV4);
- v46lp.addRoute(new RouteInfo(GATEWAY1));
- v46lp.addDnsServer(DNS1);
- assertTrue(v46lp.isIpv4Provisioned());
- assertTrue(v46lp.isIpv6Provisioned());
- assertTrue(v46lp.isProvisioned());
-
- assertEquals(ProvisioningChange.STILL_PROVISIONED,
- LinkProperties.compareProvisioning(v4lp, v46lp));
- assertEquals(ProvisioningChange.STILL_PROVISIONED,
- LinkProperties.compareProvisioning(v6lp, v46lp));
- assertEquals(ProvisioningChange.LOST_PROVISIONING,
- LinkProperties.compareProvisioning(v46lp, v6lp));
- assertEquals(ProvisioningChange.LOST_PROVISIONING,
- LinkProperties.compareProvisioning(v46lp, v4lp));
-
- // Check that losing and gaining a secondary router does not change
- // the provisioning status.
- LinkProperties v6lp2 = new LinkProperties(v6lp);
- v6lp2.addRoute(new RouteInfo(GATEWAY62));
- assertTrue(v6lp2.isProvisioned());
-
- assertEquals(ProvisioningChange.STILL_PROVISIONED,
- LinkProperties.compareProvisioning(v6lp2, v6lp));
- assertEquals(ProvisioningChange.STILL_PROVISIONED,
- LinkProperties.compareProvisioning(v6lp, v6lp2));
- }
-
- @Test
- public void testIsReachable() {
- final LinkProperties v4lp = new LinkProperties();
- assertFalse(v4lp.isReachable(DNS1));
- assertFalse(v4lp.isReachable(DNS2));
-
- // Add an on-link route, making the on-link DNS server reachable,
- // but there is still no IPv4 address.
- assertTrue(v4lp.addRoute(new RouteInfo(new IpPrefix(address("75.208.0.0"), 16))));
- assertFalse(v4lp.isReachable(DNS1));
- assertFalse(v4lp.isReachable(DNS2));
-
- // Adding an IPv4 address (right now, any IPv4 address) means we use
- // the routes to compute likely reachability.
- assertTrue(v4lp.addLinkAddress(new LinkAddress(ADDRV4, 16)));
- assertTrue(v4lp.isReachable(DNS1));
- assertFalse(v4lp.isReachable(DNS2));
-
- // Adding a default route makes the off-link DNS server reachable.
- assertTrue(v4lp.addRoute(new RouteInfo(GATEWAY1)));
- assertTrue(v4lp.isReachable(DNS1));
- assertTrue(v4lp.isReachable(DNS2));
-
- final LinkProperties v6lp = new LinkProperties();
- final InetAddress kLinkLocalDns = address("fe80::6:1");
- final InetAddress kLinkLocalDnsWithScope = address("fe80::6:2%43");
- final InetAddress kOnLinkDns = address("2001:db8:85a3::53");
- assertFalse(v6lp.isReachable(kLinkLocalDns));
- assertFalse(v6lp.isReachable(kLinkLocalDnsWithScope));
- assertFalse(v6lp.isReachable(kOnLinkDns));
- assertFalse(v6lp.isReachable(DNS6));
-
- // Add a link-local route, making the link-local DNS servers reachable. Because
- // we assume the presence of an IPv6 link-local address, link-local DNS servers
- // are considered reachable, but only those with a non-zero scope identifier.
- assertTrue(v6lp.addRoute(new RouteInfo(new IpPrefix(address("fe80::"), 64))));
- assertFalse(v6lp.isReachable(kLinkLocalDns));
- assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
- assertFalse(v6lp.isReachable(kOnLinkDns));
- assertFalse(v6lp.isReachable(DNS6));
-
- // Add a link-local address--nothing changes.
- assertTrue(v6lp.addLinkAddress(LINKADDRV6LINKLOCAL));
- assertFalse(v6lp.isReachable(kLinkLocalDns));
- assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
- assertFalse(v6lp.isReachable(kOnLinkDns));
- assertFalse(v6lp.isReachable(DNS6));
-
- // Add a global route on link, but no global address yet. DNS servers reachable
- // via a route that doesn't require a gateway: give them the benefit of the
- // doubt and hope the link-local source address suffices for communication.
- assertTrue(v6lp.addRoute(new RouteInfo(new IpPrefix(address("2001:db8:85a3::"), 64))));
- assertFalse(v6lp.isReachable(kLinkLocalDns));
- assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
- assertTrue(v6lp.isReachable(kOnLinkDns));
- assertFalse(v6lp.isReachable(DNS6));
-
- // Add a global address; the on-link global address DNS server is (still)
- // presumed reachable.
- assertTrue(v6lp.addLinkAddress(new LinkAddress(ADDRV6, 64)));
- assertFalse(v6lp.isReachable(kLinkLocalDns));
- assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
- assertTrue(v6lp.isReachable(kOnLinkDns));
- assertFalse(v6lp.isReachable(DNS6));
-
- // Adding a default route makes the off-link DNS server reachable.
- assertTrue(v6lp.addRoute(new RouteInfo(GATEWAY62)));
- assertFalse(v6lp.isReachable(kLinkLocalDns));
- assertTrue(v6lp.isReachable(kLinkLocalDnsWithScope));
- assertTrue(v6lp.isReachable(kOnLinkDns));
- assertTrue(v6lp.isReachable(DNS6));
-
- // Check isReachable on stacked links. This requires that the source IP address be assigned
- // on the interface returned by the route lookup.
- LinkProperties stacked = new LinkProperties();
-
- // Can't add a stacked link without an interface name.
- stacked.setInterfaceName("v4-test0");
- v6lp.addStackedLink(stacked);
-
- InetAddress stackedAddress = address("192.0.0.4");
- LinkAddress stackedLinkAddress = new LinkAddress(stackedAddress, 32);
- assertFalse(v6lp.isReachable(stackedAddress));
- stacked.addLinkAddress(stackedLinkAddress);
- assertFalse(v6lp.isReachable(stackedAddress));
- stacked.addRoute(new RouteInfo(stackedLinkAddress));
- assertTrue(stacked.isReachable(stackedAddress));
- assertTrue(v6lp.isReachable(stackedAddress));
-
- assertFalse(v6lp.isReachable(DNS1));
- stacked.addRoute(new RouteInfo((IpPrefix) null, stackedAddress));
- assertTrue(v6lp.isReachable(DNS1));
- }
-
- @Test
- public void testLinkPropertiesEnsureDirectlyConnectedRoutes() {
- // IPv4 case: no route added initially
- LinkProperties rmnet0 = new LinkProperties();
- rmnet0.setInterfaceName("rmnet0");
- rmnet0.addLinkAddress(new LinkAddress("10.0.0.2/8"));
- RouteInfo directRoute0 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
- rmnet0.getInterfaceName());
-
- // Since no routes is added explicitly, getAllRoutes() should return empty.
- assertTrue(rmnet0.getAllRoutes().isEmpty());
- rmnet0.ensureDirectlyConnectedRoutes();
- // ensureDirectlyConnectedRoutes() should have added the missing local route.
- assertEqualRoutes(Collections.singletonList(directRoute0), rmnet0.getAllRoutes());
-
- // IPv4 case: both direct and default routes added initially
- LinkProperties rmnet1 = new LinkProperties();
- rmnet1.setInterfaceName("rmnet1");
- rmnet1.addLinkAddress(new LinkAddress("10.0.0.3/8"));
- RouteInfo defaultRoute1 = new RouteInfo((IpPrefix) null, address("10.0.0.1"),
- rmnet1.getInterfaceName());
- RouteInfo directRoute1 = new RouteInfo(new IpPrefix("10.0.0.0/8"), null,
- rmnet1.getInterfaceName());
- rmnet1.addRoute(defaultRoute1);
- rmnet1.addRoute(directRoute1);
-
- // Check added routes
- assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes());
- // ensureDirectlyConnectedRoutes() shouldn't change the routes since direct connected
- // route is already part of the configuration.
- rmnet1.ensureDirectlyConnectedRoutes();
- assertEqualRoutes(Arrays.asList(defaultRoute1, directRoute1), rmnet1.getAllRoutes());
-
- // IPv6 case: only default routes added initially
- LinkProperties rmnet2 = new LinkProperties();
- rmnet2.setInterfaceName("rmnet2");
- rmnet2.addLinkAddress(new LinkAddress("fe80::cafe/64"));
- rmnet2.addLinkAddress(new LinkAddress("2001:db8::2/64"));
- RouteInfo defaultRoute2 = new RouteInfo((IpPrefix) null, address("2001:db8::1"),
- rmnet2.getInterfaceName());
- RouteInfo directRoute2 = new RouteInfo(new IpPrefix("2001:db8::/64"), null,
- rmnet2.getInterfaceName());
- RouteInfo linkLocalRoute2 = new RouteInfo(new IpPrefix("fe80::/64"), null,
- rmnet2.getInterfaceName());
- rmnet2.addRoute(defaultRoute2);
-
- assertEqualRoutes(Arrays.asList(defaultRoute2), rmnet2.getAllRoutes());
- rmnet2.ensureDirectlyConnectedRoutes();
- assertEqualRoutes(Arrays.asList(defaultRoute2, directRoute2, linkLocalRoute2),
- rmnet2.getAllRoutes());
-
- // Corner case: no interface name
- LinkProperties rmnet3 = new LinkProperties();
- rmnet3.addLinkAddress(new LinkAddress("192.168.0.2/24"));
- RouteInfo directRoute3 = new RouteInfo(new IpPrefix("192.168.0.0/24"), null,
- rmnet3.getInterfaceName());
-
- assertTrue(rmnet3.getAllRoutes().isEmpty());
- rmnet3.ensureDirectlyConnectedRoutes();
- assertEqualRoutes(Collections.singletonList(directRoute3), rmnet3.getAllRoutes());
- }
-
- private void assertEqualRoutes(Collection<RouteInfo> expected, Collection<RouteInfo> actual) {
- Set<RouteInfo> expectedSet = new ArraySet<>(expected);
- Set<RouteInfo> actualSet = new ArraySet<>(actual);
- // Duplicated entries in actual routes are considered failures
- assertEquals(actual.size(), actualSet.size());
-
- assertEquals(expectedSet, actualSet);
- }
-
- private static LinkProperties makeLinkPropertiesForParceling() {
- LinkProperties source = new LinkProperties();
- source.setInterfaceName(NAME);
-
- source.addLinkAddress(LINKADDRV4);
- source.addLinkAddress(LINKADDRV6);
-
- source.addDnsServer(DNS1);
- source.addDnsServer(DNS2);
- source.addDnsServer(GATEWAY62);
-
- source.addPcscfServer(TESTIPV4ADDR);
- source.addPcscfServer(TESTIPV6ADDR);
-
- source.setUsePrivateDns(true);
- source.setPrivateDnsServerName(PRIV_DNS_SERVER_NAME);
-
- source.setDomains(DOMAINS);
-
- source.addRoute(new RouteInfo(GATEWAY1));
- source.addRoute(new RouteInfo(GATEWAY2));
-
- source.addValidatedPrivateDnsServer(DNS6);
- source.addValidatedPrivateDnsServer(GATEWAY61);
- source.addValidatedPrivateDnsServer(TESTIPV6ADDR);
-
- source.setHttpProxy(ProxyInfo.buildDirectProxy("test", 8888));
-
- source.setMtu(MTU);
-
- source.setTcpBufferSizes(TCP_BUFFER_SIZES);
-
- source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96"));
-
- final LinkProperties stacked = new LinkProperties();
- stacked.setInterfaceName("test-stacked");
- source.addStackedLink(stacked);
-
- return source;
- }
-
- @Test @IgnoreAfter(Build.VERSION_CODES.Q)
- public void testLinkPropertiesParcelable_Q() throws Exception {
- final LinkProperties source = makeLinkPropertiesForParceling();
- assertParcelSane(source, 14 /* fieldCount */);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testLinkPropertiesParcelable() throws Exception {
- final LinkProperties source = makeLinkPropertiesForParceling();
-
- source.setWakeOnLanSupported(true);
- source.setCaptivePortalApiUrl(CAPPORT_API_URL);
- source.setCaptivePortalData((CaptivePortalData) getCaptivePortalData());
- source.setDhcpServerAddress((Inet4Address) GATEWAY1);
- assertParcelSane(new LinkProperties(source, true /* parcelSensitiveFields */),
- 18 /* fieldCount */);
-
- // Verify that without using a sensitiveFieldsParcelingCopy, sensitive fields are cleared.
- final LinkProperties sanitized = new LinkProperties(source);
- sanitized.setCaptivePortalApiUrl(null);
- sanitized.setCaptivePortalData(null);
- assertEquals(sanitized, parcelingRoundTrip(source));
- }
-
- // Parceling of the scope was broken until Q-QPR2
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testLinkLocalDnsServerParceling() throws Exception {
- final String strAddress = "fe80::1%lo";
- final LinkProperties lp = new LinkProperties();
- lp.addDnsServer(address(strAddress));
- final LinkProperties unparceled = parcelingRoundTrip(lp);
- // Inet6Address#equals does not test for the scope id
- assertEquals(strAddress, unparceled.getDnsServers().get(0).getHostAddress());
- }
-
- @Test
- public void testParcelUninitialized() throws Exception {
- LinkProperties empty = new LinkProperties();
- assertParcelingIsLossless(empty);
- }
-
- @Test
- public void testConstructor() {
- LinkProperties lp = new LinkProperties();
- checkEmpty(lp);
- assertLinkPropertiesEqual(lp, new LinkProperties(lp));
- assertLinkPropertiesEqual(lp, new LinkProperties());
-
- lp = makeTestObject();
- assertLinkPropertiesEqual(lp, new LinkProperties(lp));
- }
-
- @Test
- public void testDnsServers() {
- final LinkProperties lp = new LinkProperties();
- final List<InetAddress> dnsServers = Arrays.asList(DNS1, DNS2);
- lp.setDnsServers(dnsServers);
- assertEquals(2, lp.getDnsServers().size());
- assertEquals(DNS1, lp.getDnsServers().get(0));
- assertEquals(DNS2, lp.getDnsServers().get(1));
-
- lp.removeDnsServer(DNS1);
- assertEquals(1, lp.getDnsServers().size());
- assertEquals(DNS2, lp.getDnsServers().get(0));
-
- lp.addDnsServer(DNS6);
- assertEquals(2, lp.getDnsServers().size());
- assertEquals(DNS2, lp.getDnsServers().get(0));
- assertEquals(DNS6, lp.getDnsServers().get(1));
- }
-
- @Test
- public void testValidatedPrivateDnsServers() {
- final LinkProperties lp = new LinkProperties();
- final List<InetAddress> privDnsServers = Arrays.asList(PRIVDNS1, PRIVDNS2);
- lp.setValidatedPrivateDnsServers(privDnsServers);
- assertEquals(2, lp.getValidatedPrivateDnsServers().size());
- assertEquals(PRIVDNS1, lp.getValidatedPrivateDnsServers().get(0));
- assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(1));
-
- lp.removeValidatedPrivateDnsServer(PRIVDNS1);
- assertEquals(1, lp.getValidatedPrivateDnsServers().size());
- assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(0));
-
- lp.addValidatedPrivateDnsServer(PRIVDNS6);
- assertEquals(2, lp.getValidatedPrivateDnsServers().size());
- assertEquals(PRIVDNS2, lp.getValidatedPrivateDnsServers().get(0));
- assertEquals(PRIVDNS6, lp.getValidatedPrivateDnsServers().get(1));
- }
-
- @Test
- public void testPcscfServers() {
- final LinkProperties lp = new LinkProperties();
- final List<InetAddress> pcscfServers = Arrays.asList(PCSCFV4);
- lp.setPcscfServers(pcscfServers);
- assertEquals(1, lp.getPcscfServers().size());
- assertEquals(PCSCFV4, lp.getPcscfServers().get(0));
-
- lp.removePcscfServer(PCSCFV4);
- assertEquals(0, lp.getPcscfServers().size());
-
- lp.addPcscfServer(PCSCFV6);
- assertEquals(1, lp.getPcscfServers().size());
- assertEquals(PCSCFV6, lp.getPcscfServers().get(0));
- }
-
- @Test
- public void testTcpBufferSizes() {
- final LinkProperties lp = makeTestObject();
- assertEquals(TCP_BUFFER_SIZES, lp.getTcpBufferSizes());
-
- lp.setTcpBufferSizes(null);
- assertNull(lp.getTcpBufferSizes());
- }
-
- @Test
- public void testHasIpv6DefaultRoute() {
- final LinkProperties lp = makeTestObject();
- assertFalse(lp.hasIPv6DefaultRoute());
-
- lp.addRoute(new RouteInfo(GATEWAY61));
- assertTrue(lp.hasIPv6DefaultRoute());
- }
-
- @Test
- public void testHttpProxy() {
- final LinkProperties lp = makeTestObject();
- assertTrue(lp.getHttpProxy().equals(ProxyInfo.buildDirectProxy("test", 8888)));
- }
-
- @Test
- public void testPrivateDnsServerName() {
- final LinkProperties lp = makeTestObject();
- assertEquals(PRIV_DNS_SERVER_NAME, lp.getPrivateDnsServerName());
-
- lp.setPrivateDnsServerName(null);
- assertNull(lp.getPrivateDnsServerName());
- }
-
- @Test
- public void testUsePrivateDns() {
- final LinkProperties lp = makeTestObject();
- assertTrue(lp.isPrivateDnsActive());
-
- lp.clear();
- assertFalse(lp.isPrivateDnsActive());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testDhcpServerAddress() {
- final LinkProperties lp = makeTestObject();
- assertEquals(DHCPSERVER, lp.getDhcpServerAddress());
-
- lp.clear();
- assertNull(lp.getDhcpServerAddress());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testWakeOnLanSupported() {
- final LinkProperties lp = makeTestObject();
- assertTrue(lp.isWakeOnLanSupported());
-
- lp.clear();
- assertFalse(lp.isWakeOnLanSupported());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testCaptivePortalApiUrl() {
- final LinkProperties lp = makeTestObject();
- assertEquals(CAPPORT_API_URL, lp.getCaptivePortalApiUrl());
-
- lp.clear();
- assertNull(lp.getCaptivePortalApiUrl());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testCaptivePortalData() {
- final LinkProperties lp = makeTestObject();
- assertEquals(getCaptivePortalData(), lp.getCaptivePortalData());
-
- lp.clear();
- assertNull(lp.getCaptivePortalData());
- }
-
- private LinkProperties makeIpv4LinkProperties() {
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setInterfaceName(NAME);
- linkProperties.addLinkAddress(LINKADDRV4);
- linkProperties.addDnsServer(DNS1);
- linkProperties.addRoute(new RouteInfo(GATEWAY1));
- linkProperties.addRoute(new RouteInfo(GATEWAY2));
- return linkProperties;
- }
-
- private LinkProperties makeIpv6LinkProperties() {
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setInterfaceName(NAME);
- linkProperties.addLinkAddress(LINKADDRV6);
- linkProperties.addDnsServer(DNS6);
- linkProperties.addRoute(new RouteInfo(GATEWAY61));
- linkProperties.addRoute(new RouteInfo(GATEWAY62));
- return linkProperties;
- }
-
- @Test
- public void testHasIpv4DefaultRoute() {
- final LinkProperties Ipv4 = makeIpv4LinkProperties();
- assertTrue(Ipv4.hasIpv4DefaultRoute());
- final LinkProperties Ipv6 = makeIpv6LinkProperties();
- assertFalse(Ipv6.hasIpv4DefaultRoute());
- }
-
- @Test
- public void testHasIpv4DnsServer() {
- final LinkProperties Ipv4 = makeIpv4LinkProperties();
- assertTrue(Ipv4.hasIpv4DnsServer());
- final LinkProperties Ipv6 = makeIpv6LinkProperties();
- assertFalse(Ipv6.hasIpv4DnsServer());
- }
-
- @Test
- public void testHasIpv6DnsServer() {
- final LinkProperties Ipv4 = makeIpv4LinkProperties();
- assertFalse(Ipv4.hasIpv6DnsServer());
- final LinkProperties Ipv6 = makeIpv6LinkProperties();
- assertTrue(Ipv6.hasIpv6DnsServer());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testHasIpv4UnreachableDefaultRoute() {
- final LinkProperties lp = makeTestObject();
- assertFalse(lp.hasIpv4UnreachableDefaultRoute());
- assertFalse(lp.hasIpv6UnreachableDefaultRoute());
-
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
- assertTrue(lp.hasIpv4UnreachableDefaultRoute());
- assertFalse(lp.hasIpv6UnreachableDefaultRoute());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testHasIpv6UnreachableDefaultRoute() {
- final LinkProperties lp = makeTestObject();
- assertFalse(lp.hasIpv6UnreachableDefaultRoute());
- assertFalse(lp.hasIpv4UnreachableDefaultRoute());
-
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
- assertTrue(lp.hasIpv6UnreachableDefaultRoute());
- assertFalse(lp.hasIpv4UnreachableDefaultRoute());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testRouteAddWithSameKey() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("wlan0");
- final IpPrefix v6 = new IpPrefix("64:ff9b::/96");
- lp.addRoute(new RouteInfo(v6, address("fe80::1"), "wlan0", RTN_UNICAST, 1280));
- assertEquals(1, lp.getRoutes().size());
- lp.addRoute(new RouteInfo(v6, address("fe80::1"), "wlan0", RTN_UNICAST, 1500));
- assertEquals(1, lp.getRoutes().size());
- final IpPrefix v4 = new IpPrefix("192.0.2.128/25");
- lp.addRoute(new RouteInfo(v4, address("192.0.2.1"), "wlan0", RTN_UNICAST, 1460));
- assertEquals(2, lp.getRoutes().size());
- lp.addRoute(new RouteInfo(v4, address("192.0.2.1"), "wlan0", RTN_THROW, 1460));
- assertEquals(2, lp.getRoutes().size());
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/MatchAllNetworkSpecifierTest.kt b/packages/Connectivity/tests/common/java/android/net/MatchAllNetworkSpecifierTest.kt
deleted file mode 100644
index a5e44d5..0000000
--- a/packages/Connectivity/tests/common/java/android/net/MatchAllNetworkSpecifierTest.kt
+++ /dev/null
@@ -1,75 +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.net
-
-import android.net.wifi.aware.DiscoverySession
-import android.net.wifi.aware.PeerHandle
-import android.net.wifi.aware.WifiAwareNetworkSpecifier
-import android.os.Build
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-
-import com.android.testutils.assertParcelSane
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-
-import java.lang.IllegalStateException
-
-import org.junit.Assert.assertFalse
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class MatchAllNetworkSpecifierTest {
- @Rule @JvmField
- val ignoreRule: DevSdkIgnoreRule = DevSdkIgnoreRule()
-
- private val specifier = MatchAllNetworkSpecifier()
- private val discoverySession = Mockito.mock(DiscoverySession::class.java)
- private val peerHandle = Mockito.mock(PeerHandle::class.java)
- private val wifiAwareNetworkSpecifier = WifiAwareNetworkSpecifier.Builder(discoverySession,
- peerHandle).build()
-
- @Test
- fun testParcel() {
- assertParcelSane(MatchAllNetworkSpecifier(), 0)
- }
-
- @Test
- @IgnoreUpTo(Build.VERSION_CODES.Q)
- @IgnoreAfter(Build.VERSION_CODES.R)
- // Only run this test on Android R.
- // The method - satisfiedBy() has changed to canBeSatisfiedBy() starting from Android R, so the
- // method - canBeSatisfiedBy() cannot be found when running this test on Android Q.
- fun testCanBeSatisfiedBy_OnlyForR() {
- // MatchAllNetworkSpecifier didn't follow its parent class to change the satisfiedBy() to
- // canBeSatisfiedBy(), so if a caller calls MatchAllNetworkSpecifier#canBeSatisfiedBy(), the
- // NetworkSpecifier#canBeSatisfiedBy() will be called actually, and false will be returned.
- // Although it's not meeting the expectation, the behavior still needs to be verified.
- assertFalse(specifier.canBeSatisfiedBy(wifiAwareNetworkSpecifier))
- }
-
- @Test(expected = IllegalStateException::class)
- @IgnoreUpTo(Build.VERSION_CODES.R)
- fun testCanBeSatisfiedBy() {
- specifier.canBeSatisfiedBy(wifiAwareNetworkSpecifier)
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/NattKeepalivePacketDataTest.kt b/packages/Connectivity/tests/common/java/android/net/NattKeepalivePacketDataTest.kt
deleted file mode 100644
index 46f39dd..0000000
--- a/packages/Connectivity/tests/common/java/android/net/NattKeepalivePacketDataTest.kt
+++ /dev/null
@@ -1,114 +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.net
-
-import android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS
-import android.net.InvalidPacketException.ERROR_INVALID_PORT
-import android.net.NattSocketKeepalive.NATT_PORT
-import android.os.Build
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertEqualBothWays
-import com.android.testutils.assertFieldCountEquals
-import com.android.testutils.assertParcelSane
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import com.android.testutils.parcelingRoundTrip
-import java.net.InetAddress
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNotEquals
-import org.junit.Assert.fail
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class NattKeepalivePacketDataTest {
- @Rule @JvmField
- val ignoreRule: DevSdkIgnoreRule = DevSdkIgnoreRule()
-
- /* Refer to the definition in {@code NattKeepalivePacketData} */
- private val IPV4_HEADER_LENGTH = 20
- private val UDP_HEADER_LENGTH = 8
-
- private val TEST_PORT = 4243
- private val TEST_PORT2 = 4244
- private val TEST_SRC_ADDRV4 = "198.168.0.2".address()
- private val TEST_DST_ADDRV4 = "198.168.0.1".address()
- private val TEST_ADDRV6 = "2001:db8::1".address()
-
- private fun String.address() = InetAddresses.parseNumericAddress(this)
- private fun nattKeepalivePacket(
- srcAddress: InetAddress? = TEST_SRC_ADDRV4,
- srcPort: Int = TEST_PORT,
- dstAddress: InetAddress? = TEST_DST_ADDRV4,
- dstPort: Int = NATT_PORT
- ) = NattKeepalivePacketData.nattKeepalivePacket(srcAddress, srcPort, dstAddress, dstPort)
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testConstructor() {
- try {
- nattKeepalivePacket(dstPort = TEST_PORT)
- fail("Dst port is not NATT port should cause exception")
- } catch (e: InvalidPacketException) {
- assertEquals(e.error, ERROR_INVALID_PORT)
- }
-
- try {
- nattKeepalivePacket(srcAddress = TEST_ADDRV6)
- fail("A v6 srcAddress should cause exception")
- } catch (e: InvalidPacketException) {
- assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
- }
-
- try {
- nattKeepalivePacket(dstAddress = TEST_ADDRV6)
- fail("A v6 dstAddress should cause exception")
- } catch (e: InvalidPacketException) {
- assertEquals(e.error, ERROR_INVALID_IP_ADDRESS)
- }
-
- try {
- parcelingRoundTrip(
- NattKeepalivePacketData(TEST_SRC_ADDRV4, TEST_PORT, TEST_DST_ADDRV4, TEST_PORT,
- byteArrayOf(12, 31, 22, 44)))
- fail("Invalid data should cause exception")
- } catch (e: IllegalArgumentException) { }
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testParcel() {
- assertParcelSane(nattKeepalivePacket(), 0)
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testEquals() {
- assertEqualBothWays(nattKeepalivePacket(), nattKeepalivePacket())
- assertNotEquals(nattKeepalivePacket(dstAddress = TEST_SRC_ADDRV4), nattKeepalivePacket())
- assertNotEquals(nattKeepalivePacket(srcAddress = TEST_DST_ADDRV4), nattKeepalivePacket())
- // Test src port only because dst port have to be NATT_PORT
- assertNotEquals(nattKeepalivePacket(srcPort = TEST_PORT2), nattKeepalivePacket())
- // Make sure the parceling test is updated if fields are added in the base class.
- assertFieldCountEquals(5, KeepalivePacketData::class.java)
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testHashCode() {
- assertEquals(nattKeepalivePacket().hashCode(), nattKeepalivePacket().hashCode())
- }
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/common/java/android/net/NetworkAgentConfigTest.kt b/packages/Connectivity/tests/common/java/android/net/NetworkAgentConfigTest.kt
deleted file mode 100644
index 2b45b3d..0000000
--- a/packages/Connectivity/tests/common/java/android/net/NetworkAgentConfigTest.kt
+++ /dev/null
@@ -1,91 +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 android.net
-
-import android.os.Build
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.modules.utils.build.SdkLevel.isAtLeastS
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class NetworkAgentConfigTest {
- @Rule @JvmField
- val ignoreRule = DevSdkIgnoreRule()
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testParcelNetworkAgentConfig() {
- val config = NetworkAgentConfig.Builder().apply {
- setExplicitlySelected(true)
- setLegacyType(ConnectivityManager.TYPE_ETHERNET)
- setSubscriberId("MySubId")
- setPartialConnectivityAcceptable(false)
- setUnvalidatedConnectivityAcceptable(true)
- if (isAtLeastS()) {
- setBypassableVpn(true)
- }
- }.build()
- if (isAtLeastS()) {
- // From S, the config will have 12 items
- assertParcelSane(config, 12)
- } else {
- // For R or below, the config will have 10 items
- assertParcelSane(config, 10)
- }
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testBuilder() {
- val config = NetworkAgentConfig.Builder().apply {
- setExplicitlySelected(true)
- setLegacyType(ConnectivityManager.TYPE_ETHERNET)
- setSubscriberId("MySubId")
- setPartialConnectivityAcceptable(false)
- setUnvalidatedConnectivityAcceptable(true)
- setLegacyTypeName("TEST_NETWORK")
- if (isAtLeastS()) {
- setNat64DetectionEnabled(false)
- setProvisioningNotificationEnabled(false)
- setBypassableVpn(true)
- }
- }.build()
-
- assertTrue(config.isExplicitlySelected())
- assertEquals(ConnectivityManager.TYPE_ETHERNET, config.getLegacyType())
- assertEquals("MySubId", config.getSubscriberId())
- assertFalse(config.isPartialConnectivityAcceptable())
- assertTrue(config.isUnvalidatedConnectivityAcceptable())
- assertEquals("TEST_NETWORK", config.getLegacyTypeName())
- if (isAtLeastS()) {
- assertFalse(config.isNat64DetectionEnabled())
- assertFalse(config.isProvisioningNotificationEnabled())
- assertTrue(config.isBypassableVpn())
- } else {
- assertTrue(config.isNat64DetectionEnabled())
- assertTrue(config.isProvisioningNotificationEnabled())
- }
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/NetworkCapabilitiesTest.java b/packages/Connectivity/tests/common/java/android/net/NetworkCapabilitiesTest.java
deleted file mode 100644
index 9efdde4..0000000
--- a/packages/Connectivity/tests/common/java/android/net/NetworkCapabilitiesTest.java
+++ /dev/null
@@ -1,1158 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
-import static android.net.NetworkCapabilities.MAX_TRANSPORT;
-import static android.net.NetworkCapabilities.MIN_TRANSPORT;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
-import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
-import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
-import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
-import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_TEST;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
-import static android.os.Process.INVALID_UID;
-
-import static com.android.modules.utils.build.SdkLevel.isAtLeastR;
-import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
-import static com.android.net.module.util.NetworkCapabilitiesUtils.TRANSPORT_USB;
-import static com.android.testutils.MiscAsserts.assertEmpty;
-import static com.android.testutils.MiscAsserts.assertThrows;
-import static com.android.testutils.ParcelUtils.assertParcelSane;
-import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
-
-import android.net.wifi.aware.DiscoverySession;
-import android.net.wifi.aware.PeerHandle;
-import android.net.wifi.aware.WifiAwareNetworkSpecifier;
-import android.os.Build;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.ArraySet;
-import android.util.Range;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.CompatUtil;
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-
-import java.util.Arrays;
-import java.util.Set;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkCapabilitiesTest {
- private static final String TEST_SSID = "TEST_SSID";
- private static final String DIFFERENT_TEST_SSID = "DIFFERENT_TEST_SSID";
- private static final int TEST_SUBID1 = 1;
- private static final int TEST_SUBID2 = 2;
- private static final int TEST_SUBID3 = 3;
-
- @Rule
- public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule();
-
- private DiscoverySession mDiscoverySession = Mockito.mock(DiscoverySession.class);
- private PeerHandle mPeerHandle = Mockito.mock(PeerHandle.class);
-
- @Test
- public void testMaybeMarkCapabilitiesRestricted() {
- // check that internet does not get restricted
- NetworkCapabilities netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.maybeMarkCapabilitiesRestricted();
- assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // metered-ness shouldn't matter
- netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.addCapability(NET_CAPABILITY_NOT_METERED);
- netCap.maybeMarkCapabilitiesRestricted();
- assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
- netCap.maybeMarkCapabilitiesRestricted();
- assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // add EIMS - bundled with unrestricted means it's unrestricted
- netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.addCapability(NET_CAPABILITY_EIMS);
- netCap.addCapability(NET_CAPABILITY_NOT_METERED);
- netCap.maybeMarkCapabilitiesRestricted();
- assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.addCapability(NET_CAPABILITY_EIMS);
- netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
- netCap.maybeMarkCapabilitiesRestricted();
- assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // just a restricted cap should be restricted regardless of meteredness
- netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_EIMS);
- netCap.addCapability(NET_CAPABILITY_NOT_METERED);
- netCap.maybeMarkCapabilitiesRestricted();
- assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_EIMS);
- netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
- netCap.maybeMarkCapabilitiesRestricted();
- assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // try 2 restricted caps
- netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_CBS);
- netCap.addCapability(NET_CAPABILITY_EIMS);
- netCap.addCapability(NET_CAPABILITY_NOT_METERED);
- netCap.maybeMarkCapabilitiesRestricted();
- assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- netCap = new NetworkCapabilities();
- netCap.addCapability(NET_CAPABILITY_CBS);
- netCap.addCapability(NET_CAPABILITY_EIMS);
- netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
- netCap.maybeMarkCapabilitiesRestricted();
- assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- }
-
- @Test
- public void testDescribeImmutableDifferences() {
- NetworkCapabilities nc1;
- NetworkCapabilities nc2;
-
- // Transports changing
- nc1 = new NetworkCapabilities().addTransportType(TRANSPORT_CELLULAR);
- nc2 = new NetworkCapabilities().addTransportType(TRANSPORT_WIFI);
- assertNotEquals("", nc1.describeImmutableDifferences(nc2));
- assertEquals("", nc1.describeImmutableDifferences(nc1));
-
- // Mutable capability changing
- nc1 = new NetworkCapabilities().addCapability(NET_CAPABILITY_VALIDATED);
- nc2 = new NetworkCapabilities();
- assertEquals("", nc1.describeImmutableDifferences(nc2));
- assertEquals("", nc1.describeImmutableDifferences(nc1));
-
- // NOT_METERED changing (http://b/63326103)
- nc1 = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_NOT_METERED)
- .addCapability(NET_CAPABILITY_INTERNET);
- nc2 = new NetworkCapabilities().addCapability(NET_CAPABILITY_INTERNET);
- assertEquals("", nc1.describeImmutableDifferences(nc2));
- assertEquals("", nc1.describeImmutableDifferences(nc1));
-
- // Immutable capability changing
- nc1 = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- nc2 = new NetworkCapabilities().addCapability(NET_CAPABILITY_INTERNET);
- assertNotEquals("", nc1.describeImmutableDifferences(nc2));
- assertEquals("", nc1.describeImmutableDifferences(nc1));
-
- // Specifier changing
- nc1 = new NetworkCapabilities().addTransportType(TRANSPORT_WIFI);
- nc2 = new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier("eth42"));
- assertNotEquals("", nc1.describeImmutableDifferences(nc2));
- assertEquals("", nc1.describeImmutableDifferences(nc1));
- }
-
- @Test
- public void testLinkBandwidthUtils() {
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, NetworkCapabilities
- .minBandwidth(LINK_BANDWIDTH_UNSPECIFIED, LINK_BANDWIDTH_UNSPECIFIED));
- assertEquals(10, NetworkCapabilities
- .minBandwidth(LINK_BANDWIDTH_UNSPECIFIED, 10));
- assertEquals(10, NetworkCapabilities
- .minBandwidth(10, LINK_BANDWIDTH_UNSPECIFIED));
- assertEquals(10, NetworkCapabilities
- .minBandwidth(10, 20));
-
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, NetworkCapabilities
- .maxBandwidth(LINK_BANDWIDTH_UNSPECIFIED, LINK_BANDWIDTH_UNSPECIFIED));
- assertEquals(10, NetworkCapabilities
- .maxBandwidth(LINK_BANDWIDTH_UNSPECIFIED, 10));
- assertEquals(10, NetworkCapabilities
- .maxBandwidth(10, LINK_BANDWIDTH_UNSPECIFIED));
- assertEquals(20, NetworkCapabilities
- .maxBandwidth(10, 20));
- }
-
- @Test
- public void testSetUids() {
- final NetworkCapabilities netCap = new NetworkCapabilities();
- // Null uids match all UIDs
- netCap.setUids(null);
- assertTrue(netCap.appliesToUid(10));
- assertTrue(netCap.appliesToUid(200));
- assertTrue(netCap.appliesToUid(3000));
- assertTrue(netCap.appliesToUid(10010));
- assertTrue(netCap.appliesToUidRange(new UidRange(50, 100)));
- assertTrue(netCap.appliesToUidRange(new UidRange(70, 72)));
- assertTrue(netCap.appliesToUidRange(new UidRange(3500, 3912)));
- assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000)));
-
- if (isAtLeastS()) {
- final Set<Range<Integer>> uids = new ArraySet<>();
- uids.add(uidRange(50, 100));
- uids.add(uidRange(3000, 4000));
- netCap.setUids(uids);
- assertTrue(netCap.appliesToUid(50));
- assertTrue(netCap.appliesToUid(80));
- assertTrue(netCap.appliesToUid(100));
- assertTrue(netCap.appliesToUid(3000));
- assertTrue(netCap.appliesToUid(3001));
- assertFalse(netCap.appliesToUid(10));
- assertFalse(netCap.appliesToUid(25));
- assertFalse(netCap.appliesToUid(49));
- assertFalse(netCap.appliesToUid(101));
- assertFalse(netCap.appliesToUid(2000));
- assertFalse(netCap.appliesToUid(100000));
-
- assertTrue(netCap.appliesToUidRange(new UidRange(50, 100)));
- assertTrue(netCap.appliesToUidRange(new UidRange(70, 72)));
- assertTrue(netCap.appliesToUidRange(new UidRange(3500, 3912)));
- assertFalse(netCap.appliesToUidRange(new UidRange(1, 100)));
- assertFalse(netCap.appliesToUidRange(new UidRange(49, 100)));
- assertFalse(netCap.appliesToUidRange(new UidRange(1, 10)));
- assertFalse(netCap.appliesToUidRange(new UidRange(60, 101)));
- assertFalse(netCap.appliesToUidRange(new UidRange(60, 3400)));
-
- NetworkCapabilities netCap2 = new NetworkCapabilities();
- // A new netcap object has null UIDs, so anything will satisfy it.
- assertTrue(netCap2.satisfiedByUids(netCap));
- // Still not equal though.
- assertFalse(netCap2.equalsUids(netCap));
- netCap2.setUids(uids);
- assertTrue(netCap2.satisfiedByUids(netCap));
- assertTrue(netCap.equalsUids(netCap2));
- assertTrue(netCap2.equalsUids(netCap));
-
- uids.add(uidRange(600, 700));
- netCap2.setUids(uids);
- assertFalse(netCap2.satisfiedByUids(netCap));
- assertFalse(netCap.appliesToUid(650));
- assertTrue(netCap2.appliesToUid(650));
- netCap.combineCapabilities(netCap2);
- assertTrue(netCap2.satisfiedByUids(netCap));
- assertTrue(netCap.appliesToUid(650));
- assertFalse(netCap.appliesToUid(500));
-
- assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
- netCap.combineCapabilities(new NetworkCapabilities());
- assertTrue(netCap.appliesToUid(500));
- assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000)));
- assertFalse(netCap2.appliesToUid(500));
- assertFalse(netCap2.appliesToUidRange(new UidRange(1, 100000)));
- assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
-
- // Null uids satisfies everything.
- netCap.setUids(null);
- assertTrue(netCap2.satisfiedByUids(netCap));
- assertTrue(netCap.satisfiedByUids(netCap2));
- netCap2.setUids(null);
- assertTrue(netCap2.satisfiedByUids(netCap));
- assertTrue(netCap.satisfiedByUids(netCap2));
- }
- }
-
- @Test
- public void testParcelNetworkCapabilities() {
- final Set<Range<Integer>> uids = new ArraySet<>();
- uids.add(uidRange(50, 100));
- uids.add(uidRange(3000, 4000));
- final NetworkCapabilities netCap = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_EIMS)
- .addCapability(NET_CAPABILITY_NOT_METERED);
- if (isAtLeastS()) {
- netCap.setSubscriptionIds(Set.of(TEST_SUBID1, TEST_SUBID2));
- netCap.setUids(uids);
- }
- if (isAtLeastR()) {
- netCap.setOwnerUid(123);
- netCap.setAdministratorUids(new int[] {5, 11});
- }
- assertParcelingIsLossless(netCap);
- netCap.setSSID(TEST_SSID);
- testParcelSane(netCap);
- }
-
- @Test
- public void testParcelNetworkCapabilitiesWithRequestorUidAndPackageName() {
- final NetworkCapabilities netCap = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_EIMS)
- .addCapability(NET_CAPABILITY_NOT_METERED);
- if (isAtLeastR()) {
- netCap.setRequestorPackageName("com.android.test");
- netCap.setRequestorUid(9304);
- }
- assertParcelingIsLossless(netCap);
- netCap.setSSID(TEST_SSID);
- testParcelSane(netCap);
- }
-
- private void testParcelSane(NetworkCapabilities cap) {
- if (isAtLeastS()) {
- assertParcelSane(cap, 16);
- } else if (isAtLeastR()) {
- assertParcelSane(cap, 15);
- } else {
- assertParcelSane(cap, 11);
- }
- }
-
- private static NetworkCapabilities createNetworkCapabilitiesWithTransportInfo() {
- return new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_EIMS)
- .addCapability(NET_CAPABILITY_NOT_METERED)
- .setSSID(TEST_SSID)
- .setTransportInfo(new TestTransportInfo())
- .setRequestorPackageName("com.android.test")
- .setRequestorUid(9304);
- }
-
- @Test
- public void testNetworkCapabilitiesCopyWithNoRedactions() {
- assumeTrue(isAtLeastS());
-
- final NetworkCapabilities netCap = createNetworkCapabilitiesWithTransportInfo();
- final NetworkCapabilities netCapWithNoRedactions =
- new NetworkCapabilities(netCap, NetworkCapabilities.REDACT_NONE);
- TestTransportInfo testTransportInfo =
- (TestTransportInfo) netCapWithNoRedactions.getTransportInfo();
- assertFalse(testTransportInfo.locationRedacted);
- assertFalse(testTransportInfo.localMacAddressRedacted);
- assertFalse(testTransportInfo.settingsRedacted);
- }
-
- @Test
- public void testNetworkCapabilitiesCopyWithoutLocationSensitiveFields() {
- assumeTrue(isAtLeastS());
-
- final NetworkCapabilities netCap = createNetworkCapabilitiesWithTransportInfo();
- final NetworkCapabilities netCapWithNoRedactions =
- new NetworkCapabilities(netCap, REDACT_FOR_ACCESS_FINE_LOCATION);
- TestTransportInfo testTransportInfo =
- (TestTransportInfo) netCapWithNoRedactions.getTransportInfo();
- assertTrue(testTransportInfo.locationRedacted);
- assertFalse(testTransportInfo.localMacAddressRedacted);
- assertFalse(testTransportInfo.settingsRedacted);
- }
-
- @Test
- public void testOemPaid() {
- NetworkCapabilities nc = new NetworkCapabilities();
- // By default OEM_PAID is neither in the required or forbidden lists and the network is not
- // restricted.
- if (isAtLeastS()) {
- assertFalse(nc.hasForbiddenCapability(NET_CAPABILITY_OEM_PAID));
- }
- assertFalse(nc.hasCapability(NET_CAPABILITY_OEM_PAID));
- nc.maybeMarkCapabilitiesRestricted();
- assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // Adding OEM_PAID to capability list should make network restricted.
- nc.addCapability(NET_CAPABILITY_OEM_PAID);
- nc.addCapability(NET_CAPABILITY_INTERNET); // Combine with unrestricted capability.
- nc.maybeMarkCapabilitiesRestricted();
- assertTrue(nc.hasCapability(NET_CAPABILITY_OEM_PAID));
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // Now let's make request for OEM_PAID network.
- NetworkCapabilities nr = new NetworkCapabilities();
- nr.addCapability(NET_CAPABILITY_OEM_PAID);
- nr.maybeMarkCapabilitiesRestricted();
- assertTrue(nr.satisfiedByNetworkCapabilities(nc));
-
- // Request fails for network with the default capabilities.
- assertFalse(nr.satisfiedByNetworkCapabilities(new NetworkCapabilities()));
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.R)
- public void testOemPrivate() {
- NetworkCapabilities nc = new NetworkCapabilities();
- // By default OEM_PRIVATE is neither in the required or forbidden lists and the network is
- // not restricted.
- assertFalse(nc.hasForbiddenCapability(NET_CAPABILITY_OEM_PRIVATE));
- assertFalse(nc.hasCapability(NET_CAPABILITY_OEM_PRIVATE));
- nc.maybeMarkCapabilitiesRestricted();
- assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // Adding OEM_PRIVATE to capability list should make network restricted.
- nc.addCapability(NET_CAPABILITY_OEM_PRIVATE);
- nc.addCapability(NET_CAPABILITY_INTERNET); // Combine with unrestricted capability.
- nc.maybeMarkCapabilitiesRestricted();
- assertTrue(nc.hasCapability(NET_CAPABILITY_OEM_PRIVATE));
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // Now let's make request for OEM_PRIVATE network.
- NetworkCapabilities nr = new NetworkCapabilities();
- nr.addCapability(NET_CAPABILITY_OEM_PRIVATE);
- nr.maybeMarkCapabilitiesRestricted();
- assertTrue(nr.satisfiedByNetworkCapabilities(nc));
-
- // Request fails for network with the default capabilities.
- assertFalse(nr.satisfiedByNetworkCapabilities(new NetworkCapabilities()));
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.R)
- public void testForbiddenCapabilities() {
- NetworkCapabilities network = new NetworkCapabilities();
-
- NetworkCapabilities request = new NetworkCapabilities();
- assertTrue("Request: " + request + ", Network:" + network,
- request.satisfiedByNetworkCapabilities(network));
-
- // Requesting absence of capabilities that network doesn't have. Request should satisfy.
- request.addForbiddenCapability(NET_CAPABILITY_WIFI_P2P);
- request.addForbiddenCapability(NET_CAPABILITY_NOT_METERED);
- assertTrue(request.satisfiedByNetworkCapabilities(network));
- assertArrayEquals(new int[]{NET_CAPABILITY_WIFI_P2P,
- NET_CAPABILITY_NOT_METERED},
- request.getForbiddenCapabilities());
-
- // This is a default capability, just want to make sure its there because we use it below.
- assertTrue(network.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // Verify that adding forbidden capability will effectively remove it from capability list.
- request.addForbiddenCapability(NET_CAPABILITY_NOT_RESTRICTED);
- assertTrue(request.hasForbiddenCapability(NET_CAPABILITY_NOT_RESTRICTED));
- assertFalse(request.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- // Now this request won't be satisfied because network contains NOT_RESTRICTED.
- assertFalse(request.satisfiedByNetworkCapabilities(network));
- network.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- assertTrue(request.satisfiedByNetworkCapabilities(network));
-
- // Verify that adding capability will effectively remove it from forbidden list
- request.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
- assertTrue(request.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- assertFalse(request.hasForbiddenCapability(NET_CAPABILITY_NOT_RESTRICTED));
-
- assertFalse(request.satisfiedByNetworkCapabilities(network));
- network.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
- assertTrue(request.satisfiedByNetworkCapabilities(network));
- }
-
- @Test
- public void testConnectivityManagedCapabilities() {
- NetworkCapabilities nc = new NetworkCapabilities();
- assertFalse(nc.hasConnectivityManagedCapability());
- // Check every single system managed capability.
- nc.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
- assertTrue(nc.hasConnectivityManagedCapability());
- nc.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
- nc.addCapability(NET_CAPABILITY_FOREGROUND);
- assertTrue(nc.hasConnectivityManagedCapability());
- nc.removeCapability(NET_CAPABILITY_FOREGROUND);
- nc.addCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY);
- assertTrue(nc.hasConnectivityManagedCapability());
- nc.removeCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY);
- nc.addCapability(NET_CAPABILITY_VALIDATED);
- assertTrue(nc.hasConnectivityManagedCapability());
- }
-
- @Test
- public void testEqualsNetCapabilities() {
- NetworkCapabilities nc1 = new NetworkCapabilities();
- NetworkCapabilities nc2 = new NetworkCapabilities();
- assertTrue(nc1.equalsNetCapabilities(nc2));
- assertEquals(nc1, nc2);
-
- nc1.addCapability(NET_CAPABILITY_MMS);
- assertFalse(nc1.equalsNetCapabilities(nc2));
- assertNotEquals(nc1, nc2);
- nc2.addCapability(NET_CAPABILITY_MMS);
- assertTrue(nc1.equalsNetCapabilities(nc2));
- assertEquals(nc1, nc2);
-
- if (isAtLeastS()) {
- nc1.addForbiddenCapability(NET_CAPABILITY_INTERNET);
- assertFalse(nc1.equalsNetCapabilities(nc2));
- nc2.addForbiddenCapability(NET_CAPABILITY_INTERNET);
- assertTrue(nc1.equalsNetCapabilities(nc2));
-
- // Remove a required capability doesn't affect forbidden capabilities.
- // This is a behaviour change from R to S.
- nc1.removeCapability(NET_CAPABILITY_INTERNET);
- assertTrue(nc1.equalsNetCapabilities(nc2));
-
- nc1.removeForbiddenCapability(NET_CAPABILITY_INTERNET);
- assertFalse(nc1.equalsNetCapabilities(nc2));
- nc2.removeForbiddenCapability(NET_CAPABILITY_INTERNET);
- assertTrue(nc1.equalsNetCapabilities(nc2));
- }
- }
-
- @Test
- public void testSSID() {
- NetworkCapabilities nc1 = new NetworkCapabilities();
- NetworkCapabilities nc2 = new NetworkCapabilities();
- assertTrue(nc2.satisfiedBySSID(nc1));
-
- nc1.setSSID(TEST_SSID);
- assertTrue(nc2.satisfiedBySSID(nc1));
- nc2.setSSID("different " + TEST_SSID);
- assertFalse(nc2.satisfiedBySSID(nc1));
-
- assertTrue(nc1.satisfiedByImmutableNetworkCapabilities(nc2));
- assertFalse(nc1.satisfiedByNetworkCapabilities(nc2));
- }
-
- private ArraySet<Range<Integer>> uidRanges(int from, int to) {
- final ArraySet<Range<Integer>> range = new ArraySet<>(1);
- range.add(uidRange(from, to));
- return range;
- }
-
- private Range<Integer> uidRange(int from, int to) {
- return new Range<Integer>(from, to);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testSetAdministratorUids() {
- NetworkCapabilities nc =
- new NetworkCapabilities().setAdministratorUids(new int[] {2, 1, 3});
-
- assertArrayEquals(new int[] {1, 2, 3}, nc.getAdministratorUids());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testSetAdministratorUidsWithDuplicates() {
- try {
- new NetworkCapabilities().setAdministratorUids(new int[] {1, 1});
- fail("Expected IllegalArgumentException for duplicate uids");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testCombineCapabilities() {
- NetworkCapabilities nc1 = new NetworkCapabilities();
- NetworkCapabilities nc2 = new NetworkCapabilities();
-
- if (isAtLeastS()) {
- nc1.addForbiddenCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
- }
- nc1.addCapability(NET_CAPABILITY_NOT_ROAMING);
- assertNotEquals(nc1, nc2);
- nc2.combineCapabilities(nc1);
- assertEquals(nc1, nc2);
- assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- if (isAtLeastS()) {
- assertTrue(nc2.hasForbiddenCapability(NET_CAPABILITY_CAPTIVE_PORTAL));
- }
-
- if (isAtLeastS()) {
- // This will effectively move NOT_ROAMING capability from required to forbidden for nc1.
- nc1.addForbiddenCapability(NET_CAPABILITY_NOT_ROAMING);
- // It is not allowed to have the same capability in both wanted and forbidden list.
- assertThrows(IllegalArgumentException.class, () -> nc2.combineCapabilities(nc1));
- // Remove forbidden capability to continue other tests.
- nc1.removeForbiddenCapability(NET_CAPABILITY_NOT_ROAMING);
- }
-
- nc1.setSSID(TEST_SSID);
- nc2.combineCapabilities(nc1);
- if (isAtLeastR()) {
- assertTrue(TEST_SSID.equals(nc2.getSsid()));
- }
-
- // Because they now have the same SSID, the following call should not throw
- nc2.combineCapabilities(nc1);
-
- nc1.setSSID(DIFFERENT_TEST_SSID);
- try {
- nc2.combineCapabilities(nc1);
- fail("Expected IllegalStateException: can't combine different SSIDs");
- } catch (IllegalStateException expected) {}
- nc1.setSSID(TEST_SSID);
-
- if (isAtLeastS()) {
- nc1.setUids(uidRanges(10, 13));
- assertNotEquals(nc1, nc2);
- nc2.combineCapabilities(nc1); // Everything + 10~13 is still everything.
- assertNotEquals(nc1, nc2);
- nc1.combineCapabilities(nc2); // 10~13 + everything is everything.
- assertEquals(nc1, nc2);
- nc1.setUids(uidRanges(10, 13));
- nc2.setUids(uidRanges(20, 23));
- assertNotEquals(nc1, nc2);
- nc1.combineCapabilities(nc2);
- assertTrue(nc1.appliesToUid(12));
- assertFalse(nc2.appliesToUid(12));
- assertTrue(nc1.appliesToUid(22));
- assertTrue(nc2.appliesToUid(22));
-
- // Verify the subscription id list can be combined only when they are equal.
- nc1.setSubscriptionIds(Set.of(TEST_SUBID1, TEST_SUBID2));
- nc2.setSubscriptionIds(Set.of(TEST_SUBID2));
- assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1));
-
- nc2.setSubscriptionIds(Set.of());
- assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1));
-
- nc2.setSubscriptionIds(Set.of(TEST_SUBID2, TEST_SUBID1));
- nc2.combineCapabilities(nc1);
- assertEquals(Set.of(TEST_SUBID2, TEST_SUBID1), nc2.getSubscriptionIds());
- }
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testCombineCapabilities_AdministratorUids() {
- final NetworkCapabilities nc1 = new NetworkCapabilities();
- final NetworkCapabilities nc2 = new NetworkCapabilities();
-
- final int[] adminUids = {3, 6, 12};
- nc1.setAdministratorUids(adminUids);
- nc2.combineCapabilities(nc1);
- assertTrue(nc2.equalsAdministratorUids(nc1));
- assertArrayEquals(nc2.getAdministratorUids(), adminUids);
-
- final int[] adminUidsOtherOrder = {3, 12, 6};
- nc1.setAdministratorUids(adminUidsOtherOrder);
- assertTrue(nc2.equalsAdministratorUids(nc1));
-
- final int[] adminUids2 = {11, 1, 12, 3, 6};
- nc1.setAdministratorUids(adminUids2);
- assertFalse(nc2.equalsAdministratorUids(nc1));
- assertFalse(Arrays.equals(nc2.getAdministratorUids(), adminUids2));
- try {
- nc2.combineCapabilities(nc1);
- fail("Shouldn't be able to combine different lists of admin UIDs");
- } catch (IllegalStateException expected) { }
- }
-
- @Test
- public void testSetCapabilities() {
- final int[] REQUIRED_CAPABILITIES = new int[] {
- NET_CAPABILITY_INTERNET, NET_CAPABILITY_NOT_VPN };
-
- NetworkCapabilities nc1 = new NetworkCapabilities();
- NetworkCapabilities nc2 = new NetworkCapabilities();
-
- nc1.setCapabilities(REQUIRED_CAPABILITIES);
- assertArrayEquals(REQUIRED_CAPABILITIES, nc1.getCapabilities());
-
- // Verify that setting and adding capabilities leads to the same object state.
- nc2.clearAll();
- for (int cap : REQUIRED_CAPABILITIES) {
- nc2.addCapability(cap);
- }
- assertEquals(nc1, nc2);
-
- if (isAtLeastS()) {
- final int[] forbiddenCapabilities = new int[]{
- NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_NOT_RESTRICTED };
-
- nc1.setCapabilities(REQUIRED_CAPABILITIES, forbiddenCapabilities);
- assertArrayEquals(REQUIRED_CAPABILITIES, nc1.getCapabilities());
- assertArrayEquals(forbiddenCapabilities, nc1.getForbiddenCapabilities());
-
- nc2.clearAll();
- for (int cap : REQUIRED_CAPABILITIES) {
- nc2.addCapability(cap);
- }
- for (int cap : forbiddenCapabilities) {
- nc2.addForbiddenCapability(cap);
- }
- assertEquals(nc1, nc2);
- }
- }
-
- @Test
- public void testSetNetworkSpecifierOnMultiTransportNc() {
- // Sequence 1: Transport + Transport + NetworkSpecifier
- NetworkCapabilities nc1 = new NetworkCapabilities();
- nc1.addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI);
- try {
- nc1.setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier("eth0"));
- fail("Cannot set NetworkSpecifier on a NetworkCapability with multiple transports!");
- } catch (IllegalStateException expected) {
- // empty
- }
-
- // Sequence 2: Transport + NetworkSpecifier + Transport
- NetworkCapabilities nc2 = new NetworkCapabilities();
- nc2.addTransportType(TRANSPORT_CELLULAR).setNetworkSpecifier(
- CompatUtil.makeEthernetNetworkSpecifier("testtap3"));
- try {
- nc2.addTransportType(TRANSPORT_WIFI);
- fail("Cannot set a second TransportType of a network which has a NetworkSpecifier!");
- } catch (IllegalStateException expected) {
- // empty
- }
- }
-
- @Test
- public void testSetTransportInfoOnMultiTransportNc() {
- // Sequence 1: Transport + Transport + TransportInfo
- NetworkCapabilities nc1 = new NetworkCapabilities();
- nc1.addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI)
- .setTransportInfo(new TestTransportInfo());
-
- // Sequence 2: Transport + NetworkSpecifier + Transport
- NetworkCapabilities nc2 = new NetworkCapabilities();
- nc2.addTransportType(TRANSPORT_CELLULAR).setTransportInfo(new TestTransportInfo())
- .addTransportType(TRANSPORT_WIFI);
- }
-
- @Test
- public void testCombineTransportInfo() {
- NetworkCapabilities nc1 = new NetworkCapabilities();
- nc1.setTransportInfo(new TestTransportInfo());
-
- NetworkCapabilities nc2 = new NetworkCapabilities();
- // new TransportInfo so that object is not #equals to nc1's TransportInfo (that's where
- // combine fails)
- nc2.setTransportInfo(new TestTransportInfo());
-
- try {
- nc1.combineCapabilities(nc2);
- fail("Should not be able to combine NetworkCabilities which contain TransportInfos");
- } catch (IllegalStateException expected) {
- // empty
- }
-
- // verify that can combine with identical TransportInfo objects
- NetworkCapabilities nc3 = new NetworkCapabilities();
- nc3.setTransportInfo(nc1.getTransportInfo());
- nc1.combineCapabilities(nc3);
- }
-
- @Test
- public void testSet() {
- NetworkCapabilities nc1 = new NetworkCapabilities();
- NetworkCapabilities nc2 = new NetworkCapabilities();
-
- if (isAtLeastS()) {
- nc1.addForbiddenCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
- }
- nc1.addCapability(NET_CAPABILITY_NOT_ROAMING);
- assertNotEquals(nc1, nc2);
- nc2.set(nc1);
- assertEquals(nc1, nc2);
- assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- if (isAtLeastS()) {
- assertTrue(nc2.hasForbiddenCapability(NET_CAPABILITY_CAPTIVE_PORTAL));
- }
-
- if (isAtLeastS()) {
- // This will effectively move NOT_ROAMING capability from required to forbidden for nc1.
- nc1.addForbiddenCapability(NET_CAPABILITY_NOT_ROAMING);
- }
- nc1.setSSID(TEST_SSID);
- nc2.set(nc1);
- assertEquals(nc1, nc2);
- if (isAtLeastS()) {
- // Contrary to combineCapabilities, set() will have removed the NOT_ROAMING capability
- // from nc2.
- assertFalse(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(nc2.hasForbiddenCapability(NET_CAPABILITY_NOT_ROAMING));
- }
-
- if (isAtLeastR()) {
- assertTrue(TEST_SSID.equals(nc2.getSsid()));
- }
-
- nc1.setSSID(DIFFERENT_TEST_SSID);
- nc2.set(nc1);
- assertEquals(nc1, nc2);
- if (isAtLeastR()) {
- assertTrue(DIFFERENT_TEST_SSID.equals(nc2.getSsid()));
- }
- if (isAtLeastS()) {
- nc1.setUids(uidRanges(10, 13));
- } else {
- nc1.setUids(null);
- }
- nc2.set(nc1); // Overwrites, as opposed to combineCapabilities
- assertEquals(nc1, nc2);
-
- if (isAtLeastS()) {
- assertThrows(NullPointerException.class, () -> nc1.setSubscriptionIds(null));
- nc1.setSubscriptionIds(Set.of());
- nc2.set(nc1);
- assertEquals(nc1, nc2);
-
- nc1.setSubscriptionIds(Set.of(TEST_SUBID1));
- nc2.set(nc1);
- assertEquals(nc1, nc2);
-
- nc2.setSubscriptionIds(Set.of(TEST_SUBID2, TEST_SUBID1));
- nc2.set(nc1);
- assertEquals(nc1, nc2);
-
- nc2.setSubscriptionIds(Set.of(TEST_SUBID3, TEST_SUBID2));
- assertNotEquals(nc1, nc2);
- }
- }
-
- @Test
- public void testGetTransportTypes() {
- final NetworkCapabilities nc = new NetworkCapabilities();
- nc.addTransportType(TRANSPORT_CELLULAR);
- nc.addTransportType(TRANSPORT_WIFI);
- nc.addTransportType(TRANSPORT_VPN);
- nc.addTransportType(TRANSPORT_TEST);
-
- final int[] transportTypes = nc.getTransportTypes();
- assertEquals(4, transportTypes.length);
- assertEquals(TRANSPORT_CELLULAR, transportTypes[0]);
- assertEquals(TRANSPORT_WIFI, transportTypes[1]);
- assertEquals(TRANSPORT_VPN, transportTypes[2]);
- assertEquals(TRANSPORT_TEST, transportTypes[3]);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testTelephonyNetworkSpecifier() {
- final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier(1);
- final NetworkCapabilities nc1 = new NetworkCapabilities.Builder()
- .addTransportType(TRANSPORT_WIFI)
- .setNetworkSpecifier(specifier)
- .build();
- assertEquals(specifier, nc1.getNetworkSpecifier());
- try {
- final NetworkCapabilities nc2 = new NetworkCapabilities.Builder()
- .setNetworkSpecifier(specifier)
- .build();
- fail("Must have a single transport type. Without transport type or multiple transport"
- + " types is invalid.");
- } catch (IllegalStateException expected) { }
- }
-
- @Test
- public void testWifiAwareNetworkSpecifier() {
- final NetworkCapabilities nc = new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI_AWARE);
- // If NetworkSpecifier is not set, the default value is null.
- assertNull(nc.getNetworkSpecifier());
- final WifiAwareNetworkSpecifier specifier = new WifiAwareNetworkSpecifier.Builder(
- mDiscoverySession, mPeerHandle).build();
- nc.setNetworkSpecifier(specifier);
- assertEquals(specifier, nc.getNetworkSpecifier());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testAdministratorUidsAndOwnerUid() {
- // Test default owner uid.
- // If the owner uid is not set, the default value should be Process.INVALID_UID.
- final NetworkCapabilities nc1 = new NetworkCapabilities.Builder().build();
- assertEquals(INVALID_UID, nc1.getOwnerUid());
- // Test setAdministratorUids and getAdministratorUids.
- final int[] administratorUids = {1001, 10001};
- final NetworkCapabilities nc2 = new NetworkCapabilities.Builder()
- .setAdministratorUids(administratorUids)
- .build();
- assertTrue(Arrays.equals(administratorUids, nc2.getAdministratorUids()));
- // Test setOwnerUid and getOwnerUid.
- // The owner UID must be included in administrator UIDs, or throw IllegalStateException.
- try {
- final NetworkCapabilities nc3 = new NetworkCapabilities.Builder()
- .setOwnerUid(1001)
- .build();
- fail("The owner UID must be included in administrator UIDs.");
- } catch (IllegalStateException expected) { }
- final NetworkCapabilities nc4 = new NetworkCapabilities.Builder()
- .setAdministratorUids(administratorUids)
- .setOwnerUid(1001)
- .build();
- assertEquals(1001, nc4.getOwnerUid());
- try {
- final NetworkCapabilities nc5 = new NetworkCapabilities.Builder()
- .setAdministratorUids(null)
- .build();
- fail("Should not set null into setAdministratorUids");
- } catch (NullPointerException expected) { }
- }
-
- private static NetworkCapabilities capsWithSubIds(Integer ... subIds) {
- // Since the NetworkRequest would put NOT_VCN_MANAGED capabilities in general, for
- // every NetworkCapabilities that simulates networks needs to add it too in order to
- // satisfy these requests.
- final NetworkCapabilities nc = new NetworkCapabilities.Builder()
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
- .setSubscriptionIds(new ArraySet<>(subIds)).build();
- assertEquals(new ArraySet<>(subIds), nc.getSubscriptionIds());
- return nc;
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.R)
- public void testSubIds() throws Exception {
- final NetworkCapabilities ncWithoutId = capsWithSubIds();
- final NetworkCapabilities ncWithId = capsWithSubIds(TEST_SUBID1);
- final NetworkCapabilities ncWithOtherIds = capsWithSubIds(TEST_SUBID1, TEST_SUBID3);
- final NetworkCapabilities ncWithoutRequestedIds = capsWithSubIds(TEST_SUBID3);
-
- final NetworkRequest requestWithoutId = new NetworkRequest.Builder().build();
- assertEmpty(requestWithoutId.networkCapabilities.getSubscriptionIds());
- final NetworkRequest requestWithIds = new NetworkRequest.Builder()
- .setSubscriptionIds(Set.of(TEST_SUBID1, TEST_SUBID2)).build();
- assertEquals(Set.of(TEST_SUBID1, TEST_SUBID2),
- requestWithIds.networkCapabilities.getSubscriptionIds());
-
- assertFalse(requestWithIds.canBeSatisfiedBy(ncWithoutId));
- assertTrue(requestWithIds.canBeSatisfiedBy(ncWithOtherIds));
- assertFalse(requestWithIds.canBeSatisfiedBy(ncWithoutRequestedIds));
- assertTrue(requestWithIds.canBeSatisfiedBy(ncWithId));
- assertTrue(requestWithoutId.canBeSatisfiedBy(ncWithoutId));
- assertTrue(requestWithoutId.canBeSatisfiedBy(ncWithId));
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.R)
- public void testEqualsSubIds() throws Exception {
- assertEquals(capsWithSubIds(), capsWithSubIds());
- assertNotEquals(capsWithSubIds(), capsWithSubIds(TEST_SUBID1));
- assertEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID1));
- assertNotEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID2));
- assertNotEquals(capsWithSubIds(TEST_SUBID1), capsWithSubIds(TEST_SUBID2, TEST_SUBID1));
- assertEquals(capsWithSubIds(TEST_SUBID1, TEST_SUBID2),
- capsWithSubIds(TEST_SUBID2, TEST_SUBID1));
- }
-
- @Test
- public void testLinkBandwidthKbps() {
- final NetworkCapabilities nc = new NetworkCapabilities();
- // The default value of LinkDown/UpstreamBandwidthKbps should be LINK_BANDWIDTH_UNSPECIFIED.
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, nc.getLinkDownstreamBandwidthKbps());
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, nc.getLinkUpstreamBandwidthKbps());
- nc.setLinkDownstreamBandwidthKbps(512);
- nc.setLinkUpstreamBandwidthKbps(128);
- assertEquals(512, nc.getLinkDownstreamBandwidthKbps());
- assertNotEquals(128, nc.getLinkDownstreamBandwidthKbps());
- assertEquals(128, nc.getLinkUpstreamBandwidthKbps());
- assertNotEquals(512, nc.getLinkUpstreamBandwidthKbps());
- }
-
- private int getMaxTransport() {
- if (!isAtLeastS() && MAX_TRANSPORT == TRANSPORT_USB) return MAX_TRANSPORT - 1;
- return MAX_TRANSPORT;
- }
-
- @Test
- public void testSignalStrength() {
- final NetworkCapabilities nc = new NetworkCapabilities();
- // The default value of signal strength should be SIGNAL_STRENGTH_UNSPECIFIED.
- assertEquals(SIGNAL_STRENGTH_UNSPECIFIED, nc.getSignalStrength());
- nc.setSignalStrength(-80);
- assertEquals(-80, nc.getSignalStrength());
- assertNotEquals(-50, nc.getSignalStrength());
- }
-
- private void assertNoTransport(NetworkCapabilities nc) {
- for (int i = MIN_TRANSPORT; i <= getMaxTransport(); i++) {
- assertFalse(nc.hasTransport(i));
- }
- }
-
- // Checks that all transport types from MIN_TRANSPORT to maxTransportType are set and all
- // transport types from maxTransportType + 1 to MAX_TRANSPORT are not set when positiveSequence
- // is true. If positiveSequence is false, then the check sequence is opposite.
- private void checkCurrentTransportTypes(NetworkCapabilities nc, int maxTransportType,
- boolean positiveSequence) {
- for (int i = MIN_TRANSPORT; i <= maxTransportType; i++) {
- if (positiveSequence) {
- assertTrue(nc.hasTransport(i));
- } else {
- assertFalse(nc.hasTransport(i));
- }
- }
- for (int i = getMaxTransport(); i > maxTransportType; i--) {
- if (positiveSequence) {
- assertFalse(nc.hasTransport(i));
- } else {
- assertTrue(nc.hasTransport(i));
- }
- }
- }
-
- @Test
- public void testMultipleTransportTypes() {
- final NetworkCapabilities nc = new NetworkCapabilities();
- assertNoTransport(nc);
- // Test adding multiple transport types.
- for (int i = MIN_TRANSPORT; i <= getMaxTransport(); i++) {
- nc.addTransportType(i);
- checkCurrentTransportTypes(nc, i, true /* positiveSequence */);
- }
- // Test removing multiple transport types.
- for (int i = MIN_TRANSPORT; i <= getMaxTransport(); i++) {
- nc.removeTransportType(i);
- checkCurrentTransportTypes(nc, i, false /* positiveSequence */);
- }
- assertNoTransport(nc);
- nc.addTransportType(TRANSPORT_WIFI);
- assertTrue(nc.hasTransport(TRANSPORT_WIFI));
- assertFalse(nc.hasTransport(TRANSPORT_VPN));
- nc.addTransportType(TRANSPORT_VPN);
- assertTrue(nc.hasTransport(TRANSPORT_WIFI));
- assertTrue(nc.hasTransport(TRANSPORT_VPN));
- nc.removeTransportType(TRANSPORT_WIFI);
- assertFalse(nc.hasTransport(TRANSPORT_WIFI));
- assertTrue(nc.hasTransport(TRANSPORT_VPN));
- nc.removeTransportType(TRANSPORT_VPN);
- assertFalse(nc.hasTransport(TRANSPORT_WIFI));
- assertFalse(nc.hasTransport(TRANSPORT_VPN));
- assertNoTransport(nc);
- }
-
- @Test
- public void testAddAndRemoveTransportType() {
- final NetworkCapabilities nc = new NetworkCapabilities();
- try {
- nc.addTransportType(-1);
- fail("Should not set invalid transport type into addTransportType");
- } catch (IllegalArgumentException expected) { }
- try {
- nc.removeTransportType(-1);
- fail("Should not set invalid transport type into removeTransportType");
- } catch (IllegalArgumentException e) { }
- }
-
- /**
- * Test TransportInfo to verify redaction mechanism.
- */
- private static class TestTransportInfo implements TransportInfo {
- public final boolean locationRedacted;
- public final boolean localMacAddressRedacted;
- public final boolean settingsRedacted;
-
- TestTransportInfo() {
- locationRedacted = false;
- localMacAddressRedacted = false;
- settingsRedacted = false;
- }
-
- TestTransportInfo(boolean locationRedacted,
- boolean localMacAddressRedacted,
- boolean settingsRedacted) {
- this.locationRedacted = locationRedacted;
- this.localMacAddressRedacted =
- localMacAddressRedacted;
- this.settingsRedacted = settingsRedacted;
- }
-
- @Override
- public TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) {
- return new TestTransportInfo(
- (redactions & NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION) != 0,
- (redactions & REDACT_FOR_LOCAL_MAC_ADDRESS) != 0,
- (redactions & REDACT_FOR_NETWORK_SETTINGS) != 0
- );
- }
-
- @Override
- public @NetworkCapabilities.RedactionType long getApplicableRedactions() {
- return REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS
- | REDACT_FOR_NETWORK_SETTINGS;
- }
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testBuilder() {
- final int ownerUid = 1001;
- final int signalStrength = -80;
- final int requestUid = 10100;
- final int[] administratorUids = {ownerUid, 10001};
- final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier(1);
- final TransportInfo transportInfo = new TransportInfo() {};
- final String ssid = "TEST_SSID";
- final String packageName = "com.google.test.networkcapabilities";
- final NetworkCapabilities nc = new NetworkCapabilities.Builder()
- .addTransportType(TRANSPORT_WIFI)
- .addTransportType(TRANSPORT_CELLULAR)
- .removeTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_EIMS)
- .addCapability(NET_CAPABILITY_CBS)
- .removeCapability(NET_CAPABILITY_CBS)
- .setAdministratorUids(administratorUids)
- .setOwnerUid(ownerUid)
- .setLinkDownstreamBandwidthKbps(512)
- .setLinkUpstreamBandwidthKbps(128)
- .setNetworkSpecifier(specifier)
- .setTransportInfo(transportInfo)
- .setSignalStrength(signalStrength)
- .setSsid(ssid)
- .setRequestorUid(requestUid)
- .setRequestorPackageName(packageName)
- .build();
- assertEquals(1, nc.getTransportTypes().length);
- assertEquals(TRANSPORT_WIFI, nc.getTransportTypes()[0]);
- assertTrue(nc.hasCapability(NET_CAPABILITY_EIMS));
- assertFalse(nc.hasCapability(NET_CAPABILITY_CBS));
- assertTrue(Arrays.equals(administratorUids, nc.getAdministratorUids()));
- assertEquals(ownerUid, nc.getOwnerUid());
- assertEquals(512, nc.getLinkDownstreamBandwidthKbps());
- assertNotEquals(128, nc.getLinkDownstreamBandwidthKbps());
- assertEquals(128, nc.getLinkUpstreamBandwidthKbps());
- assertNotEquals(512, nc.getLinkUpstreamBandwidthKbps());
- assertEquals(specifier, nc.getNetworkSpecifier());
- assertEquals(transportInfo, nc.getTransportInfo());
- assertEquals(signalStrength, nc.getSignalStrength());
- assertNotEquals(-50, nc.getSignalStrength());
- assertEquals(ssid, nc.getSsid());
- assertEquals(requestUid, nc.getRequestorUid());
- assertEquals(packageName, nc.getRequestorPackageName());
- // Cannot assign null into NetworkCapabilities.Builder
- try {
- final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(null);
- fail("Should not set null into NetworkCapabilities.Builder");
- } catch (NullPointerException expected) { }
- assertEquals(nc, new NetworkCapabilities.Builder(nc).build());
-
- if (isAtLeastS()) {
- final NetworkCapabilities nc2 = new NetworkCapabilities.Builder()
- .setSubscriptionIds(Set.of(TEST_SUBID1)).build();
- assertEquals(Set.of(TEST_SUBID1), nc2.getSubscriptionIds());
- }
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/NetworkProviderTest.kt b/packages/Connectivity/tests/common/java/android/net/NetworkProviderTest.kt
deleted file mode 100644
index 7424157..0000000
--- a/packages/Connectivity/tests/common/java/android/net/NetworkProviderTest.kt
+++ /dev/null
@@ -1,201 +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.net
-
-import android.app.Instrumentation
-import android.content.Context
-import android.net.NetworkCapabilities.TRANSPORT_TEST
-import android.net.NetworkProviderTest.TestNetworkCallback.CallbackEntry.OnUnavailable
-import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequestWithdrawn
-import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequested
-import android.os.Build
-import android.os.HandlerThread
-import android.os.Looper
-import androidx.test.InstrumentationRegistry
-import com.android.net.module.util.ArrayTrackRecord
-import com.android.testutils.CompatUtil
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import com.android.testutils.DevSdkIgnoreRunner
-import com.android.testutils.isDevSdkInRange
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.verifyNoMoreInteractions
-import java.util.UUID
-import kotlin.test.assertEquals
-import kotlin.test.assertNotEquals
-
-private const val DEFAULT_TIMEOUT_MS = 5000L
-private val instrumentation: Instrumentation
- get() = InstrumentationRegistry.getInstrumentation()
-private val context: Context get() = InstrumentationRegistry.getContext()
-private val PROVIDER_NAME = "NetworkProviderTest"
-
-@RunWith(DevSdkIgnoreRunner::class)
-@IgnoreUpTo(Build.VERSION_CODES.Q)
-class NetworkProviderTest {
- private val mCm = context.getSystemService(ConnectivityManager::class.java)
- private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread")
-
- @Before
- fun setUp() {
- instrumentation.getUiAutomation().adoptShellPermissionIdentity()
- mHandlerThread.start()
- }
-
- @After
- fun tearDown() {
- mHandlerThread.quitSafely()
- instrumentation.getUiAutomation().dropShellPermissionIdentity()
- }
-
- private class TestNetworkProvider(context: Context, looper: Looper) :
- NetworkProvider(context, looper, PROVIDER_NAME) {
- private val seenEvents = ArrayTrackRecord<CallbackEntry>().newReadHead()
-
- sealed class CallbackEntry {
- data class OnNetworkRequested(
- val request: NetworkRequest,
- val score: Int,
- val id: Int
- ) : CallbackEntry()
- data class OnNetworkRequestWithdrawn(val request: NetworkRequest) : CallbackEntry()
- }
-
- override fun onNetworkRequested(request: NetworkRequest, score: Int, id: Int) {
- seenEvents.add(OnNetworkRequested(request, score, id))
- }
-
- override fun onNetworkRequestWithdrawn(request: NetworkRequest) {
- seenEvents.add(OnNetworkRequestWithdrawn(request))
- }
-
- inline fun <reified T : CallbackEntry> expectCallback(
- crossinline predicate: (T) -> Boolean
- ) = seenEvents.poll(DEFAULT_TIMEOUT_MS) { it is T && predicate(it) }
- }
-
- private fun createNetworkProvider(ctx: Context = context): TestNetworkProvider {
- return TestNetworkProvider(ctx, mHandlerThread.looper)
- }
-
- @Test
- fun testOnNetworkRequested() {
- val provider = createNetworkProvider()
- assertEquals(provider.getProviderId(), NetworkProvider.ID_NONE)
- mCm.registerNetworkProvider(provider)
- assertNotEquals(provider.getProviderId(), NetworkProvider.ID_NONE)
-
- val specifier = CompatUtil.makeTestNetworkSpecifier(
- UUID.randomUUID().toString())
- val nr: NetworkRequest = NetworkRequest.Builder()
- .addTransportType(TRANSPORT_TEST)
- .setNetworkSpecifier(specifier)
- .build()
- val cb = ConnectivityManager.NetworkCallback()
- mCm.requestNetwork(nr, cb)
- provider.expectCallback<OnNetworkRequested>() { callback ->
- callback.request.getNetworkSpecifier() == specifier &&
- callback.request.hasTransport(TRANSPORT_TEST)
- }
-
- val initialScore = 40
- val updatedScore = 60
- val nc = NetworkCapabilities().apply {
- addTransportType(NetworkCapabilities.TRANSPORT_TEST)
- removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
- removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
- addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
- addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- setNetworkSpecifier(specifier)
- }
- val lp = LinkProperties()
- val config = NetworkAgentConfig.Builder().build()
- val agent = object : NetworkAgent(context, mHandlerThread.looper, "TestAgent", nc, lp,
- initialScore, config, provider) {}
-
- provider.expectCallback<OnNetworkRequested>() { callback ->
- callback.request.getNetworkSpecifier() == specifier &&
- callback.score == initialScore &&
- callback.id == agent.providerId
- }
-
- agent.sendNetworkScore(updatedScore)
- provider.expectCallback<OnNetworkRequested>() { callback ->
- callback.request.getNetworkSpecifier() == specifier &&
- callback.score == updatedScore &&
- callback.id == agent.providerId
- }
-
- mCm.unregisterNetworkCallback(cb)
- provider.expectCallback<OnNetworkRequestWithdrawn>() { callback ->
- callback.request.getNetworkSpecifier() == specifier &&
- callback.request.hasTransport(TRANSPORT_TEST)
- }
- mCm.unregisterNetworkProvider(provider)
- // Provider id should be ID_NONE after unregister network provider
- assertEquals(provider.getProviderId(), NetworkProvider.ID_NONE)
- // unregisterNetworkProvider should not crash even if it's called on an
- // already unregistered provider.
- mCm.unregisterNetworkProvider(provider)
- }
-
- private class TestNetworkCallback : ConnectivityManager.NetworkCallback() {
- private val seenEvents = ArrayTrackRecord<CallbackEntry>().newReadHead()
- sealed class CallbackEntry {
- object OnUnavailable : CallbackEntry()
- }
-
- override fun onUnavailable() {
- seenEvents.add(OnUnavailable)
- }
-
- inline fun <reified T : CallbackEntry> expectCallback(
- crossinline predicate: (T) -> Boolean
- ) = seenEvents.poll(DEFAULT_TIMEOUT_MS) { it is T && predicate(it) }
- }
-
- @Test
- fun testDeclareNetworkRequestUnfulfillable() {
- val mockContext = mock(Context::class.java)
- doReturn(mCm).`when`(mockContext).getSystemService(Context.CONNECTIVITY_SERVICE)
- val provider = createNetworkProvider(mockContext)
- // ConnectivityManager not required at creation time after R
- if (!isDevSdkInRange(0, Build.VERSION_CODES.R)) {
- verifyNoMoreInteractions(mockContext)
- }
-
- mCm.registerNetworkProvider(provider)
-
- val specifier = CompatUtil.makeTestNetworkSpecifier(
- UUID.randomUUID().toString())
- val nr: NetworkRequest = NetworkRequest.Builder()
- .addTransportType(TRANSPORT_TEST)
- .setNetworkSpecifier(specifier)
- .build()
-
- val cb = TestNetworkCallback()
- mCm.requestNetwork(nr, cb)
- provider.declareNetworkRequestUnfulfillable(nr)
- cb.expectCallback<OnUnavailable>() { nr.getNetworkSpecifier() == specifier }
- mCm.unregisterNetworkProvider(provider)
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/NetworkSpecifierTest.kt b/packages/Connectivity/tests/common/java/android/net/NetworkSpecifierTest.kt
deleted file mode 100644
index f3409f5..0000000
--- a/packages/Connectivity/tests/common/java/android/net/NetworkSpecifierTest.kt
+++ /dev/null
@@ -1,67 +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.net
-
-import android.os.Build
-import androidx.test.filters.SmallTest
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import com.android.testutils.DevSdkIgnoreRunner
-import kotlin.test.assertTrue
-import kotlin.test.assertEquals
-import kotlin.test.assertFalse
-import kotlin.test.assertNotEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(DevSdkIgnoreRunner::class)
-@IgnoreUpTo(Build.VERSION_CODES.Q)
-class NetworkSpecifierTest {
- private class TestNetworkSpecifier(
- val intData: Int = 123,
- val stringData: String = "init"
- ) : NetworkSpecifier() {
- override fun canBeSatisfiedBy(other: NetworkSpecifier?): Boolean =
- other != null &&
- other is TestNetworkSpecifier &&
- other.intData >= intData &&
- stringData.equals(other.stringData)
-
- override fun redact(): NetworkSpecifier = TestNetworkSpecifier(intData, "redact")
- }
-
- @Test
- fun testRedact() {
- val ns: TestNetworkSpecifier = TestNetworkSpecifier()
- val redactNs = ns.redact()
- assertTrue(redactNs is TestNetworkSpecifier)
- assertEquals(ns.intData, redactNs.intData)
- assertNotEquals(ns.stringData, redactNs.stringData)
- assertTrue("redact".equals(redactNs.stringData))
- }
-
- @Test
- fun testcanBeSatisfiedBy() {
- val target: TestNetworkSpecifier = TestNetworkSpecifier()
- assertFalse(target.canBeSatisfiedBy(null))
- assertTrue(target.canBeSatisfiedBy(TestNetworkSpecifier()))
- val otherNs = TelephonyNetworkSpecifier.Builder().setSubscriptionId(123).build()
- assertFalse(target.canBeSatisfiedBy(otherNs))
- assertTrue(target.canBeSatisfiedBy(TestNetworkSpecifier(intData = 999)))
- assertFalse(target.canBeSatisfiedBy(TestNetworkSpecifier(intData = 1)))
- assertFalse(target.canBeSatisfiedBy(TestNetworkSpecifier(stringData = "diff")))
- }
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/common/java/android/net/NetworkStackTest.java b/packages/Connectivity/tests/common/java/android/net/NetworkStackTest.java
deleted file mode 100644
index f8f9c72..0000000
--- a/packages/Connectivity/tests/common/java/android/net/NetworkStackTest.java
+++ /dev/null
@@ -1,51 +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 android.net;
-
-import static org.junit.Assert.assertEquals;
-
-import android.os.Build;
-import android.os.IBinder;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-public class NetworkStackTest {
- @Rule
- public DevSdkIgnoreRule mDevSdkIgnoreRule = new DevSdkIgnoreRule();
-
- @Mock private IBinder mConnectorBinder;
-
- @Before public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testGetService() {
- NetworkStack.setServiceForTest(mConnectorBinder);
- assertEquals(NetworkStack.getService(), mConnectorBinder);
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/NetworkStateSnapshotTest.kt b/packages/Connectivity/tests/common/java/android/net/NetworkStateSnapshotTest.kt
deleted file mode 100644
index 0ca4d95..0000000
--- a/packages/Connectivity/tests/common/java/android/net/NetworkStateSnapshotTest.kt
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net
-
-import android.net.ConnectivityManager.TYPE_NONE
-import android.net.ConnectivityManager.TYPE_WIFI
-import android.net.InetAddresses.parseNumericAddress
-import android.net.NetworkCapabilities.TRANSPORT_WIFI
-import android.os.Build
-import androidx.test.filters.SmallTest
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRunner
-import com.android.testutils.assertParcelSane
-import org.junit.Test
-import org.junit.runner.RunWith
-import java.net.Inet4Address
-import java.net.Inet6Address
-
-private const val TEST_IMSI = "imsi1"
-private const val TEST_SSID = "SSID1"
-private const val TEST_NETID = 123
-
-private val TEST_IPV4_GATEWAY = parseNumericAddress("192.168.222.3") as Inet4Address
-private val TEST_IPV6_GATEWAY = parseNumericAddress("2001:db8::1") as Inet6Address
-private val TEST_IPV4_LINKADDR = LinkAddress("192.168.222.123/24")
-private val TEST_IPV6_LINKADDR = LinkAddress("2001:db8::123/64")
-private val TEST_IFACE = "fake0"
-private val TEST_LINK_PROPERTIES = LinkProperties().apply {
- interfaceName = TEST_IFACE
- addLinkAddress(TEST_IPV4_LINKADDR)
- addLinkAddress(TEST_IPV6_LINKADDR)
-
- // Add default routes
- addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY))
- addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_GATEWAY))
-}
-
-private val TEST_CAPABILITIES = NetworkCapabilities().apply {
- addTransportType(TRANSPORT_WIFI)
- setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false)
- setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
- setSSID(TEST_SSID)
-}
-
-@SmallTest
-@RunWith(DevSdkIgnoreRunner::class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
-class NetworkStateSnapshotTest {
-
- @Test
- fun testParcelUnparcel() {
- val emptySnapshot = NetworkStateSnapshot(Network(TEST_NETID), NetworkCapabilities(),
- LinkProperties(), null, TYPE_NONE)
- val snapshot = NetworkStateSnapshot(
- Network(TEST_NETID), TEST_CAPABILITIES, TEST_LINK_PROPERTIES, TEST_IMSI, TYPE_WIFI)
- assertParcelSane(emptySnapshot, 5)
- assertParcelSane(snapshot, 5)
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/NetworkTest.java b/packages/Connectivity/tests/common/java/android/net/NetworkTest.java
deleted file mode 100644
index 7423c73..0000000
--- a/packages/Connectivity/tests/common/java/android/net/NetworkTest.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.os.Build;
-import android.platform.test.annotations.AppModeFull;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.net.DatagramSocket;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.SocketException;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkTest {
- final Network mNetwork = new Network(99);
-
- @Rule
- public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
-
- @Test
- public void testBindSocketOfInvalidFdThrows() throws Exception {
-
- final FileDescriptor fd = new FileDescriptor();
- assertFalse(fd.valid());
-
- try {
- mNetwork.bindSocket(fd);
- fail("SocketException not thrown");
- } catch (SocketException expected) {}
- }
-
- @Test
- public void testBindSocketOfNonSocketFdThrows() throws Exception {
- final File devNull = new File("/dev/null");
- assertTrue(devNull.canRead());
-
- final FileInputStream fis = new FileInputStream(devNull);
- assertTrue(null != fis.getFD());
- assertTrue(fis.getFD().valid());
-
- try {
- mNetwork.bindSocket(fis.getFD());
- fail("SocketException not thrown");
- } catch (SocketException expected) {}
- }
-
- @Test
- @AppModeFull(reason = "Socket cannot bind in instant app mode")
- public void testBindSocketOfConnectedDatagramSocketThrows() throws Exception {
- final DatagramSocket mDgramSocket = new DatagramSocket(0, (InetAddress) Inet6Address.ANY);
- mDgramSocket.connect((InetAddress) Inet6Address.LOOPBACK, 53);
- assertTrue(mDgramSocket.isConnected());
-
- try {
- mNetwork.bindSocket(mDgramSocket);
- fail("SocketException not thrown");
- } catch (SocketException expected) {}
- }
-
- @Test
- public void testBindSocketOfLocalSocketThrows() throws Exception {
- final LocalSocket mLocalClient = new LocalSocket();
- mLocalClient.bind(new LocalSocketAddress("testClient"));
- assertTrue(mLocalClient.getFileDescriptor().valid());
-
- try {
- mNetwork.bindSocket(mLocalClient.getFileDescriptor());
- fail("SocketException not thrown");
- } catch (SocketException expected) {}
-
- final LocalServerSocket mLocalServer = new LocalServerSocket("testServer");
- mLocalClient.connect(mLocalServer.getLocalSocketAddress());
- assertTrue(mLocalClient.isConnected());
-
- try {
- mNetwork.bindSocket(mLocalClient.getFileDescriptor());
- fail("SocketException not thrown");
- } catch (SocketException expected) {}
- }
-
- @Test
- public void testZeroIsObviousForDebugging() {
- Network zero = new Network(0);
- assertEquals(0, zero.hashCode());
- assertEquals(0, zero.getNetworkHandle());
- assertEquals("0", zero.toString());
- }
-
- @Test
- public void testGetNetworkHandle() {
- Network one = new Network(1);
- Network two = new Network(2);
- Network three = new Network(3);
-
- // None of the hashcodes are zero.
- assertNotEquals(0, one.hashCode());
- assertNotEquals(0, two.hashCode());
- assertNotEquals(0, three.hashCode());
-
- // All the hashcodes are distinct.
- assertNotEquals(one.hashCode(), two.hashCode());
- assertNotEquals(one.hashCode(), three.hashCode());
- assertNotEquals(two.hashCode(), three.hashCode());
-
- // None of the handles are zero.
- assertNotEquals(0, one.getNetworkHandle());
- assertNotEquals(0, two.getNetworkHandle());
- assertNotEquals(0, three.getNetworkHandle());
-
- // All the handles are distinct.
- assertNotEquals(one.getNetworkHandle(), two.getNetworkHandle());
- assertNotEquals(one.getNetworkHandle(), three.getNetworkHandle());
- assertNotEquals(two.getNetworkHandle(), three.getNetworkHandle());
-
- // The handles are not equal to the hashcodes.
- assertNotEquals(one.hashCode(), one.getNetworkHandle());
- assertNotEquals(two.hashCode(), two.getNetworkHandle());
- assertNotEquals(three.hashCode(), three.getNetworkHandle());
-
- // Adjust as necessary to test an implementation's specific constants.
- // When running with runtest, "adb logcat -s TestRunner" can be useful.
- assertEquals(7700664333L, one.getNetworkHandle());
- assertEquals(11995631629L, two.getNetworkHandle());
- assertEquals(16290598925L, three.getNetworkHandle());
- }
-
- // getNetId() did not exist in Q
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testGetNetId() {
- assertEquals(1234, new Network(1234).getNetId());
- assertEquals(2345, new Network(2345, true).getNetId());
- }
-
- @Test
- public void testFromNetworkHandle() {
- final Network network = new Network(1234);
- assertEquals(network.netId, Network.fromNetworkHandle(network.getNetworkHandle()).netId);
- }
-
- // Parsing private DNS bypassing handle was not supported until S
- @Test @IgnoreUpTo(Build.VERSION_CODES.R)
- public void testFromNetworkHandlePrivateDnsBypass_S() {
- final Network network = new Network(1234, true);
-
- final Network recreatedNetwork = Network.fromNetworkHandle(network.getNetworkHandle());
- assertEquals(network.netId, recreatedNetwork.netId);
- assertEquals(network.getNetIdForResolv(), recreatedNetwork.getNetIdForResolv());
- }
-
- @Test @IgnoreAfter(Build.VERSION_CODES.R)
- public void testFromNetworkHandlePrivateDnsBypass_R() {
- final Network network = new Network(1234, true);
-
- final Network recreatedNetwork = Network.fromNetworkHandle(network.getNetworkHandle());
- assertEquals(network.netId, recreatedNetwork.netId);
- // Until R included, fromNetworkHandle would not parse the private DNS bypass flag
- assertEquals(network.netId, recreatedNetwork.getNetIdForResolv());
- }
-
- @Test
- public void testGetPrivateDnsBypassingCopy() {
- final Network copy = mNetwork.getPrivateDnsBypassingCopy();
- assertEquals(mNetwork.netId, copy.netId);
- assertNotEquals(copy.netId, copy.getNetIdForResolv());
- assertNotEquals(mNetwork.getNetIdForResolv(), copy.getNetIdForResolv());
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/OemNetworkPreferencesTest.java b/packages/Connectivity/tests/common/java/android/net/OemNetworkPreferencesTest.java
deleted file mode 100644
index fd29a95..0000000
--- a/packages/Connectivity/tests/common/java/android/net/OemNetworkPreferencesTest.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static com.android.testutils.MiscAsserts.assertThrows;
-import static com.android.testutils.ParcelUtils.assertParcelSane;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.os.Build;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-import com.android.testutils.DevSdkIgnoreRunner;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Map;
-
-@IgnoreUpTo(Build.VERSION_CODES.R)
-@RunWith(DevSdkIgnoreRunner.class)
-@SmallTest
-public class OemNetworkPreferencesTest {
-
- private static final int TEST_PREF = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED;
- private static final String TEST_PACKAGE = "com.google.apps.contacts";
-
- private final OemNetworkPreferences.Builder mBuilder = new OemNetworkPreferences.Builder();
-
- @Test
- public void testBuilderAddNetworkPreferenceRequiresNonNullPackageName() {
- assertThrows(NullPointerException.class,
- () -> mBuilder.addNetworkPreference(null, TEST_PREF));
- }
-
- @Test
- public void testBuilderRemoveNetworkPreferenceRequiresNonNullPackageName() {
- assertThrows(NullPointerException.class,
- () -> mBuilder.clearNetworkPreference(null));
- }
-
- @Test
- public void testGetNetworkPreferenceReturnsCorrectValue() {
- final int expectedNumberOfMappings = 1;
- mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
-
- final Map<String, Integer> networkPreferences =
- mBuilder.build().getNetworkPreferences();
-
- assertEquals(expectedNumberOfMappings, networkPreferences.size());
- assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
- }
-
- @Test
- public void testGetNetworkPreferenceReturnsUnmodifiableValue() {
- final String newPackage = "new.com.google.apps.contacts";
- mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
-
- final Map<String, Integer> networkPreferences =
- mBuilder.build().getNetworkPreferences();
-
- assertThrows(UnsupportedOperationException.class,
- () -> networkPreferences.put(newPackage, TEST_PREF));
-
- assertThrows(UnsupportedOperationException.class,
- () -> networkPreferences.remove(TEST_PACKAGE));
-
- }
-
- @Test
- public void testToStringReturnsCorrectValue() {
- mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
-
- final String networkPreferencesString = mBuilder.build().getNetworkPreferences().toString();
-
- assertTrue(networkPreferencesString.contains(Integer.toString(TEST_PREF)));
- assertTrue(networkPreferencesString.contains(TEST_PACKAGE));
- }
-
- @Test
- public void testOemNetworkPreferencesParcelable() {
- mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
-
- final OemNetworkPreferences prefs = mBuilder.build();
-
- assertParcelSane(prefs, 1 /* fieldCount */);
- }
-
- @Test
- public void testAddNetworkPreferenceOverwritesPriorPreference() {
- final int newPref = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
- mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
- Map<String, Integer> networkPreferences =
- mBuilder.build().getNetworkPreferences();
-
- assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
- assertEquals(networkPreferences.get(TEST_PACKAGE).intValue(), TEST_PREF);
-
- mBuilder.addNetworkPreference(TEST_PACKAGE, newPref);
- networkPreferences = mBuilder.build().getNetworkPreferences();
-
- assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
- assertEquals(networkPreferences.get(TEST_PACKAGE).intValue(), newPref);
- }
-
- @Test
- public void testRemoveNetworkPreferenceRemovesValue() {
- mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
- Map<String, Integer> networkPreferences =
- mBuilder.build().getNetworkPreferences();
-
- assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
-
- mBuilder.clearNetworkPreference(TEST_PACKAGE);
- networkPreferences = mBuilder.build().getNetworkPreferences();
-
- assertFalse(networkPreferences.containsKey(TEST_PACKAGE));
- }
-
- @Test
- public void testConstructorByOemNetworkPreferencesSetsValue() {
- mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
- OemNetworkPreferences networkPreference = mBuilder.build();
-
- final Map<String, Integer> networkPreferences =
- new OemNetworkPreferences
- .Builder(networkPreference)
- .build()
- .getNetworkPreferences();
-
- assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
- assertEquals(networkPreferences.get(TEST_PACKAGE).intValue(), TEST_PREF);
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/RouteInfoTest.java b/packages/Connectivity/tests/common/java/android/net/RouteInfoTest.java
deleted file mode 100644
index 71689f9..0000000
--- a/packages/Connectivity/tests/common/java/android/net/RouteInfoTest.java
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.RouteInfo.RTN_UNREACHABLE;
-
-import static com.android.testutils.MiscAsserts.assertEqualBothWays;
-import static com.android.testutils.MiscAsserts.assertFieldCountEquals;
-import static com.android.testutils.MiscAsserts.assertNotEqualEitherWay;
-import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.os.Build;
-
-import androidx.core.os.BuildCompat;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class RouteInfoTest {
- @Rule
- public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
-
- private static final int INVALID_ROUTE_TYPE = -1;
-
- private InetAddress Address(String addr) {
- return InetAddresses.parseNumericAddress(addr);
- }
-
- private IpPrefix Prefix(String prefix) {
- return new IpPrefix(prefix);
- }
-
- private static boolean isAtLeastR() {
- // BuildCompat.isAtLeastR is documented to return false on release SDKs (including R)
- return Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR();
- }
-
- @Test
- public void testConstructor() {
- RouteInfo r;
- // Invalid input.
- try {
- r = new RouteInfo((IpPrefix) null, null, "rmnet0");
- fail("Expected RuntimeException: destination and gateway null");
- } catch (RuntimeException e) { }
-
- try {
- r = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("2001:db8::1"), "rmnet0",
- INVALID_ROUTE_TYPE);
- fail("Invalid route type should cause exception");
- } catch (IllegalArgumentException e) { }
-
- try {
- r = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("192.0.2.1"), "rmnet0",
- RTN_UNREACHABLE);
- fail("Address family mismatch should cause exception");
- } catch (IllegalArgumentException e) { }
-
- try {
- r = new RouteInfo(Prefix("0.0.0.0/0"), Address("2001:db8::1"), "rmnet0",
- RTN_UNREACHABLE);
- fail("Address family mismatch should cause exception");
- } catch (IllegalArgumentException e) { }
-
- // Null destination is default route.
- r = new RouteInfo((IpPrefix) null, Address("2001:db8::1"), null);
- assertEquals(Prefix("::/0"), r.getDestination());
- assertEquals(Address("2001:db8::1"), r.getGateway());
- assertNull(r.getInterface());
-
- r = new RouteInfo((IpPrefix) null, Address("192.0.2.1"), "wlan0");
- assertEquals(Prefix("0.0.0.0/0"), r.getDestination());
- assertEquals(Address("192.0.2.1"), r.getGateway());
- assertEquals("wlan0", r.getInterface());
-
- // Null gateway sets gateway to unspecified address (why?).
- r = new RouteInfo(Prefix("2001:db8:beef:cafe::/48"), null, "lo");
- assertEquals(Prefix("2001:db8:beef::/48"), r.getDestination());
- assertEquals(Address("::"), r.getGateway());
- assertEquals("lo", r.getInterface());
-
- r = new RouteInfo(Prefix("192.0.2.5/24"), null);
- assertEquals(Prefix("192.0.2.0/24"), r.getDestination());
- assertEquals(Address("0.0.0.0"), r.getGateway());
- assertNull(r.getInterface());
- }
-
- @Test
- public void testMatches() {
- class PatchedRouteInfo {
- private final RouteInfo mRouteInfo;
-
- public PatchedRouteInfo(IpPrefix destination, InetAddress gateway, String iface) {
- mRouteInfo = new RouteInfo(destination, gateway, iface);
- }
-
- public boolean matches(InetAddress destination) {
- return mRouteInfo.matches(destination);
- }
- }
-
- PatchedRouteInfo r;
-
- r = new PatchedRouteInfo(Prefix("2001:db8:f00::ace:d00d/127"), null, "rmnet0");
- assertTrue(r.matches(Address("2001:db8:f00::ace:d00c")));
- assertTrue(r.matches(Address("2001:db8:f00::ace:d00d")));
- assertFalse(r.matches(Address("2001:db8:f00::ace:d00e")));
- assertFalse(r.matches(Address("2001:db8:f00::bad:d00d")));
- assertFalse(r.matches(Address("2001:4868:4860::8888")));
- assertFalse(r.matches(Address("8.8.8.8")));
-
- r = new PatchedRouteInfo(Prefix("192.0.2.0/23"), null, "wlan0");
- assertTrue(r.matches(Address("192.0.2.43")));
- assertTrue(r.matches(Address("192.0.3.21")));
- assertFalse(r.matches(Address("192.0.0.21")));
- assertFalse(r.matches(Address("8.8.8.8")));
-
- PatchedRouteInfo ipv6Default = new PatchedRouteInfo(Prefix("::/0"), null, "rmnet0");
- assertTrue(ipv6Default.matches(Address("2001:db8::f00")));
- assertFalse(ipv6Default.matches(Address("192.0.2.1")));
-
- PatchedRouteInfo ipv4Default = new PatchedRouteInfo(Prefix("0.0.0.0/0"), null, "rmnet0");
- assertTrue(ipv4Default.matches(Address("255.255.255.255")));
- assertTrue(ipv4Default.matches(Address("192.0.2.1")));
- assertFalse(ipv4Default.matches(Address("2001:db8::f00")));
- }
-
- @Test
- public void testEquals() {
- // IPv4
- RouteInfo r1 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
- RouteInfo r2 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
- assertEqualBothWays(r1, r2);
-
- RouteInfo r3 = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("2001:db8::1"), "wlan0");
- RouteInfo r4 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::2"), "wlan0");
- RouteInfo r5 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "rmnet0");
- assertNotEqualEitherWay(r1, r3);
- assertNotEqualEitherWay(r1, r4);
- assertNotEqualEitherWay(r1, r5);
-
- // IPv6
- r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0");
- r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0");
- assertEqualBothWays(r1, r2);
-
- r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0");
- r4 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.2"), "wlan0");
- r5 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "rmnet0");
- assertNotEqualEitherWay(r1, r3);
- assertNotEqualEitherWay(r1, r4);
- assertNotEqualEitherWay(r1, r5);
-
- // Interfaces (but not destinations or gateways) can be null.
- r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null);
- r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null);
- r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0");
- assertEqualBothWays(r1, r2);
- assertNotEqualEitherWay(r1, r3);
- }
-
- @Test
- public void testHostAndDefaultRoutes() {
- RouteInfo r;
-
- r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0");
- assertFalse(r.isHostRoute());
- assertTrue(r.isDefaultRoute());
- assertTrue(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("::/0"), Address("::"), "wlan0");
- assertFalse(r.isHostRoute());
- assertTrue(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertTrue(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
- assertFalse(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("2001:db8::/48"), null, "wlan0");
- assertFalse(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("192.0.2.0/32"), Address("0.0.0.0"), "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("2001:db8::/128"), Address("::"), "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("192.0.2.0/32"), null, "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("2001:db8::/128"), null, "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("::/128"), Address("fe80::"), "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE);
- assertFalse(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertTrue(r.isIPv4UnreachableDefault());
- assertFalse(r.isIPv6UnreachableDefault());
- }
-
- r = new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE);
- assertFalse(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
- if (isAtLeastR()) {
- assertFalse(r.isIPv4UnreachableDefault());
- assertTrue(r.isIPv6UnreachableDefault());
- }
- }
-
- @Test
- public void testTruncation() {
- LinkAddress l;
- RouteInfo r;
-
- l = new LinkAddress("192.0.2.5/30");
- r = new RouteInfo(l, Address("192.0.2.1"), "wlan0");
- assertEquals("192.0.2.4", r.getDestination().getAddress().getHostAddress());
-
- l = new LinkAddress("2001:db8:1:f::5/63");
- r = new RouteInfo(l, Address("2001:db8:5::1"), "wlan0");
- assertEquals("2001:db8:1:e::", r.getDestination().getAddress().getHostAddress());
- }
-
- // Make sure that creating routes to multicast addresses doesn't throw an exception. Even though
- // there's nothing we can do with them, we don't want to crash if, e.g., someone calls
- // requestRouteToHostAddress("230.0.0.0", MOBILE_HIPRI);
- @Test
- public void testMulticastRoute() {
- RouteInfo r;
- r = new RouteInfo(Prefix("230.0.0.0/32"), Address("192.0.2.1"), "wlan0");
- r = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::1"), "wlan0");
- // No exceptions? Good.
- }
-
- @Test
- public void testParceling() {
- RouteInfo r;
- r = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), null);
- assertParcelingIsLossless(r);
- r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
- assertParcelingIsLossless(r);
- r = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0", RTN_UNREACHABLE);
- assertParcelingIsLossless(r);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testMtuParceling() {
- final RouteInfo r = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::"), "testiface",
- RTN_UNREACHABLE, 1450 /* mtu */);
- assertParcelingIsLossless(r);
- }
-
- @Test @IgnoreAfter(Build.VERSION_CODES.Q)
- public void testFieldCount_Q() {
- assertFieldCountEquals(6, RouteInfo.class);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testFieldCount() {
- // Make sure any new field is covered by the above parceling tests when changing this number
- assertFieldCountEquals(7, RouteInfo.class);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testMtu() {
- RouteInfo r;
- r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0",
- RouteInfo.RTN_UNICAST, 1500);
- assertEquals(1500, r.getMtu());
-
- r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0");
- assertEquals(0, r.getMtu());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testRouteKey() {
- RouteInfo.RouteKey k1, k2;
- // Only prefix, null gateway and null interface
- k1 = new RouteInfo(Prefix("2001:db8::/128"), null).getRouteKey();
- k2 = new RouteInfo(Prefix("2001:db8::/128"), null).getRouteKey();
- assertEquals(k1, k2);
- assertEquals(k1.hashCode(), k2.hashCode());
-
- // With prefix, gateway and interface. Type and MTU does not affect RouteKey equality
- k1 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0",
- RTN_UNREACHABLE, 1450).getRouteKey();
- k2 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0",
- RouteInfo.RTN_UNICAST, 1400).getRouteKey();
- assertEquals(k1, k2);
- assertEquals(k1.hashCode(), k2.hashCode());
-
- // Different scope IDs are ignored by the kernel, so we consider them equal here too.
- k1 = new RouteInfo(Prefix("2001:db8::/64"), Address("fe80::1%1"), "wlan0").getRouteKey();
- k2 = new RouteInfo(Prefix("2001:db8::/64"), Address("fe80::1%2"), "wlan0").getRouteKey();
- assertEquals(k1, k2);
- assertEquals(k1.hashCode(), k2.hashCode());
-
- // Different prefix
- k1 = new RouteInfo(Prefix("192.0.2.0/24"), null).getRouteKey();
- k2 = new RouteInfo(Prefix("192.0.3.0/24"), null).getRouteKey();
- assertNotEquals(k1, k2);
-
- // Different gateway
- k1 = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::1"), null).getRouteKey();
- k2 = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::2"), null).getRouteKey();
- assertNotEquals(k1, k2);
-
- // Different interface
- k1 = new RouteInfo(Prefix("ff02::1/128"), null, "tun0").getRouteKey();
- k2 = new RouteInfo(Prefix("ff02::1/128"), null, "tun1").getRouteKey();
- assertNotEquals(k1, k2);
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/StaticIpConfigurationTest.java b/packages/Connectivity/tests/common/java/android/net/StaticIpConfigurationTest.java
deleted file mode 100644
index b5f23bf..0000000
--- a/packages/Connectivity/tests/common/java/android/net/StaticIpConfigurationTest.java
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.os.Parcel;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class StaticIpConfigurationTest {
-
- private static final String ADDRSTR = "192.0.2.2/25";
- private static final LinkAddress ADDR = new LinkAddress(ADDRSTR);
- private static final InetAddress GATEWAY = IpAddress("192.0.2.1");
- private static final InetAddress OFFLINKGATEWAY = IpAddress("192.0.2.129");
- private static final InetAddress DNS1 = IpAddress("8.8.8.8");
- private static final InetAddress DNS2 = IpAddress("8.8.4.4");
- private static final InetAddress DNS3 = IpAddress("4.2.2.2");
- private static final String IFACE = "eth0";
- private static final String FAKE_DOMAINS = "google.com";
-
- private static InetAddress IpAddress(String addr) {
- return InetAddress.parseNumericAddress(addr);
- }
-
- private void checkEmpty(StaticIpConfiguration s) {
- assertNull(s.ipAddress);
- assertNull(s.gateway);
- assertNull(s.domains);
- assertEquals(0, s.dnsServers.size());
- }
-
- private StaticIpConfiguration makeTestObject() {
- StaticIpConfiguration s = new StaticIpConfiguration();
- s.ipAddress = ADDR;
- s.gateway = GATEWAY;
- s.dnsServers.add(DNS1);
- s.dnsServers.add(DNS2);
- s.dnsServers.add(DNS3);
- s.domains = FAKE_DOMAINS;
- return s;
- }
-
- @Test
- public void testConstructor() {
- StaticIpConfiguration s = new StaticIpConfiguration();
- checkEmpty(s);
- }
-
- @Test
- public void testCopyAndClear() {
- StaticIpConfiguration empty = new StaticIpConfiguration((StaticIpConfiguration) null);
- checkEmpty(empty);
-
- StaticIpConfiguration s1 = makeTestObject();
- StaticIpConfiguration s2 = new StaticIpConfiguration(s1);
- assertEquals(s1, s2);
- s2.clear();
- assertEquals(empty, s2);
- }
-
- @Test
- public void testHashCodeAndEquals() {
- HashSet<Integer> hashCodes = new HashSet();
- hashCodes.add(0);
-
- StaticIpConfiguration s = new StaticIpConfiguration();
- // Check that this hash code is nonzero and different from all the ones seen so far.
- assertTrue(hashCodes.add(s.hashCode()));
-
- s.ipAddress = ADDR;
- assertTrue(hashCodes.add(s.hashCode()));
-
- s.gateway = GATEWAY;
- assertTrue(hashCodes.add(s.hashCode()));
-
- s.dnsServers.add(DNS1);
- assertTrue(hashCodes.add(s.hashCode()));
-
- s.dnsServers.add(DNS2);
- assertTrue(hashCodes.add(s.hashCode()));
-
- s.dnsServers.add(DNS3);
- assertTrue(hashCodes.add(s.hashCode()));
-
- s.domains = "example.com";
- assertTrue(hashCodes.add(s.hashCode()));
-
- assertFalse(s.equals(null));
- assertEquals(s, s);
-
- StaticIpConfiguration s2 = new StaticIpConfiguration(s);
- assertEquals(s, s2);
-
- s.ipAddress = new LinkAddress(DNS1, 32);
- assertNotEquals(s, s2);
-
- s2 = new StaticIpConfiguration(s);
- s.domains = "foo";
- assertNotEquals(s, s2);
-
- s2 = new StaticIpConfiguration(s);
- s.gateway = DNS2;
- assertNotEquals(s, s2);
-
- s2 = new StaticIpConfiguration(s);
- s.dnsServers.add(DNS3);
- assertNotEquals(s, s2);
- }
-
- @Test
- public void testToLinkProperties() {
- LinkProperties expected = new LinkProperties();
- expected.setInterfaceName(IFACE);
-
- StaticIpConfiguration s = new StaticIpConfiguration();
- assertEquals(expected, s.toLinkProperties(IFACE));
-
- final RouteInfo connectedRoute = new RouteInfo(new IpPrefix(ADDRSTR), null, IFACE);
- s.ipAddress = ADDR;
- expected.addLinkAddress(ADDR);
- expected.addRoute(connectedRoute);
- assertEquals(expected, s.toLinkProperties(IFACE));
-
- s.gateway = GATEWAY;
- RouteInfo defaultRoute = new RouteInfo(new IpPrefix("0.0.0.0/0"), GATEWAY, IFACE);
- expected.addRoute(defaultRoute);
- assertEquals(expected, s.toLinkProperties(IFACE));
-
- s.gateway = OFFLINKGATEWAY;
- expected.removeRoute(defaultRoute);
- defaultRoute = new RouteInfo(new IpPrefix("0.0.0.0/0"), OFFLINKGATEWAY, IFACE);
- expected.addRoute(defaultRoute);
-
- RouteInfo gatewayRoute = new RouteInfo(new IpPrefix("192.0.2.129/32"), null, IFACE);
- expected.addRoute(gatewayRoute);
- assertEquals(expected, s.toLinkProperties(IFACE));
-
- s.dnsServers.add(DNS1);
- expected.addDnsServer(DNS1);
- assertEquals(expected, s.toLinkProperties(IFACE));
-
- s.dnsServers.add(DNS2);
- s.dnsServers.add(DNS3);
- expected.addDnsServer(DNS2);
- expected.addDnsServer(DNS3);
- assertEquals(expected, s.toLinkProperties(IFACE));
-
- s.domains = FAKE_DOMAINS;
- expected.setDomains(FAKE_DOMAINS);
- assertEquals(expected, s.toLinkProperties(IFACE));
-
- s.gateway = null;
- expected.removeRoute(defaultRoute);
- expected.removeRoute(gatewayRoute);
- assertEquals(expected, s.toLinkProperties(IFACE));
-
- // Without knowing the IP address, we don't have a directly-connected route, so we can't
- // tell if the gateway is off-link or not and we don't add a host route. This isn't a real
- // configuration, but we should at least not crash.
- s.gateway = OFFLINKGATEWAY;
- s.ipAddress = null;
- expected.removeLinkAddress(ADDR);
- expected.removeRoute(connectedRoute);
- expected.addRoute(defaultRoute);
- assertEquals(expected, s.toLinkProperties(IFACE));
- }
-
- private StaticIpConfiguration passThroughParcel(StaticIpConfiguration s) {
- Parcel p = Parcel.obtain();
- StaticIpConfiguration s2 = null;
- try {
- s.writeToParcel(p, 0);
- p.setDataPosition(0);
- s2 = StaticIpConfiguration.readFromParcel(p);
- } finally {
- p.recycle();
- }
- assertNotNull(s2);
- return s2;
- }
-
- @Test
- public void testParceling() {
- StaticIpConfiguration s = makeTestObject();
- StaticIpConfiguration s2 = passThroughParcel(s);
- assertEquals(s, s2);
- }
-
- @Test
- public void testBuilder() {
- final ArrayList<InetAddress> dnsServers = new ArrayList<>();
- dnsServers.add(DNS1);
-
- final StaticIpConfiguration s = new StaticIpConfiguration.Builder()
- .setIpAddress(ADDR)
- .setGateway(GATEWAY)
- .setDomains(FAKE_DOMAINS)
- .setDnsServers(dnsServers)
- .build();
-
- assertEquals(s.ipAddress, s.getIpAddress());
- assertEquals(ADDR, s.getIpAddress());
- assertEquals(s.gateway, s.getGateway());
- assertEquals(GATEWAY, s.getGateway());
- assertEquals(s.domains, s.getDomains());
- assertEquals(FAKE_DOMAINS, s.getDomains());
- assertTrue(s.dnsServers.equals(s.getDnsServers()));
- assertEquals(1, s.getDnsServers().size());
- assertEquals(DNS1, s.getDnsServers().get(0));
- }
-
- @Test
- public void testAddDnsServers() {
- final StaticIpConfiguration s = new StaticIpConfiguration((StaticIpConfiguration) null);
- checkEmpty(s);
-
- s.addDnsServer(DNS1);
- assertEquals(1, s.getDnsServers().size());
- assertEquals(DNS1, s.getDnsServers().get(0));
-
- s.addDnsServer(DNS2);
- s.addDnsServer(DNS3);
- assertEquals(3, s.getDnsServers().size());
- assertEquals(DNS2, s.getDnsServers().get(1));
- assertEquals(DNS3, s.getDnsServers().get(2));
- }
-
- @Test
- public void testGetRoutes() {
- final StaticIpConfiguration s = makeTestObject();
- final List<RouteInfo> routeInfoList = s.getRoutes(IFACE);
-
- assertEquals(2, routeInfoList.size());
- assertEquals(new RouteInfo(ADDR, (InetAddress) null, IFACE), routeInfoList.get(0));
- assertEquals(new RouteInfo((IpPrefix) null, GATEWAY, IFACE), routeInfoList.get(1));
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/TcpKeepalivePacketDataTest.kt b/packages/Connectivity/tests/common/java/android/net/TcpKeepalivePacketDataTest.kt
deleted file mode 100644
index 7a18bb0..0000000
--- a/packages/Connectivity/tests/common/java/android/net/TcpKeepalivePacketDataTest.kt
+++ /dev/null
@@ -1,106 +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.net
-
-import android.net.InetAddresses.parseNumericAddress
-import android.os.Build
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRunner
-import com.android.testutils.assertFieldCountEquals
-import com.android.testutils.assertParcelSane
-import org.junit.Test
-import org.junit.runner.RunWith
-import java.net.InetAddress
-import kotlin.test.assertEquals
-import kotlin.test.assertNotEquals
-import kotlin.test.assertTrue
-
-@RunWith(DevSdkIgnoreRunner::class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) // TcpKeepalivePacketData added to SDK in S
-class TcpKeepalivePacketDataTest {
- private fun makeData(
- srcAddress: InetAddress = parseNumericAddress("192.0.2.123"),
- srcPort: Int = 1234,
- dstAddress: InetAddress = parseNumericAddress("192.0.2.231"),
- dstPort: Int = 4321,
- data: ByteArray = byteArrayOf(1, 2, 3),
- tcpSeq: Int = 135,
- tcpAck: Int = 246,
- tcpWnd: Int = 1234,
- tcpWndScale: Int = 2,
- ipTos: Int = 0x12,
- ipTtl: Int = 10
- ) = TcpKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, data, tcpSeq, tcpAck,
- tcpWnd, tcpWndScale, ipTos, ipTtl)
-
- @Test
- fun testEquals() {
- val data1 = makeData()
- val data2 = makeData()
- assertEquals(data1, data2)
- assertEquals(data1.hashCode(), data2.hashCode())
- }
-
- @Test
- fun testNotEquals() {
- assertNotEquals(makeData(srcAddress = parseNumericAddress("192.0.2.124")), makeData())
- assertNotEquals(makeData(srcPort = 1235), makeData())
- assertNotEquals(makeData(dstAddress = parseNumericAddress("192.0.2.232")), makeData())
- assertNotEquals(makeData(dstPort = 4322), makeData())
- // .equals does not test .packet, as it should be generated from the other fields
- assertNotEquals(makeData(tcpSeq = 136), makeData())
- assertNotEquals(makeData(tcpAck = 247), makeData())
- assertNotEquals(makeData(tcpWnd = 1235), makeData())
- assertNotEquals(makeData(tcpWndScale = 3), makeData())
- assertNotEquals(makeData(ipTos = 0x14), makeData())
- assertNotEquals(makeData(ipTtl = 11), makeData())
-
- // Update above assertions if field is added
- assertFieldCountEquals(5, KeepalivePacketData::class.java)
- assertFieldCountEquals(6, TcpKeepalivePacketData::class.java)
- }
-
- @Test
- fun testParcelUnparcel() {
- assertParcelSane(makeData(), fieldCount = 6) { a, b ->
- // .equals() does not verify .packet
- a == b && a.packet contentEquals b.packet
- }
- }
-
- @Test
- fun testToString() {
- val data = makeData()
- val str = data.toString()
-
- assertTrue(str.contains(data.srcAddress.hostAddress))
- assertTrue(str.contains(data.srcPort.toString()))
- assertTrue(str.contains(data.dstAddress.hostAddress))
- assertTrue(str.contains(data.dstPort.toString()))
- // .packet not included in toString()
- assertTrue(str.contains(data.getTcpSeq().toString()))
- assertTrue(str.contains(data.getTcpAck().toString()))
- assertTrue(str.contains(data.getTcpWindow().toString()))
- assertTrue(str.contains(data.getTcpWindowScale().toString()))
- assertTrue(str.contains(data.getIpTos().toString()))
- assertTrue(str.contains(data.getIpTtl().toString()))
-
- // Update above assertions if field is added
- assertFieldCountEquals(5, KeepalivePacketData::class.java)
- assertFieldCountEquals(6, TcpKeepalivePacketData::class.java)
- }
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/common/java/android/net/UidRangeTest.java b/packages/Connectivity/tests/common/java/android/net/UidRangeTest.java
deleted file mode 100644
index 1b1c954..0000000
--- a/packages/Connectivity/tests/common/java/android/net/UidRangeTest.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.os.UserHandle.MIN_SECONDARY_USER_ID;
-import static android.os.UserHandle.SYSTEM;
-import static android.os.UserHandle.USER_SYSTEM;
-import static android.os.UserHandle.getUid;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.os.Build;
-import android.os.UserHandle;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class UidRangeTest {
-
- /*
- * UidRange is no longer passed to netd. UID ranges between the framework and netd are passed as
- * UidRangeParcel objects.
- */
-
- @Rule
- public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
-
- @Test
- public void testSingleItemUidRangeAllowed() {
- new UidRange(123, 123);
- new UidRange(0, 0);
- new UidRange(Integer.MAX_VALUE, Integer.MAX_VALUE);
- }
-
- @Test
- public void testNegativeUidsDisallowed() {
- try {
- new UidRange(-2, 100);
- fail("Exception not thrown for negative start UID");
- } catch (IllegalArgumentException expected) {
- }
-
- try {
- new UidRange(-200, -100);
- fail("Exception not thrown for negative stop UID");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testStopLessThanStartDisallowed() {
- final int x = 4195000;
- try {
- new UidRange(x, x - 1);
- fail("Exception not thrown for negative-length UID range");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testGetStartAndEndUser() throws Exception {
- final UidRange uidRangeOfPrimaryUser = new UidRange(
- getUid(USER_SYSTEM, 10000), getUid(USER_SYSTEM, 10100));
- final UidRange uidRangeOfSecondaryUser = new UidRange(
- getUid(MIN_SECONDARY_USER_ID, 10000), getUid(MIN_SECONDARY_USER_ID, 10100));
- assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
- assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getEndUser());
- assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getStartUser());
- assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getEndUser());
-
- final UidRange uidRangeForDifferentUsers = new UidRange(
- getUid(USER_SYSTEM, 10000), getUid(MIN_SECONDARY_USER_ID, 10100));
- assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
- assertEquals(MIN_SECONDARY_USER_ID, uidRangeOfSecondaryUser.getEndUser());
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.R)
- public void testCreateForUser() throws Exception {
- final UidRange uidRangeOfPrimaryUser = UidRange.createForUser(SYSTEM);
- final UidRange uidRangeOfSecondaryUser = UidRange.createForUser(
- UserHandle.of(USER_SYSTEM + 1));
- assertTrue(uidRangeOfPrimaryUser.stop < uidRangeOfSecondaryUser.start);
- assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getStartUser());
- assertEquals(USER_SYSTEM, uidRangeOfPrimaryUser.getEndUser());
- assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getStartUser());
- assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getEndUser());
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/UnderlyingNetworkInfoTest.kt b/packages/Connectivity/tests/common/java/android/net/UnderlyingNetworkInfoTest.kt
deleted file mode 100644
index f23ba26..0000000
--- a/packages/Connectivity/tests/common/java/android/net/UnderlyingNetworkInfoTest.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net
-
-import android.os.Build
-import androidx.test.filters.SmallTest
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRunner
-import com.android.testutils.assertParcelSane
-import org.junit.Test
-import org.junit.runner.RunWith
-import kotlin.test.assertEquals
-
-private const val TEST_OWNER_UID = 123
-private const val TEST_IFACE = "test_tun0"
-private val TEST_IFACE_LIST = listOf("wlan0", "rmnet_data0", "eth0")
-
-@SmallTest
-@RunWith(DevSdkIgnoreRunner::class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
-class UnderlyingNetworkInfoTest {
- @Test
- fun testParcelUnparcel() {
- val testInfo = UnderlyingNetworkInfo(TEST_OWNER_UID, TEST_IFACE, TEST_IFACE_LIST)
- assertEquals(TEST_OWNER_UID, testInfo.getOwnerUid())
- assertEquals(TEST_IFACE, testInfo.getInterface())
- assertEquals(TEST_IFACE_LIST, testInfo.getUnderlyingInterfaces())
- assertParcelSane(testInfo, 3)
-
- val emptyInfo = UnderlyingNetworkInfo(0, String(), listOf())
- assertEquals(0, emptyInfo.getOwnerUid())
- assertEquals(String(), emptyInfo.getInterface())
- assertEquals(listOf(), emptyInfo.getUnderlyingInterfaces())
- assertParcelSane(emptyInfo, 3)
- }
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/common/java/android/net/apf/ApfCapabilitiesTest.java b/packages/Connectivity/tests/common/java/android/net/apf/ApfCapabilitiesTest.java
deleted file mode 100644
index 88996d9..0000000
--- a/packages/Connectivity/tests/common/java/android/net/apf/ApfCapabilitiesTest.java
+++ /dev/null
@@ -1,132 +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 android.net.apf;
-
-import static com.android.testutils.ParcelUtils.assertParcelSane;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.os.Build;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.DevSdkIgnoreRule;
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ApfCapabilitiesTest {
- @Rule
- public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
-
- private Context mContext;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getContext();
- }
-
- @Test
- public void testConstructAndParcel() {
- final ApfCapabilities caps = new ApfCapabilities(123, 456, 789);
- assertEquals(123, caps.apfVersionSupported);
- assertEquals(456, caps.maximumApfProgramSize);
- assertEquals(789, caps.apfPacketFormat);
-
- assertParcelSane(caps, 3);
- }
-
- @Test
- public void testEquals() {
- assertEquals(new ApfCapabilities(1, 2, 3), new ApfCapabilities(1, 2, 3));
- assertNotEquals(new ApfCapabilities(2, 2, 3), new ApfCapabilities(1, 2, 3));
- assertNotEquals(new ApfCapabilities(1, 3, 3), new ApfCapabilities(1, 2, 3));
- assertNotEquals(new ApfCapabilities(1, 2, 4), new ApfCapabilities(1, 2, 3));
- }
-
- @Test
- public void testHasDataAccess() {
- //hasDataAccess is only supported starting at apf version 4.
- ApfCapabilities caps = new ApfCapabilities(1 /* apfVersionSupported */, 2, 3);
- assertFalse(caps.hasDataAccess());
-
- caps = new ApfCapabilities(4 /* apfVersionSupported */, 5, 6);
- assertTrue(caps.hasDataAccess());
- }
-
- @Test
- public void testGetApfDrop8023Frames() {
- // Get com.android.internal.R.bool.config_apfDrop802_3Frames. The test cannot directly
- // use R.bool.config_apfDrop802_3Frames because that is not a stable resource ID.
- final int resId = mContext.getResources().getIdentifier("config_apfDrop802_3Frames",
- "bool", "android");
- final boolean shouldDrop8023Frames = mContext.getResources().getBoolean(resId);
- final boolean actual = ApfCapabilities.getApfDrop8023Frames();
- assertEquals(shouldDrop8023Frames, actual);
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.R)
- public void testGetApfDrop8023Frames_S() {
- // IpClient does not call getApfDrop8023Frames() since S, so any customization of the return
- // value on S+ is a configuration error as it will not be used by IpClient.
- assertTrue("android.R.bool.config_apfDrop802_3Frames has been modified to false, but "
- + "starting from S its value is not used by IpClient. If the modification is "
- + "intentional, use a runtime resource overlay for the NetworkStack package to "
- + "overlay com.android.networkstack.R.bool.config_apfDrop802_3Frames instead.",
- ApfCapabilities.getApfDrop8023Frames());
- }
-
- @Test
- public void testGetApfEtherTypeBlackList() {
- // Get com.android.internal.R.array.config_apfEthTypeBlackList. The test cannot directly
- // use R.array.config_apfEthTypeBlackList because that is not a stable resource ID.
- final int resId = mContext.getResources().getIdentifier("config_apfEthTypeBlackList",
- "array", "android");
- final int[] blacklistedEtherTypeArray = mContext.getResources().getIntArray(resId);
- final int[] actual = ApfCapabilities.getApfEtherTypeBlackList();
- assertNotNull(actual);
- assertTrue(Arrays.equals(blacklistedEtherTypeArray, actual));
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.R)
- public void testGetApfEtherTypeBlackList_S() {
- // IpClient does not call getApfEtherTypeBlackList() since S, so any customization of the
- // return value on S+ is a configuration error as it will not be used by IpClient.
- assertArrayEquals("android.R.array.config_apfEthTypeBlackList has been modified, but "
- + "starting from S its value is not used by IpClient. If the modification "
- + "is intentional, use a runtime resource overlay for the NetworkStack "
- + "package to overlay "
- + "com.android.networkstack.R.array.config_apfEthTypeDenyList instead.",
- new int[] { 0x88a2, 0x88a4, 0x88b8, 0x88cd, 0x88e3 },
- ApfCapabilities.getApfEtherTypeBlackList());
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/metrics/ApfProgramEventTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/ApfProgramEventTest.kt
deleted file mode 100644
index 0b7b740..0000000
--- a/packages/Connectivity/tests/common/java/android/net/metrics/ApfProgramEventTest.kt
+++ /dev/null
@@ -1,72 +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 android.net.metrics;
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class ApfProgramEventTest {
- private infix fun Int.hasFlag(flag: Int) = (this and (1 shl flag)) != 0
-
- @Test
- fun testBuilderAndParcel() {
- val apfProgramEvent = ApfProgramEvent.Builder()
- .setLifetime(1)
- .setActualLifetime(2)
- .setFilteredRas(3)
- .setCurrentRas(4)
- .setProgramLength(5)
- .setFlags(true, true)
- .build()
-
- assertEquals(1, apfProgramEvent.lifetime)
- assertEquals(2, apfProgramEvent.actualLifetime)
- assertEquals(3, apfProgramEvent.filteredRas)
- assertEquals(4, apfProgramEvent.currentRas)
- assertEquals(5, apfProgramEvent.programLength)
- assertEquals(ApfProgramEvent.flagsFor(true, true), apfProgramEvent.flags)
-
- assertParcelSane(apfProgramEvent, 6)
- }
-
- @Test
- fun testFlagsFor() {
- var flags = ApfProgramEvent.flagsFor(false, false)
- assertFalse(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
- assertFalse(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
-
- flags = ApfProgramEvent.flagsFor(true, false)
- assertTrue(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
- assertFalse(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
-
- flags = ApfProgramEvent.flagsFor(false, true)
- assertFalse(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
- assertTrue(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
-
- flags = ApfProgramEvent.flagsFor(true, true)
- assertTrue(flags hasFlag ApfProgramEvent.FLAG_HAS_IPV4_ADDRESS)
- assertTrue(flags hasFlag ApfProgramEvent.FLAG_MULTICAST_FILTER_ON)
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/metrics/ApfStatsTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/ApfStatsTest.kt
deleted file mode 100644
index 46a8c8e..0000000
--- a/packages/Connectivity/tests/common/java/android/net/metrics/ApfStatsTest.kt
+++ /dev/null
@@ -1,57 +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 android.net.metrics
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class ApfStatsTest {
- @Test
- fun testBuilderAndParcel() {
- val apfStats = ApfStats.Builder()
- .setDurationMs(Long.MAX_VALUE)
- .setReceivedRas(1)
- .setMatchingRas(2)
- .setDroppedRas(3)
- .setZeroLifetimeRas(4)
- .setParseErrors(5)
- .setProgramUpdates(6)
- .setProgramUpdatesAll(7)
- .setProgramUpdatesAllowingMulticast(8)
- .setMaxProgramSize(9)
- .build()
-
- assertEquals(Long.MAX_VALUE, apfStats.durationMs)
- assertEquals(1, apfStats.receivedRas)
- assertEquals(2, apfStats.matchingRas)
- assertEquals(3, apfStats.droppedRas)
- assertEquals(4, apfStats.zeroLifetimeRas)
- assertEquals(5, apfStats.parseErrors)
- assertEquals(6, apfStats.programUpdates)
- assertEquals(7, apfStats.programUpdatesAll)
- assertEquals(8, apfStats.programUpdatesAllowingMulticast)
- assertEquals(9, apfStats.maxProgramSize)
-
- assertParcelSane(apfStats, 10)
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/metrics/DhcpClientEventTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/DhcpClientEventTest.kt
deleted file mode 100644
index 8d7a9c4..0000000
--- a/packages/Connectivity/tests/common/java/android/net/metrics/DhcpClientEventTest.kt
+++ /dev/null
@@ -1,43 +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 android.net.metrics
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-private const val FAKE_MESSAGE = "test"
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class DhcpClientEventTest {
- @Test
- fun testBuilderAndParcel() {
- val dhcpClientEvent = DhcpClientEvent.Builder()
- .setMsg(FAKE_MESSAGE)
- .setDurationMs(Integer.MAX_VALUE)
- .build()
-
- assertEquals(FAKE_MESSAGE, dhcpClientEvent.msg)
- assertEquals(Integer.MAX_VALUE, dhcpClientEvent.durationMs)
-
- assertParcelSane(dhcpClientEvent, 2)
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/metrics/DhcpErrorEventTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/DhcpErrorEventTest.kt
deleted file mode 100644
index 236f72e..0000000
--- a/packages/Connectivity/tests/common/java/android/net/metrics/DhcpErrorEventTest.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-package android.net.metrics
-
-import android.net.metrics.DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH
-import android.net.metrics.DhcpErrorEvent.errorCodeWithOption
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.parcelingRoundTrip
-import java.lang.reflect.Modifier
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNotNull
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-
-private const val TEST_ERROR_CODE = 12345
-//DHCP Optional Type: DHCP Subnet Mask (Copy from DhcpPacket.java due to it's protected)
-private const val DHCP_SUBNET_MASK = 1
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class DhcpErrorEventTest {
-
- @Test
- fun testConstructor() {
- val event = DhcpErrorEvent(TEST_ERROR_CODE)
- assertEquals(TEST_ERROR_CODE, event.errorCode)
- }
-
- @Test
- fun testParcelUnparcel() {
- val event = DhcpErrorEvent(TEST_ERROR_CODE)
- val parceled = parcelingRoundTrip(event)
- assertEquals(TEST_ERROR_CODE, parceled.errorCode)
- }
-
- @Test
- fun testErrorCodeWithOption() {
- val errorCode = errorCodeWithOption(DHCP_INVALID_OPTION_LENGTH, DHCP_SUBNET_MASK);
- assertTrue((DHCP_INVALID_OPTION_LENGTH and errorCode) == DHCP_INVALID_OPTION_LENGTH);
- assertTrue((DHCP_SUBNET_MASK and errorCode) == DHCP_SUBNET_MASK);
- }
-
- @Test
- fun testToString() {
- val names = listOf("L2_ERROR", "L3_ERROR", "L4_ERROR", "DHCP_ERROR", "MISC_ERROR")
- val errorFields = DhcpErrorEvent::class.java.declaredFields.filter {
- it.type == Int::class.javaPrimitiveType
- && Modifier.isPublic(it.modifiers) && Modifier.isStatic(it.modifiers)
- && it.name !in names
- }
-
- errorFields.forEach {
- val intValue = it.getInt(null)
- val stringValue = DhcpErrorEvent(intValue).toString()
- assertTrue("Invalid string for error 0x%08X (field %s): %s".format(intValue, it.name,
- stringValue),
- stringValue.contains(it.name))
- }
- }
-
- @Test
- fun testToString_InvalidErrorCode() {
- assertNotNull(DhcpErrorEvent(TEST_ERROR_CODE).toString())
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/metrics/IpConnectivityLogTest.java b/packages/Connectivity/tests/common/java/android/net/metrics/IpConnectivityLogTest.java
deleted file mode 100644
index d4780d3..0000000
--- a/packages/Connectivity/tests/common/java/android/net/metrics/IpConnectivityLogTest.java
+++ /dev/null
@@ -1,161 +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 android.net.metrics;
-
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-
-import android.net.ConnectivityMetricsEvent;
-import android.net.IIpConnectivityMetrics;
-import android.net.Network;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.BitUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpConnectivityLogTest {
- private static final int FAKE_NET_ID = 100;
- private static final int[] FAKE_TRANSPORT_TYPES = BitUtils.unpackBits(TRANSPORT_WIFI);
- private static final long FAKE_TIME_STAMP = System.currentTimeMillis();
- private static final String FAKE_INTERFACE_NAME = "test";
- private static final IpReachabilityEvent FAKE_EV =
- new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED);
-
- @Mock IIpConnectivityMetrics mMockService;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- }
-
- @Test
- public void testLoggingEvents() throws Exception {
- IpConnectivityLog logger = new IpConnectivityLog(mMockService);
-
- assertTrue(logger.log(FAKE_EV));
- assertTrue(logger.log(FAKE_TIME_STAMP, FAKE_EV));
- assertTrue(logger.log(FAKE_NET_ID, FAKE_TRANSPORT_TYPES, FAKE_EV));
- assertTrue(logger.log(new Network(FAKE_NET_ID), FAKE_TRANSPORT_TYPES, FAKE_EV));
- assertTrue(logger.log(FAKE_INTERFACE_NAME, FAKE_EV));
- assertTrue(logger.log(makeExpectedEvent(FAKE_TIME_STAMP, FAKE_NET_ID, TRANSPORT_WIFI,
- FAKE_INTERFACE_NAME)));
-
- List<ConnectivityMetricsEvent> got = verifyEvents(6);
- assertEventsEqual(makeExpectedEvent(got.get(0).timestamp, 0, 0, null), got.get(0));
- assertEventsEqual(makeExpectedEvent(FAKE_TIME_STAMP, 0, 0, null), got.get(1));
- assertEventsEqual(makeExpectedEvent(got.get(2).timestamp, FAKE_NET_ID,
- TRANSPORT_WIFI, null), got.get(2));
- assertEventsEqual(makeExpectedEvent(got.get(3).timestamp, FAKE_NET_ID,
- TRANSPORT_WIFI, null), got.get(3));
- assertEventsEqual(makeExpectedEvent(got.get(4).timestamp, 0, 0, FAKE_INTERFACE_NAME),
- got.get(4));
- assertEventsEqual(makeExpectedEvent(FAKE_TIME_STAMP, FAKE_NET_ID,
- TRANSPORT_WIFI, FAKE_INTERFACE_NAME), got.get(5));
- }
-
- @Test
- public void testLoggingEventsWithMultipleCallers() throws Exception {
- IpConnectivityLog logger = new IpConnectivityLog(mMockService);
-
- final int nCallers = 10;
- final int nEvents = 10;
- for (int n = 0; n < nCallers; n++) {
- final int i = n;
- new Thread() {
- public void run() {
- for (int j = 0; j < nEvents; j++) {
- assertTrue(logger.log(makeExpectedEvent(
- FAKE_TIME_STAMP + i * 100 + j,
- FAKE_NET_ID + i * 100 + j,
- ((i + j) % 2 == 0) ? TRANSPORT_WIFI : TRANSPORT_CELLULAR,
- FAKE_INTERFACE_NAME)));
- }
- }
- }.start();
- }
-
- List<ConnectivityMetricsEvent> got = verifyEvents(nCallers * nEvents, 200);
- Collections.sort(got, EVENT_COMPARATOR);
- Iterator<ConnectivityMetricsEvent> iter = got.iterator();
- for (int i = 0; i < nCallers; i++) {
- for (int j = 0; j < nEvents; j++) {
- final long expectedTimestamp = FAKE_TIME_STAMP + i * 100 + j;
- final int expectedNetId = FAKE_NET_ID + i * 100 + j;
- final long expectedTransports =
- ((i + j) % 2 == 0) ? TRANSPORT_WIFI : TRANSPORT_CELLULAR;
- assertEventsEqual(makeExpectedEvent(expectedTimestamp, expectedNetId,
- expectedTransports, FAKE_INTERFACE_NAME), iter.next());
- }
- }
- }
-
- private List<ConnectivityMetricsEvent> verifyEvents(int n, int timeoutMs) throws Exception {
- ArgumentCaptor<ConnectivityMetricsEvent> captor =
- ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
- verify(mMockService, timeout(timeoutMs).times(n)).logEvent(captor.capture());
- return captor.getAllValues();
- }
-
- private List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
- return verifyEvents(n, 10);
- }
-
-
- private ConnectivityMetricsEvent makeExpectedEvent(long timestamp, int netId, long transports,
- String ifname) {
- ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
- ev.timestamp = timestamp;
- ev.data = FAKE_EV;
- ev.netId = netId;
- ev.transports = transports;
- ev.ifname = ifname;
- return ev;
- }
-
- /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
- private void assertEventsEqual(ConnectivityMetricsEvent expected,
- ConnectivityMetricsEvent got) {
- assertEquals(expected.data, got.data);
- assertEquals(expected.timestamp, got.timestamp);
- assertEquals(expected.netId, got.netId);
- assertEquals(expected.transports, got.transports);
- assertEquals(expected.ifname, got.ifname);
- }
-
- static final Comparator<ConnectivityMetricsEvent> EVENT_COMPARATOR =
- Comparator.comparingLong((ev) -> ev.timestamp);
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/metrics/IpManagerEventTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/IpManagerEventTest.kt
deleted file mode 100644
index 64be508..0000000
--- a/packages/Connectivity/tests/common/java/android/net/metrics/IpManagerEventTest.kt
+++ /dev/null
@@ -1,39 +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 android.net.metrics
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class IpManagerEventTest {
- @Test
- fun testConstructorAndParcel() {
- (IpManagerEvent.PROVISIONING_OK..IpManagerEvent.ERROR_INTERFACE_NOT_FOUND).forEach {
- val ipManagerEvent = IpManagerEvent(it, Long.MAX_VALUE)
- assertEquals(it, ipManagerEvent.eventType)
- assertEquals(Long.MAX_VALUE, ipManagerEvent.durationMs)
-
- assertParcelSane(ipManagerEvent, 2)
- }
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/metrics/IpReachabilityEventTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/IpReachabilityEventTest.kt
deleted file mode 100644
index 55b5e49..0000000
--- a/packages/Connectivity/tests/common/java/android/net/metrics/IpReachabilityEventTest.kt
+++ /dev/null
@@ -1,38 +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 android.net.metrics
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class IpReachabilityEventTest {
- @Test
- fun testConstructorAndParcel() {
- (IpReachabilityEvent.PROBE..IpReachabilityEvent.PROVISIONING_LOST_ORGANIC).forEach {
- val ipReachabilityEvent = IpReachabilityEvent(it)
- assertEquals(it, ipReachabilityEvent.eventType)
-
- assertParcelSane(ipReachabilityEvent, 1)
- }
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/metrics/NetworkEventTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/NetworkEventTest.kt
deleted file mode 100644
index 41430b0..0000000
--- a/packages/Connectivity/tests/common/java/android/net/metrics/NetworkEventTest.kt
+++ /dev/null
@@ -1,43 +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 android.net.metrics
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class NetworkEventTest {
- @Test
- fun testConstructorAndParcel() {
- (NetworkEvent.NETWORK_CONNECTED..NetworkEvent.NETWORK_PARTIAL_CONNECTIVITY).forEach {
- var networkEvent = NetworkEvent(it)
- assertEquals(it, networkEvent.eventType)
- assertEquals(0, networkEvent.durationMs)
-
- networkEvent = NetworkEvent(it, Long.MAX_VALUE)
- assertEquals(it, networkEvent.eventType)
- assertEquals(Long.MAX_VALUE, networkEvent.durationMs)
-
- assertParcelSane(networkEvent, 2)
- }
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/metrics/RaEventTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/RaEventTest.kt
deleted file mode 100644
index d9b7203..0000000
--- a/packages/Connectivity/tests/common/java/android/net/metrics/RaEventTest.kt
+++ /dev/null
@@ -1,72 +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 android.net.metrics
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-private const val NO_LIFETIME: Long = -1L
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class RaEventTest {
- @Test
- fun testConstructorAndParcel() {
- var raEvent = RaEvent.Builder().build()
- assertEquals(NO_LIFETIME, raEvent.routerLifetime)
- assertEquals(NO_LIFETIME, raEvent.prefixValidLifetime)
- assertEquals(NO_LIFETIME, raEvent.prefixPreferredLifetime)
- assertEquals(NO_LIFETIME, raEvent.routeInfoLifetime)
- assertEquals(NO_LIFETIME, raEvent.rdnssLifetime)
- assertEquals(NO_LIFETIME, raEvent.dnsslLifetime)
-
- raEvent = RaEvent.Builder()
- .updateRouterLifetime(1)
- .updatePrefixValidLifetime(2)
- .updatePrefixPreferredLifetime(3)
- .updateRouteInfoLifetime(4)
- .updateRdnssLifetime(5)
- .updateDnsslLifetime(6)
- .build()
- assertEquals(1, raEvent.routerLifetime)
- assertEquals(2, raEvent.prefixValidLifetime)
- assertEquals(3, raEvent.prefixPreferredLifetime)
- assertEquals(4, raEvent.routeInfoLifetime)
- assertEquals(5, raEvent.rdnssLifetime)
- assertEquals(6, raEvent.dnsslLifetime)
-
- raEvent = RaEvent.Builder()
- .updateRouterLifetime(Long.MIN_VALUE)
- .updateRouterLifetime(Long.MAX_VALUE)
- .build()
- assertEquals(Long.MIN_VALUE, raEvent.routerLifetime)
-
- raEvent = RaEvent(1, 2, 3, 4, 5, 6)
- assertEquals(1, raEvent.routerLifetime)
- assertEquals(2, raEvent.prefixValidLifetime)
- assertEquals(3, raEvent.prefixPreferredLifetime)
- assertEquals(4, raEvent.routeInfoLifetime)
- assertEquals(5, raEvent.rdnssLifetime)
- assertEquals(6, raEvent.dnsslLifetime)
-
- assertParcelSane(raEvent, 6)
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/metrics/ValidationProbeEventTest.kt b/packages/Connectivity/tests/common/java/android/net/metrics/ValidationProbeEventTest.kt
deleted file mode 100644
index 51c0d41..0000000
--- a/packages/Connectivity/tests/common/java/android/net/metrics/ValidationProbeEventTest.kt
+++ /dev/null
@@ -1,72 +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 android.net.metrics
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import java.lang.reflect.Modifier
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-
-private const val FIRST_VALIDATION: Int = 1 shl 8
-private const val REVALIDATION: Int = 2 shl 8
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class ValidationProbeEventTest {
- private infix fun Int.hasType(type: Int) = (type and this) == type
-
- @Test
- fun testBuilderAndParcel() {
- var validationProbeEvent = ValidationProbeEvent.Builder()
- .setProbeType(ValidationProbeEvent.PROBE_DNS, false).build()
-
- assertTrue(validationProbeEvent.probeType hasType REVALIDATION)
-
- validationProbeEvent = ValidationProbeEvent.Builder()
- .setDurationMs(Long.MAX_VALUE)
- .setProbeType(ValidationProbeEvent.PROBE_DNS, true)
- .setReturnCode(ValidationProbeEvent.DNS_SUCCESS)
- .build()
-
- assertEquals(Long.MAX_VALUE, validationProbeEvent.durationMs)
- assertTrue(validationProbeEvent.probeType hasType ValidationProbeEvent.PROBE_DNS)
- assertTrue(validationProbeEvent.probeType hasType FIRST_VALIDATION)
- assertEquals(ValidationProbeEvent.DNS_SUCCESS, validationProbeEvent.returnCode)
-
- assertParcelSane(validationProbeEvent, 3)
- }
-
- @Test
- fun testGetProbeName() {
- val probeFields = ValidationProbeEvent::class.java.declaredFields.filter {
- it.type == Int::class.javaPrimitiveType
- && Modifier.isPublic(it.modifiers) && Modifier.isStatic(it.modifiers)
- && it.name.contains("PROBE")
- }
-
- probeFields.forEach {
- val intValue = it.getInt(null)
- val stringValue = ValidationProbeEvent.getProbeName(intValue)
- assertEquals(it.name, stringValue)
- }
-
- }
-}
diff --git a/packages/Connectivity/tests/common/java/android/net/netstats/NetworkStatsApiTest.kt b/packages/Connectivity/tests/common/java/android/net/netstats/NetworkStatsApiTest.kt
deleted file mode 100644
index 7b22e45..0000000
--- a/packages/Connectivity/tests/common/java/android/net/netstats/NetworkStatsApiTest.kt
+++ /dev/null
@@ -1,209 +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.net.netstats
-
-import android.net.NetworkStats
-import android.net.NetworkStats.DEFAULT_NETWORK_NO
-import android.net.NetworkStats.DEFAULT_NETWORK_YES
-import android.net.NetworkStats.Entry
-import android.net.NetworkStats.IFACE_VT
-import android.net.NetworkStats.METERED_NO
-import android.net.NetworkStats.METERED_YES
-import android.net.NetworkStats.ROAMING_NO
-import android.net.NetworkStats.ROAMING_YES
-import android.net.NetworkStats.SET_DEFAULT
-import android.net.NetworkStats.SET_FOREGROUND
-import android.net.NetworkStats.TAG_NONE
-import android.os.Build
-import androidx.test.filters.SmallTest
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.assertFieldCountEquals
-import com.android.testutils.assertNetworkStatsEquals
-import com.android.testutils.assertParcelingIsLossless
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import kotlin.test.assertEquals
-
-@RunWith(JUnit4::class)
-@SmallTest
-class NetworkStatsApiTest {
- @Rule
- @JvmField
- val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q)
-
- private val testStatsEmpty = NetworkStats(0L, 0)
-
- // Note that these variables need to be initialized outside of constructor, initialize
- // here with methods that don't exist in Q devices will result in crash.
-
- // stats1 and stats2 will have some entries with common keys, which are expected to
- // be merged if performing add on these 2 stats.
- private lateinit var testStats1: NetworkStats
- private lateinit var testStats2: NetworkStats
-
- // This is a result of adding stats1 and stats2, while the merging of common key items is
- // subject to test later, this should not be initialized with for a loop to add stats1
- // and stats2 above.
- private lateinit var testStats3: NetworkStats
-
- companion object {
- private const val TEST_IFACE = "test0"
- private const val TEST_UID1 = 1001
- private const val TEST_UID2 = 1002
- }
-
- @Before
- fun setUp() {
- testStats1 = NetworkStats(0L, 0)
- // Entries which only appear in set1.
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 37, 52, 1, 10, 4))
- // Entries which are common for set1 and set2.
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 17, 2, 11, 1, 0))
- .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 40, 1, 0, 0, 8))
- .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 1, 6, 2, 0))
- assertEquals(8, testStats1.size())
-
- testStats2 = NetworkStats(0L, 0)
- // Entries which are common for set1 and set2.
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45))
- .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7))
- .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0))
- // Entry which only appears in set2.
- .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
- assertEquals(5, testStats2.size())
-
- testStats3 = NetworkStats(0L, 9)
- // Entries which are unique either in stats1 or stats2.
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 101, 2, 103, 4, 5))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 31, 7, 24, 5, 8))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 25, 3, 47, 8, 2))
- .addEntry(Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
- // Entries which are common for stats1 and stats2 are being merged.
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 20, 3, 57, 40, 3))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 20, 17, 13, 32, 1))
- .addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 50, 113, 11, 11, 49))
- .addEntry(Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 51, 3, 3, 4, 15))
- .addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 7, 4, 8, 3, 0))
- assertEquals(9, testStats3.size())
- }
-
- @Test
- fun testAddEntry() {
- val expectedEntriesInStats2 = arrayOf(
- Entry(TEST_IFACE, TEST_UID1, SET_DEFAULT, 0x80,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 3, 15, 2, 31, 1),
- Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45),
- Entry(TEST_IFACE, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 11, 2, 3, 4, 7),
- Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4, 3, 2, 1, 0),
- Entry(IFACE_VT, TEST_UID2, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2, 3, 7, 8, 0))
-
- // While testStats* are already initialized with addEntry, verify content added
- // matches expectation.
- for (i in expectedEntriesInStats2.indices) {
- val entry = testStats2.getValues(i, null)
- assertEquals(expectedEntriesInStats2[i], entry)
- }
-
- // Verify entry updated with addEntry.
- val stats = testStats2.addEntry(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 12, -5, 7, 0, 9))
- assertEquals(Entry(IFACE_VT, TEST_UID1, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 16, -2, 9, 1, 9),
- stats.getValues(3, null))
- }
-
- @Test
- fun testAdd() {
- var stats = NetworkStats(0L, 0)
- assertNetworkStatsEquals(testStatsEmpty, stats)
- stats = stats.add(testStats2)
- assertNetworkStatsEquals(testStats2, stats)
- stats = stats.add(testStats1)
- // EMPTY + STATS2 + STATS1 = STATS3
- assertNetworkStatsEquals(testStats3, stats)
- }
-
- @Test
- fun testParcelUnparcel() {
- assertParcelingIsLossless(testStatsEmpty)
- assertParcelingIsLossless(testStats1)
- assertParcelingIsLossless(testStats2)
- assertFieldCountEquals(15, NetworkStats::class.java)
- }
-
- @Test
- fun testDescribeContents() {
- assertEquals(0, testStatsEmpty.describeContents())
- assertEquals(0, testStats1.describeContents())
- assertEquals(0, testStats2.describeContents())
- assertEquals(0, testStats3.describeContents())
- }
-
- @Test
- fun testSubtract() {
- // STATS3 - STATS2 = STATS1
- assertNetworkStatsEquals(testStats1, testStats3.subtract(testStats2))
- // STATS3 - STATS1 = STATS2
- assertNetworkStatsEquals(testStats2, testStats3.subtract(testStats1))
- }
-
- @Test
- fun testMethodsDontModifyReceiver() {
- listOf(testStatsEmpty, testStats1, testStats2, testStats3).forEach {
- val origStats = it.clone()
- it.addEntry(Entry(TEST_IFACE, TEST_UID1, SET_FOREGROUND, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 13, 61, 10, 1, 45))
- it.add(testStats3)
- it.subtract(testStats1)
- assertNetworkStatsEquals(origStats, it)
- }
- }
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/common/java/android/net/util/SocketUtilsTest.kt b/packages/Connectivity/tests/common/java/android/net/util/SocketUtilsTest.kt
deleted file mode 100644
index aaf97f3..0000000
--- a/packages/Connectivity/tests/common/java/android/net/util/SocketUtilsTest.kt
+++ /dev/null
@@ -1,90 +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 android.net.util
-
-import android.os.Build
-import android.system.NetlinkSocketAddress
-import android.system.Os
-import android.system.OsConstants.AF_INET
-import android.system.OsConstants.ETH_P_ALL
-import android.system.OsConstants.IPPROTO_UDP
-import android.system.OsConstants.RTMGRP_NEIGH
-import android.system.OsConstants.SOCK_DGRAM
-import android.system.PacketSocketAddress
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
-import org.junit.Assert.fail
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-private const val TEST_INDEX = 123
-private const val TEST_PORT = 555
-private const val FF_BYTE = 0xff.toByte()
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class SocketUtilsTest {
- @Rule @JvmField
- val ignoreRule = DevSdkIgnoreRule()
-
- @Test
- fun testMakeNetlinkSocketAddress() {
- val nlAddress = SocketUtils.makeNetlinkSocketAddress(TEST_PORT, RTMGRP_NEIGH)
- if (nlAddress is NetlinkSocketAddress) {
- assertEquals(TEST_PORT, nlAddress.getPortId())
- assertEquals(RTMGRP_NEIGH, nlAddress.getGroupsMask())
- } else {
- fail("Not NetlinkSocketAddress object")
- }
- }
-
- @Test
- fun testMakePacketSocketAddress_Q() {
- val pkAddress = SocketUtils.makePacketSocketAddress(ETH_P_ALL, TEST_INDEX)
- assertTrue("Not PacketSocketAddress object", pkAddress is PacketSocketAddress)
-
- val pkAddress2 = SocketUtils.makePacketSocketAddress(TEST_INDEX, ByteArray(6) { FF_BYTE })
- assertTrue("Not PacketSocketAddress object", pkAddress2 is PacketSocketAddress)
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- fun testMakePacketSocketAddress() {
- val pkAddress = SocketUtils.makePacketSocketAddress(
- ETH_P_ALL, TEST_INDEX, ByteArray(6) { FF_BYTE })
- assertTrue("Not PacketSocketAddress object", pkAddress is PacketSocketAddress)
- }
-
- @Test
- fun testCloseSocket() {
- // Expect no exception happening with null object.
- SocketUtils.closeSocket(null)
-
- val fd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
- assertTrue(fd.valid())
- SocketUtils.closeSocket(fd)
- assertFalse(fd.valid())
- // Expecting socket should be still invalid even closed socket again.
- SocketUtils.closeSocket(fd)
- assertFalse(fd.valid())
- }
-}
diff --git a/packages/Connectivity/tests/deflake/Android.bp b/packages/Connectivity/tests/deflake/Android.bp
deleted file mode 100644
index 58ece37..0000000
--- a/packages/Connectivity/tests/deflake/Android.bp
+++ /dev/null
@@ -1,39 +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 {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-java_test_host {
- name: "FrameworksNetDeflakeTest",
- srcs: ["src/**/*.kt"],
- libs: [
- "junit",
- "tradefed",
- ],
- static_libs: [
- "kotlin-test",
- "net-host-tests-utils",
- ],
- data: [":FrameworksNetTests"],
- test_suites: ["device-tests"],
-}
diff --git a/packages/Connectivity/tests/deflake/src/com/android/server/net/FrameworksNetDeflakeTest.kt b/packages/Connectivity/tests/deflake/src/com/android/server/net/FrameworksNetDeflakeTest.kt
deleted file mode 100644
index 6285525..0000000
--- a/packages/Connectivity/tests/deflake/src/com/android/server/net/FrameworksNetDeflakeTest.kt
+++ /dev/null
@@ -1,28 +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.server.net
-
-import com.android.testutils.host.DeflakeHostTestBase
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
-import org.junit.runner.RunWith
-
-@RunWith(DeviceJUnit4ClassRunner::class)
-class FrameworksNetDeflakeTest: DeflakeHostTestBase() {
- override val runCount = 20
- override val testApkFilename = "FrameworksNetTests.apk"
- override val testClasses = listOf("com.android.server.ConnectivityServiceTest")
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/integration/Android.bp b/packages/Connectivity/tests/integration/Android.bp
deleted file mode 100644
index 39c424e..0000000
--- a/packages/Connectivity/tests/integration/Android.bp
+++ /dev/null
@@ -1,78 +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 {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_test {
- name: "FrameworksNetIntegrationTests",
- defaults: ["framework-connectivity-test-defaults"],
- platform_apis: true,
- certificate: "platform",
- srcs: [
- "src/**/*.kt",
- "src/**/*.aidl",
- ],
- libs: [
- "android.test.mock",
- ],
- static_libs: [
- "NetworkStackApiStableLib",
- "androidx.test.ext.junit",
- "frameworks-net-integration-testutils",
- "kotlin-reflect",
- "mockito-target-extended-minus-junit4",
- "net-tests-utils",
- "service-connectivity",
- "services.core",
- "services.net",
- "testables",
- ],
- test_suites: ["device-tests"],
- use_embedded_native_libs: true,
- jni_libs: [
- // For mockito extended
- "libdexmakerjvmtiagent",
- "libstaticjvmtiagent",
- // android_library does not include JNI libs: include NetworkStack dependencies here
- "libnativehelper_compat_libc++",
- "libnetworkstackutilsjni",
- ],
-}
-
-// Utilities for testing framework code both in integration and unit tests.
-java_library {
- name: "frameworks-net-integration-testutils",
- defaults: ["framework-connectivity-test-defaults"],
- srcs: ["util/**/*.java", "util/**/*.kt"],
- static_libs: [
- "androidx.annotation_annotation",
- "androidx.test.rules",
- "junit",
- "net-tests-utils",
- ],
- libs: [
- "service-connectivity",
- "services.core",
- "services.net",
- ],
-}
diff --git a/packages/Connectivity/tests/integration/AndroidManifest.xml b/packages/Connectivity/tests/integration/AndroidManifest.xml
deleted file mode 100644
index 2e13689..0000000
--- a/packages/Connectivity/tests/integration/AndroidManifest.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * 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.
- */
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.net.integrationtests">
-
- <!-- For ConnectivityService registerReceiverAsUser (receiving broadcasts) -->
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
- <!-- PermissionMonitor sets network permissions for each user -->
- <uses-permission android:name="android.permission.MANAGE_USERS"/>
- <!-- ConnectivityService sends notifications to BatteryStats -->
- <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS"/>
- <!-- Reading network status -->
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
- <uses-permission android:name="android.permission.NETWORK_FACTORY"/>
- <!-- Obtain LinkProperties callbacks with sensitive fields -->
- <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
- <uses-permission android:name="android.permission.NETWORK_STACK"/>
- <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY"/>
- <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
- <!-- Reading DeviceConfig flags -->
- <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
- <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
- <!-- Querying the resources package -->
- <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
- <application android:debuggable="true">
- <uses-library android:name="android.test.runner"/>
-
- <!-- This manifest is merged with the base manifest of the real NetworkStack app.
- Remove the NetworkStackService from the base (real) manifest, and replace with a test
- service that responds to the same intent -->
- <service android:name=".TestNetworkStackService"
- android:process="com.android.server.net.integrationtests.testnetworkstack"
- android:exported="true">
- <intent-filter>
- <action android:name="android.net.INetworkStackConnector.Test"/>
- </intent-filter>
- </service>
- <service android:name=".NetworkStackInstrumentationService"
- android:process="com.android.server.net.integrationtests.testnetworkstack"
- android:exported="true">
- <intent-filter>
- <action android:name=".INetworkStackInstrumentation"/>
- </intent-filter>
- </service>
- <service android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService"
- android:process="com.android.server.net.integrationtests.testnetworkstack"
- android:permission="android.permission.BIND_JOB_SERVICE"/>
-
- </application>
-
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.net.integrationtests"
- android:label="Frameworks Net Integration Tests"/>
-
-</manifest>
diff --git a/packages/Connectivity/tests/integration/res/values/config.xml b/packages/Connectivity/tests/integration/res/values/config.xml
deleted file mode 100644
index 2c8046f..0000000
--- a/packages/Connectivity/tests/integration/res/values/config.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <!--
- Override configuration for testing. The below settings use the config_ variants, which are
- normally used by RROs to override the setting with highest priority. -->
- <integer name="config_captive_portal_dns_probe_timeout">12500</integer>
- <string name="config_captive_portal_http_url" translatable="false">http://test.android.com</string>
- <string name="config_captive_portal_https_url" translatable="false">https://secure.test.android.com</string>
- <string-array name="config_captive_portal_fallback_urls" translatable="false">
- <item>http://fallback1.android.com</item>
- <item>http://fallback2.android.com</item>
- </string-array>
- <string-array name="config_captive_portal_fallback_probe_specs" translatable="false">
- </string-array>
-</resources>
diff --git a/packages/Connectivity/tests/integration/src/android/net/TestNetworkStackClient.kt b/packages/Connectivity/tests/integration/src/android/net/TestNetworkStackClient.kt
deleted file mode 100644
index 61ef5bd..0000000
--- a/packages/Connectivity/tests/integration/src/android/net/TestNetworkStackClient.kt
+++ /dev/null
@@ -1,75 +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 android.net
-
-import android.content.ComponentName
-import android.content.Context
-import android.content.Intent
-import android.net.networkstack.NetworkStackClientBase
-import android.os.IBinder
-import com.android.server.net.integrationtests.TestNetworkStackService
-import org.mockito.Mockito.any
-import org.mockito.Mockito.spy
-import org.mockito.Mockito.timeout
-import org.mockito.Mockito.verify
-import kotlin.test.fail
-
-const val TEST_ACTION_SUFFIX = ".Test"
-
-class TestNetworkStackClient(private val context: Context) : NetworkStackClientBase() {
- // TODO: consider switching to TrackRecord for more expressive checks
- private val lastCallbacks = HashMap<Network, INetworkMonitorCallbacks>()
- private val moduleConnector = ConnectivityModuleConnector { _, action, _, _ ->
- val intent = Intent(action)
- val serviceName = TestNetworkStackService::class.qualifiedName
- ?: fail("TestNetworkStackService name not found")
- intent.component = ComponentName(context.packageName, serviceName)
- return@ConnectivityModuleConnector intent
- }.also { it.init(context) }
-
- fun start() {
- moduleConnector.startModuleService(
- INetworkStackConnector::class.qualifiedName + TEST_ACTION_SUFFIX,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) { connector ->
- onNetworkStackConnected(INetworkStackConnector.Stub.asInterface(connector))
- }
- }
-
- // base may be an instance of an inaccessible subclass, so non-spyable.
- // Use a known open class that delegates to the original instance for all methods except
- // asBinder. asBinder needs to use its own non-delegated implementation as otherwise it would
- // return a binder token to a class that is not spied on.
- open class NetworkMonitorCallbacksWrapper(private val base: INetworkMonitorCallbacks) :
- INetworkMonitorCallbacks.Stub(), INetworkMonitorCallbacks by base {
- // asBinder is implemented by both base class and delegate: specify explicitly
- override fun asBinder(): IBinder {
- return super.asBinder()
- }
- }
-
- override fun makeNetworkMonitor(network: Network, name: String?, cb: INetworkMonitorCallbacks) {
- val cbSpy = spy(NetworkMonitorCallbacksWrapper(cb))
- lastCallbacks[network] = cbSpy
- super.makeNetworkMonitor(network, name, cbSpy)
- }
-
- fun verifyNetworkMonitorCreated(network: Network, timeoutMs: Long) {
- val cb = lastCallbacks[network]
- ?: fail("NetworkMonitor for network $network not requested")
- verify(cb, timeout(timeoutMs)).onNetworkMonitorCreated(any())
- }
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
deleted file mode 100644
index e039ef0..0000000
--- a/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ /dev/null
@@ -1,257 +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.server.net.integrationtests
-
-import android.app.usage.NetworkStatsManager
-import android.content.ComponentName
-import android.content.Context
-import android.content.Context.BIND_AUTO_CREATE
-import android.content.Context.BIND_IMPORTANT
-import android.content.Intent
-import android.content.ServiceConnection
-import android.net.ConnectivityManager
-import android.net.IDnsResolver
-import android.net.INetd
-import android.net.LinkProperties
-import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL
-import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
-import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
-import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
-import android.net.NetworkRequest
-import android.net.TestNetworkStackClient
-import android.net.Uri
-import android.net.metrics.IpConnectivityLog
-import android.os.ConditionVariable
-import android.os.IBinder
-import android.os.SystemConfigManager
-import android.os.UserHandle
-import android.testing.TestableContext
-import android.util.Log
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.ConnectivityService
-import com.android.server.NetworkAgentWrapper
-import com.android.server.TestNetIdManager
-import com.android.server.connectivity.MockableSystemProperties
-import com.android.server.connectivity.ProxyTracker
-import com.android.testutils.TestableNetworkCallback
-import org.junit.After
-import org.junit.Before
-import org.junit.BeforeClass
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.AdditionalAnswers
-import org.mockito.ArgumentMatchers.anyString
-import org.mockito.Mock
-import org.mockito.Mockito.any
-import org.mockito.Mockito.anyInt
-import org.mockito.Mockito.doNothing
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.eq
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.spy
-import org.mockito.MockitoAnnotations
-import org.mockito.Spy
-import kotlin.test.assertEquals
-import kotlin.test.assertFalse
-import kotlin.test.assertNotNull
-import kotlin.test.assertTrue
-import kotlin.test.fail
-
-const val SERVICE_BIND_TIMEOUT_MS = 5_000L
-const val TEST_TIMEOUT_MS = 10_000L
-
-/**
- * Test that exercises an instrumented version of ConnectivityService against an instrumented
- * NetworkStack in a different test process.
- */
-@RunWith(AndroidJUnit4::class)
-class ConnectivityServiceIntegrationTest {
- // lateinit used here for mocks as they need to be reinitialized between each test and the test
- // should crash if they are used before being initialized.
- @Mock
- private lateinit var statsManager: NetworkStatsManager
- @Mock
- private lateinit var log: IpConnectivityLog
- @Mock
- private lateinit var netd: INetd
- @Mock
- private lateinit var dnsResolver: IDnsResolver
- @Mock
- private lateinit var systemConfigManager: SystemConfigManager
- @Spy
- private var context = TestableContext(realContext)
-
- // lateinit for these three classes under test, as they should be reset to a different instance
- // for every test but should always be initialized before use (or the test should crash).
- private lateinit var networkStackClient: TestNetworkStackClient
- private lateinit var service: ConnectivityService
- private lateinit var cm: ConnectivityManager
-
- companion object {
- // lateinit for this binder token, as it must be initialized before any test code is run
- // and use of it before init should crash the test.
- private lateinit var nsInstrumentation: INetworkStackInstrumentation
- private val bindingCondition = ConditionVariable(false)
-
- private val realContext get() = InstrumentationRegistry.getInstrumentation().context
- private val httpProbeUrl get() =
- realContext.getResources().getString(R.string.config_captive_portal_http_url)
- private val httpsProbeUrl get() =
- realContext.getResources().getString(R.string.config_captive_portal_https_url)
-
- private class InstrumentationServiceConnection : ServiceConnection {
- override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
- Log.i("TestNetworkStack", "Service connected")
- try {
- if (service == null) fail("Error binding to NetworkStack instrumentation")
- if (::nsInstrumentation.isInitialized) fail("Service already connected")
- nsInstrumentation = INetworkStackInstrumentation.Stub.asInterface(service)
- } finally {
- bindingCondition.open()
- }
- }
-
- override fun onServiceDisconnected(name: ComponentName?) = Unit
- }
-
- @BeforeClass
- @JvmStatic
- fun setUpClass() {
- val intent = Intent(realContext, NetworkStackInstrumentationService::class.java)
- intent.action = INetworkStackInstrumentation::class.qualifiedName
- assertTrue(realContext.bindService(intent, InstrumentationServiceConnection(),
- BIND_AUTO_CREATE or BIND_IMPORTANT),
- "Error binding to instrumentation service")
- assertTrue(bindingCondition.block(SERVICE_BIND_TIMEOUT_MS),
- "Timed out binding to instrumentation service " +
- "after $SERVICE_BIND_TIMEOUT_MS ms")
- }
- }
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- val asUserCtx = mock(Context::class.java, AdditionalAnswers.delegatesTo<Context>(context))
- doReturn(UserHandle.ALL).`when`(asUserCtx).user
- doReturn(asUserCtx).`when`(context).createContextAsUser(eq(UserHandle.ALL), anyInt())
- doNothing().`when`(context).sendStickyBroadcast(any(), any())
- doReturn(Context.SYSTEM_CONFIG_SERVICE).`when`(context)
- .getSystemServiceName(SystemConfigManager::class.java)
- doReturn(systemConfigManager).`when`(context)
- .getSystemService(Context.SYSTEM_CONFIG_SERVICE)
- doReturn(IntArray(0)).`when`(systemConfigManager).getSystemPermissionUids(anyString())
-
- networkStackClient = TestNetworkStackClient(realContext)
- networkStackClient.start()
-
- service = TestConnectivityService(makeDependencies())
- cm = ConnectivityManager(context, service)
- context.addMockSystemService(Context.CONNECTIVITY_SERVICE, cm)
- context.addMockSystemService(Context.NETWORK_STATS_SERVICE, statsManager)
-
- service.systemReadyInternal()
- }
-
- private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService(
- context, dnsResolver, log, netd, deps)
-
- private fun makeDependencies(): ConnectivityService.Dependencies {
- val deps = spy(ConnectivityService.Dependencies())
- doReturn(networkStackClient).`when`(deps).networkStack
- doReturn(mock(ProxyTracker::class.java)).`when`(deps).makeProxyTracker(any(), any())
- doReturn(mock(MockableSystemProperties::class.java)).`when`(deps).systemProperties
- doReturn(TestNetIdManager()).`when`(deps).makeNetIdManager()
- return deps
- }
-
- @After
- fun tearDown() {
- nsInstrumentation.clearAllState()
- }
-
- @Test
- fun testValidation() {
- val request = NetworkRequest.Builder()
- .clearCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .build()
- val testCallback = TestableNetworkCallback()
-
- cm.registerNetworkCallback(request, testCallback)
- nsInstrumentation.addHttpResponse(HttpResponse(httpProbeUrl, responseCode = 204))
- nsInstrumentation.addHttpResponse(HttpResponse(httpsProbeUrl, responseCode = 204))
-
- val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, LinkProperties(), null /* ncTemplate */,
- context)
- networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS)
-
- na.addCapability(NET_CAPABILITY_INTERNET)
- na.connect()
-
- testCallback.expectAvailableThenValidatedCallbacks(na.network, TEST_TIMEOUT_MS)
- assertEquals(2, nsInstrumentation.getRequestUrls().size)
- }
-
- @Test
- fun testCapportApi() {
- val request = NetworkRequest.Builder()
- .clearCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .build()
- val testCb = TestableNetworkCallback()
- val apiUrl = "https://capport.android.com"
-
- cm.registerNetworkCallback(request, testCb)
- nsInstrumentation.addHttpResponse(HttpResponse(
- apiUrl,
- """
- |{
- | "captive": true,
- | "user-portal-url": "https://login.capport.android.com",
- | "venue-info-url": "https://venueinfo.capport.android.com"
- |}
- """.trimMargin()))
-
- // Tests will fail if a non-mocked query is received: mock the HTTPS probe, but not the
- // HTTP probe as it should not be sent.
- // Even if the HTTPS probe succeeds, a portal should be detected as the API takes precedence
- // in that case.
- nsInstrumentation.addHttpResponse(HttpResponse(httpsProbeUrl, responseCode = 204))
-
- val lp = LinkProperties()
- lp.captivePortalApiUrl = Uri.parse(apiUrl)
- val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, lp, null /* ncTemplate */, context)
- networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS)
-
- na.addCapability(NET_CAPABILITY_INTERNET)
- na.connect()
-
- testCb.expectAvailableCallbacks(na.network, validated = false, tmt = TEST_TIMEOUT_MS)
-
- val capportData = testCb.expectLinkPropertiesThat(na, TEST_TIMEOUT_MS) {
- it.captivePortalData != null
- }.lp.captivePortalData
- assertNotNull(capportData)
- assertTrue(capportData.isCaptive)
- assertEquals(Uri.parse("https://login.capport.android.com"), capportData.userPortalUrl)
- assertEquals(Uri.parse("https://venueinfo.capport.android.com"), capportData.venueInfoUrl)
-
- val nc = testCb.expectCapabilitiesWith(NET_CAPABILITY_CAPTIVE_PORTAL, na, TEST_TIMEOUT_MS)
- assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED))
- }
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl
deleted file mode 100644
index 9a2bcfe..0000000
--- a/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/HttpResponse.aidl
+++ /dev/null
@@ -1,19 +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.server.net.integrationtests;
-
-parcelable HttpResponse;
\ No newline at end of file
diff --git a/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/HttpResponse.kt b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/HttpResponse.kt
deleted file mode 100644
index e206313..0000000
--- a/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/HttpResponse.kt
+++ /dev/null
@@ -1,49 +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.server.net.integrationtests
-
-import android.os.Parcel
-import android.os.Parcelable
-
-data class HttpResponse(
- val requestUrl: String,
- val responseCode: Int,
- val content: String = "",
- val redirectUrl: String? = null
-) : Parcelable {
- constructor(p: Parcel): this(p.readString(), p.readInt(), p.readString(), p.readString())
- constructor(requestUrl: String, contentBody: String): this(
- requestUrl,
- responseCode = 200,
- content = contentBody,
- redirectUrl = null)
-
- override fun writeToParcel(dest: Parcel, flags: Int) {
- with(dest) {
- writeString(requestUrl)
- writeInt(responseCode)
- writeString(content)
- writeString(redirectUrl)
- }
- }
-
- override fun describeContents() = 0
- companion object CREATOR : Parcelable.Creator<HttpResponse> {
- override fun createFromParcel(source: Parcel) = HttpResponse(source)
- override fun newArray(size: Int) = arrayOfNulls<HttpResponse?>(size)
- }
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/INetworkStackInstrumentation.aidl b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/INetworkStackInstrumentation.aidl
deleted file mode 100644
index efc58ad..0000000
--- a/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/INetworkStackInstrumentation.aidl
+++ /dev/null
@@ -1,25 +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.server.net.integrationtests;
-
-import com.android.server.net.integrationtests.HttpResponse;
-
-interface INetworkStackInstrumentation {
- void clearAllState();
- void addHttpResponse(in HttpResponse response);
- List<String> getRequestUrls();
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt
deleted file mode 100644
index e807952..0000000
--- a/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/NetworkStackInstrumentationService.kt
+++ /dev/null
@@ -1,84 +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.server.net.integrationtests
-
-import android.app.Service
-import android.content.Intent
-import java.net.URL
-import java.util.Collections
-import java.util.concurrent.ConcurrentHashMap
-import java.util.concurrent.ConcurrentLinkedQueue
-import kotlin.collections.ArrayList
-import kotlin.test.fail
-
-/**
- * An instrumentation interface for the NetworkStack that allows controlling behavior to
- * facilitate integration tests.
- */
-class NetworkStackInstrumentationService : Service() {
- override fun onBind(intent: Intent) = InstrumentationConnector.asBinder()
-
- object InstrumentationConnector : INetworkStackInstrumentation.Stub() {
- private val httpResponses = ConcurrentHashMap<String, ConcurrentLinkedQueue<HttpResponse>>()
- .run {
- withDefault { key -> getOrPut(key) { ConcurrentLinkedQueue() } }
- }
- private val httpRequestUrls = Collections.synchronizedList(ArrayList<String>())
-
- /**
- * Called when an HTTP request is being processed by NetworkMonitor. Returns the response
- * that should be simulated.
- */
- fun processRequest(url: URL): HttpResponse {
- val strUrl = url.toString()
- httpRequestUrls.add(strUrl)
- return httpResponses[strUrl]?.poll()
- ?: fail("No mocked response for request: $strUrl. " +
- "Mocked URL keys are: ${httpResponses.keys}")
- }
-
- /**
- * Clear all state of this connector. This is intended for use between two tests, so all
- * state should be reset as if the connector was just created.
- */
- override fun clearAllState() {
- httpResponses.clear()
- httpRequestUrls.clear()
- }
-
- /**
- * Add a response to a future HTTP request.
- *
- * <p>For any subsequent HTTP/HTTPS query, the first response with a matching URL will be
- * used to mock the query response.
- *
- * <p>All requests that are expected to be sent must have a mock response: if an unexpected
- * request is seen, the test will fail.
- */
- override fun addHttpResponse(response: HttpResponse) {
- httpResponses.getValue(response.requestUrl).add(response)
- }
-
- /**
- * Get the ordered list of request URLs that have been sent by NetworkMonitor, and were
- * answered based on mock responses.
- */
- override fun getRequestUrls(): List<String> {
- return ArrayList(httpRequestUrls)
- }
- }
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt b/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
deleted file mode 100644
index eff6658..0000000
--- a/packages/Connectivity/tests/integration/src/com/android/server/net/integrationtests/TestNetworkStackService.kt
+++ /dev/null
@@ -1,100 +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.server.net.integrationtests
-
-import android.app.Service
-import android.content.Context
-import android.content.Intent
-import android.net.INetworkMonitorCallbacks
-import android.net.Network
-import android.net.metrics.IpConnectivityLog
-import android.net.util.SharedLog
-import android.os.IBinder
-import com.android.networkstack.netlink.TcpSocketTracker
-import com.android.server.NetworkStackService
-import com.android.server.NetworkStackService.NetworkMonitorConnector
-import com.android.server.NetworkStackService.NetworkStackConnector
-import com.android.server.connectivity.NetworkMonitor
-import com.android.server.net.integrationtests.NetworkStackInstrumentationService.InstrumentationConnector
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.spy
-import java.io.ByteArrayInputStream
-import java.net.HttpURLConnection
-import java.net.URL
-import java.net.URLConnection
-import java.nio.charset.StandardCharsets
-
-private const val TEST_NETID = 42
-
-/**
- * Android service that can return an [android.net.INetworkStackConnector] which can be instrumented
- * through [NetworkStackInstrumentationService].
- * Useful in tests to create test instrumented NetworkStack components that can receive
- * instrumentation commands through [NetworkStackInstrumentationService].
- */
-class TestNetworkStackService : Service() {
- override fun onBind(intent: Intent): IBinder = TestNetworkStackConnector(makeTestContext())
-
- private fun makeTestContext() = spy(applicationContext).also {
- doReturn(mock(IBinder::class.java)).`when`(it).getSystemService(Context.NETD_SERVICE)
- }
-
- private class TestPermissionChecker : NetworkStackService.PermissionChecker() {
- override fun enforceNetworkStackCallingPermission() = Unit
- }
-
- private class NetworkMonitorDeps(private val privateDnsBypassNetwork: Network) :
- NetworkMonitor.Dependencies() {
- override fun getPrivateDnsBypassNetwork(network: Network?) = privateDnsBypassNetwork
- }
-
- private inner class TestNetworkStackConnector(context: Context) : NetworkStackConnector(
- context, TestPermissionChecker(), NetworkStackService.Dependencies()) {
-
- private val network = Network(TEST_NETID)
- private val privateDnsBypassNetwork = TestNetwork(TEST_NETID)
-
- private inner class TestNetwork(netId: Int) : Network(netId) {
- override fun openConnection(url: URL): URLConnection {
- val response = InstrumentationConnector.processRequest(url)
- val responseBytes = response.content.toByteArray(StandardCharsets.UTF_8)
-
- val connection = mock(HttpURLConnection::class.java)
- doReturn(response.responseCode).`when`(connection).responseCode
- doReturn(responseBytes.size.toLong()).`when`(connection).contentLengthLong
- doReturn(response.redirectUrl).`when`(connection).getHeaderField("location")
- doReturn(ByteArrayInputStream(responseBytes)).`when`(connection).inputStream
- return connection
- }
- }
-
- override fun makeNetworkMonitor(
- network: Network,
- name: String?,
- cb: INetworkMonitorCallbacks
- ) {
- val nm = NetworkMonitor(this@TestNetworkStackService, cb,
- this.network,
- mock(IpConnectivityLog::class.java), mock(SharedLog::class.java),
- mock(NetworkStackService.NetworkStackServiceManager::class.java),
- NetworkMonitorDeps(privateDnsBypassNetwork),
- mock(TcpSocketTracker::class.java))
- cb.onNetworkMonitorCreated(NetworkMonitorConnector(nm, TestPermissionChecker()))
- }
- }
-}
diff --git a/packages/Connectivity/tests/integration/util/com/android/server/ConnectivityServiceTestUtils.kt b/packages/Connectivity/tests/integration/util/com/android/server/ConnectivityServiceTestUtils.kt
deleted file mode 100644
index 165fd37..0000000
--- a/packages/Connectivity/tests/integration/util/com/android/server/ConnectivityServiceTestUtils.kt
+++ /dev/null
@@ -1,43 +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
- */
-
-@file:JvmName("ConnectivityServiceTestUtils")
-
-package com.android.server
-
-import android.net.ConnectivityManager.TYPE_BLUETOOTH
-import android.net.ConnectivityManager.TYPE_ETHERNET
-import android.net.ConnectivityManager.TYPE_MOBILE
-import android.net.ConnectivityManager.TYPE_NONE
-import android.net.ConnectivityManager.TYPE_TEST
-import android.net.ConnectivityManager.TYPE_VPN
-import android.net.ConnectivityManager.TYPE_WIFI
-import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH
-import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
-import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
-import android.net.NetworkCapabilities.TRANSPORT_TEST
-import android.net.NetworkCapabilities.TRANSPORT_VPN
-import android.net.NetworkCapabilities.TRANSPORT_WIFI
-
-fun transportToLegacyType(transport: Int) = when (transport) {
- TRANSPORT_BLUETOOTH -> TYPE_BLUETOOTH
- TRANSPORT_CELLULAR -> TYPE_MOBILE
- TRANSPORT_ETHERNET -> TYPE_ETHERNET
- TRANSPORT_TEST -> TYPE_TEST
- TRANSPORT_VPN -> TYPE_VPN
- TRANSPORT_WIFI -> TYPE_WIFI
- else -> TYPE_NONE
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/integration/util/com/android/server/NetworkAgentWrapper.java b/packages/Connectivity/tests/integration/util/com/android/server/NetworkAgentWrapper.java
deleted file mode 100644
index 17db179..0000000
--- a/packages/Connectivity/tests/integration/util/com/android/server/NetworkAgentWrapper.java
+++ /dev/null
@@ -1,388 +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.server;
-
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
-
-import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType;
-
-import static junit.framework.Assert.assertTrue;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkAgent;
-import android.net.NetworkAgentConfig;
-import android.net.NetworkCapabilities;
-import android.net.NetworkProvider;
-import android.net.NetworkScore;
-import android.net.NetworkSpecifier;
-import android.net.QosFilter;
-import android.net.SocketKeepalive;
-import android.os.ConditionVariable;
-import android.os.HandlerThread;
-import android.os.Message;
-import android.util.Log;
-import android.util.Range;
-
-import com.android.net.module.util.ArrayTrackRecord;
-import com.android.testutils.HandlerUtils;
-import com.android.testutils.TestableNetworkCallback;
-
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
- private final NetworkCapabilities mNetworkCapabilities;
- private final HandlerThread mHandlerThread;
- private final Context mContext;
- private final String mLogTag;
- private final NetworkAgentConfig mNetworkAgentConfig;
-
- private final ConditionVariable mDisconnected = new ConditionVariable();
- private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
- private final AtomicBoolean mConnected = new AtomicBoolean(false);
- private NetworkScore mScore;
- private NetworkAgent mNetworkAgent;
- private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED;
- private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE;
- // Controls how test network agent is going to wait before responding to keepalive
- // start/stop. Useful when simulate KeepaliveTracker is waiting for response from modem.
- private long mKeepaliveResponseDelay = 0L;
- private Integer mExpectedKeepaliveSlot = null;
- private final ArrayTrackRecord<CallbackType>.ReadHead mCallbackHistory =
- new ArrayTrackRecord<CallbackType>().newReadHead();
-
- public NetworkAgentWrapper(int transport, LinkProperties linkProperties,
- NetworkCapabilities ncTemplate, Context context) throws Exception {
- final int type = transportToLegacyType(transport);
- final String typeName = ConnectivityManager.getNetworkTypeName(type);
- mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
- mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- mNetworkCapabilities.addTransportType(transport);
- switch (transport) {
- case TRANSPORT_ETHERNET:
- mScore = new NetworkScore.Builder().setLegacyInt(70).build();
- break;
- case TRANSPORT_WIFI:
- mScore = new NetworkScore.Builder().setLegacyInt(60).build();
- break;
- case TRANSPORT_CELLULAR:
- mScore = new NetworkScore.Builder().setLegacyInt(50).build();
- break;
- case TRANSPORT_WIFI_AWARE:
- mScore = new NetworkScore.Builder().setLegacyInt(20).build();
- break;
- case TRANSPORT_VPN:
- mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
- // VPNs deduce the SUSPENDED capability from their underlying networks and there
- // is no public API to let VPN services set it.
- mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
- mScore = new NetworkScore.Builder().setLegacyInt(101).build();
- break;
- default:
- throw new UnsupportedOperationException("unimplemented network type");
- }
- mContext = context;
- mLogTag = "Mock-" + typeName;
- mHandlerThread = new HandlerThread(mLogTag);
- mHandlerThread.start();
-
- // extraInfo is set to "" by default in NetworkAgentConfig.
- final String extraInfo = (transport == TRANSPORT_CELLULAR) ? "internet.apn" : "";
- mNetworkAgentConfig = new NetworkAgentConfig.Builder()
- .setLegacyType(type)
- .setLegacyTypeName(typeName)
- .setLegacyExtraInfo(extraInfo)
- .build();
- mNetworkAgent = makeNetworkAgent(linkProperties, mNetworkAgentConfig);
- }
-
- protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties,
- final NetworkAgentConfig nac) throws Exception {
- return new InstrumentedNetworkAgent(this, linkProperties, nac);
- }
-
- public static class InstrumentedNetworkAgent extends NetworkAgent {
- private final NetworkAgentWrapper mWrapper;
- private static final String PROVIDER_NAME = "InstrumentedNetworkAgentProvider";
-
- public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp,
- NetworkAgentConfig nac) {
- super(wrapper.mContext, wrapper.mHandlerThread.getLooper(), wrapper.mLogTag,
- wrapper.mNetworkCapabilities, lp, wrapper.mScore, nac,
- new NetworkProvider(wrapper.mContext, wrapper.mHandlerThread.getLooper(),
- PROVIDER_NAME));
- mWrapper = wrapper;
- register();
- }
-
- @Override
- public void unwanted() {
- mWrapper.mDisconnected.open();
- }
-
- @Override
- public void startSocketKeepalive(Message msg) {
- int slot = msg.arg1;
- if (mWrapper.mExpectedKeepaliveSlot != null) {
- assertEquals((int) mWrapper.mExpectedKeepaliveSlot, slot);
- }
- mWrapper.mHandlerThread.getThreadHandler().postDelayed(
- () -> onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError),
- mWrapper.mKeepaliveResponseDelay);
- }
-
- @Override
- public void stopSocketKeepalive(Message msg) {
- final int slot = msg.arg1;
- mWrapper.mHandlerThread.getThreadHandler().postDelayed(
- () -> onSocketKeepaliveEvent(slot, mWrapper.mStopKeepaliveError),
- mWrapper.mKeepaliveResponseDelay);
- }
-
- @Override
- public void onQosCallbackRegistered(final int qosCallbackId,
- final @NonNull QosFilter filter) {
- Log.i(mWrapper.mLogTag, "onQosCallbackRegistered");
- mWrapper.mCallbackHistory.add(
- new CallbackType.OnQosCallbackRegister(qosCallbackId, filter));
- }
-
- @Override
- public void onQosCallbackUnregistered(final int qosCallbackId) {
- Log.i(mWrapper.mLogTag, "onQosCallbackUnregistered");
- mWrapper.mCallbackHistory.add(new CallbackType.OnQosCallbackUnregister(qosCallbackId));
- }
-
- @Override
- protected void preventAutomaticReconnect() {
- mWrapper.mPreventReconnectReceived.open();
- }
-
- @Override
- protected void addKeepalivePacketFilter(Message msg) {
- Log.i(mWrapper.mLogTag, "Add keepalive packet filter.");
- }
-
- @Override
- protected void removeKeepalivePacketFilter(Message msg) {
- Log.i(mWrapper.mLogTag, "Remove keepalive packet filter.");
- }
- }
-
- public void setScore(@NonNull final NetworkScore score) {
- mScore = score;
- mNetworkAgent.sendNetworkScore(score);
- }
-
- public void adjustScore(int change) {
- final int newLegacyScore = mScore.getLegacyInt() + change;
- final NetworkScore.Builder builder = new NetworkScore.Builder()
- .setLegacyInt(newLegacyScore);
- if (mNetworkCapabilities.hasTransport(TRANSPORT_WIFI) && newLegacyScore < 50) {
- builder.setExiting(true);
- }
- mScore = builder.build();
- mNetworkAgent.sendNetworkScore(mScore);
- }
-
- public NetworkScore getScore() {
- return mScore;
- }
-
- public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) {
- mNetworkAgent.explicitlySelected(explicitlySelected, acceptUnvalidated);
- }
-
- public void addCapability(int capability) {
- mNetworkCapabilities.addCapability(capability);
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
-
- public void removeCapability(int capability) {
- mNetworkCapabilities.removeCapability(capability);
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
-
- public void setUids(Set<Range<Integer>> uids) {
- mNetworkCapabilities.setUids(uids);
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
-
- public void setSignalStrength(int signalStrength) {
- mNetworkCapabilities.setSignalStrength(signalStrength);
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
-
- public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
- mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
-
- public void setNetworkCapabilities(NetworkCapabilities nc, boolean sendToConnectivityService) {
- mNetworkCapabilities.set(nc);
- if (sendToConnectivityService) {
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- }
- }
-
- public void connect() {
- if (!mConnected.compareAndSet(false /* expect */, true /* update */)) {
- // compareAndSet returns false when the value couldn't be updated because it did not
- // match the expected value.
- fail("Test NetworkAgents can only be connected once");
- }
- mNetworkAgent.markConnected();
- }
-
- public void suspend() {
- removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
- }
-
- public void resume() {
- addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- }
-
- public void disconnect() {
- mNetworkAgent.unregister();
- }
-
- @Override
- public Network getNetwork() {
- return mNetworkAgent.getNetwork();
- }
-
- public void expectPreventReconnectReceived(long timeoutMs) {
- assertTrue(mPreventReconnectReceived.block(timeoutMs));
- }
-
- public void expectDisconnected(long timeoutMs) {
- assertTrue(mDisconnected.block(timeoutMs));
- }
-
- public void sendLinkProperties(LinkProperties lp) {
- mNetworkAgent.sendLinkProperties(lp);
- }
-
- public void setStartKeepaliveEvent(int reason) {
- mStartKeepaliveError = reason;
- }
-
- public void setStopKeepaliveEvent(int reason) {
- mStopKeepaliveError = reason;
- }
-
- public void setKeepaliveResponseDelay(long delay) {
- mKeepaliveResponseDelay = delay;
- }
-
- public void setExpectedKeepaliveSlot(Integer slot) {
- mExpectedKeepaliveSlot = slot;
- }
-
- public NetworkAgent getNetworkAgent() {
- return mNetworkAgent;
- }
-
- public NetworkCapabilities getNetworkCapabilities() {
- return mNetworkCapabilities;
- }
-
- public int getLegacyType() {
- return mNetworkAgentConfig.getLegacyType();
- }
-
- public String getExtraInfo() {
- return mNetworkAgentConfig.getLegacyExtraInfo();
- }
-
- public @NonNull ArrayTrackRecord<CallbackType>.ReadHead getCallbackHistory() {
- return mCallbackHistory;
- }
-
- public void waitForIdle(long timeoutMs) {
- HandlerUtils.waitForIdle(mHandlerThread, timeoutMs);
- }
-
- abstract static class CallbackType {
- final int mQosCallbackId;
-
- protected CallbackType(final int qosCallbackId) {
- mQosCallbackId = qosCallbackId;
- }
-
- static class OnQosCallbackRegister extends CallbackType {
- final QosFilter mFilter;
- OnQosCallbackRegister(final int qosCallbackId, final QosFilter filter) {
- super(qosCallbackId);
- mFilter = filter;
- }
-
- @Override
- public boolean equals(final Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- final OnQosCallbackRegister that = (OnQosCallbackRegister) o;
- return mQosCallbackId == that.mQosCallbackId
- && Objects.equals(mFilter, that.mFilter);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mQosCallbackId, mFilter);
- }
- }
-
- static class OnQosCallbackUnregister extends CallbackType {
- OnQosCallbackUnregister(final int qosCallbackId) {
- super(qosCallbackId);
- }
-
- @Override
- public boolean equals(final Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- final OnQosCallbackUnregister that = (OnQosCallbackUnregister) o;
- return mQosCallbackId == that.mQosCallbackId;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mQosCallbackId);
- }
- }
- }
-
- public boolean isBypassableVpn() {
- return mNetworkAgentConfig.isBypassableVpn();
- }
-}
diff --git a/packages/Connectivity/tests/integration/util/com/android/server/TestNetIdManager.kt b/packages/Connectivity/tests/integration/util/com/android/server/TestNetIdManager.kt
deleted file mode 100644
index 938a694..0000000
--- a/packages/Connectivity/tests/integration/util/com/android/server/TestNetIdManager.kt
+++ /dev/null
@@ -1,39 +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.server
-
-import java.util.concurrent.atomic.AtomicInteger
-
-/**
- * A [NetIdManager] that generates ID starting from [NetIdManager.MAX_NET_ID] and decreasing, rather
- * than starting from [NetIdManager.MIN_NET_ID] and increasing.
- *
- * Useful for testing ConnectivityService, to minimize the risk of test ConnectivityService netIDs
- * overlapping with netIDs used by the real ConnectivityService on the device.
- *
- * IDs may still overlap if many networks have been used on the device (so the "real" netIDs
- * are close to MAX_NET_ID), but this is typically not the case when running unit tests. Also, there
- * is no way to fully solve the overlap issue without altering ID allocation in non-test code, as
- * the real ConnectivityService could start using netIds that have been used by the test in the
- * past.
- */
-class TestNetIdManager : NetIdManager() {
- private val nextId = AtomicInteger(MAX_NET_ID)
- override fun reserveNetId() = nextId.decrementAndGet()
- override fun releaseNetId(id: Int) = Unit
- fun peekNextNetId() = nextId.get() - 1
-}
diff --git a/packages/Connectivity/tests/smoketest/Android.bp b/packages/Connectivity/tests/smoketest/Android.bp
deleted file mode 100644
index 1535f3d..0000000
--- a/packages/Connectivity/tests/smoketest/Android.bp
+++ /dev/null
@@ -1,31 +0,0 @@
-// This test exists only because the jni_libs list for these tests is difficult to
-// maintain: the test itself only depends on libnetworkstatsfactorytestjni, but the test
-// fails to load that library unless *all* the dependencies of that library are explicitly
-// listed in jni_libs. This means that whenever any of the dependencies changes the test
-// starts failing and breaking presubmits in frameworks/base. We cannot easily put
-// FrameworksNetTests into global presubmit because they are at times flaky, but this
-// test is effectively empty beyond validating that the libraries load correctly, and
-// thus should be stable enough to put in global presubmit.
-//
-// TODO: remove this hack when there is a better solution for jni_libs that includes
-// dependent libraries.
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_test {
- name: "FrameworksNetSmokeTests",
- defaults: ["FrameworksNetTests-jni-defaults"],
- srcs: ["java/SmokeTest.java"],
- test_suites: ["device-tests"],
- static_libs: [
- "androidx.test.rules",
- "mockito-target-minus-junit4",
- "services.core",
- ],
-}
diff --git a/packages/Connectivity/tests/smoketest/AndroidManifest.xml b/packages/Connectivity/tests/smoketest/AndroidManifest.xml
deleted file mode 100644
index f1b9feb..0000000
--- a/packages/Connectivity/tests/smoketest/AndroidManifest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.frameworks.tests.net.smoketest">
- <application>
- <uses-library android:name="android.test.runner" />
- </application>
-
- <instrumentation
- android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.frameworks.tests.net.smoketest"
- android:label="Frameworks Networking Smoke Tests" />
-</manifest>
diff --git a/packages/Connectivity/tests/smoketest/AndroidTest.xml b/packages/Connectivity/tests/smoketest/AndroidTest.xml
deleted file mode 100644
index ac366e4..0000000
--- a/packages/Connectivity/tests/smoketest/AndroidTest.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<configuration description="Runs Frameworks Networking Smoke Tests.">
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
- <option name="test-file-name" value="FrameworksNetSmokeTests.apk" />
- </target_preparer>
-
- <option name="test-suite-tag" value="apct" />
- <option name="test-tag" value="FrameworksNetSmokeTests" />
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="com.android.frameworks.tests.net.smoketest" />
- <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
- <option name="hidden-api-checks" value="false"/>
- </test>
-</configuration>
diff --git a/packages/Connectivity/tests/smoketest/java/SmokeTest.java b/packages/Connectivity/tests/smoketest/java/SmokeTest.java
deleted file mode 100644
index 7d6655f..0000000
--- a/packages/Connectivity/tests/smoketest/java/SmokeTest.java
+++ /dev/null
@@ -1,33 +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.server.net;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class SmokeTest {
-
- @Test
- public void testLoadJni() {
- System.loadLibrary("networkstatsfactorytestjni");
- assertEquals(0, 0x00);
- }
-}
diff --git a/packages/Connectivity/tests/unit/Android.bp b/packages/Connectivity/tests/unit/Android.bp
deleted file mode 100644
index 6f503ac..0000000
--- a/packages/Connectivity/tests/unit/Android.bp
+++ /dev/null
@@ -1,89 +0,0 @@
-//########################################################################
-// Build FrameworksNetTests package
-//########################################################################
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-java_defaults {
- name: "FrameworksNetTests-jni-defaults",
- jni_libs: [
- "ld-android",
- "libbacktrace",
- "libbase",
- "libbinder",
- "libbpf",
- "libbpf_android",
- "libc++",
- "libcgrouprc",
- "libcrypto",
- "libcutils",
- "libdl_android",
- "libhidl-gen-utils",
- "libhidlbase",
- "libjsoncpp",
- "liblog",
- "liblzma",
- "libnativehelper",
- "libnetdbpf",
- "libnetdutils",
- "libnetworkstatsfactorytestjni",
- "libpackagelistparser",
- "libpcre2",
- "libprocessgroup",
- "libselinux",
- "libtinyxml2",
- "libui",
- "libunwindstack",
- "libutils",
- "libutilscallstack",
- "libvndksupport",
- "libziparchive",
- "libz",
- "netd_aidl_interface-V5-cpp",
- ],
-}
-
-android_test {
- name: "FrameworksNetTests",
- defaults: [
- "framework-connectivity-test-defaults",
- "FrameworksNetTests-jni-defaults",
- ],
- srcs: [
- "java/**/*.java",
- "java/**/*.kt",
- ],
- test_suites: ["device-tests"],
- certificate: "platform",
- jarjar_rules: "jarjar-rules.txt",
- static_libs: [
- "androidx.test.rules",
- "bouncycastle-repackaged-unbundled",
- "FrameworksNetCommonTests",
- "frameworks-base-testutils",
- "frameworks-net-integration-testutils",
- "framework-protos",
- "mockito-target-minus-junit4",
- "net-tests-utils",
- "platform-test-annotations",
- "service-connectivity-pre-jarjar",
- "services.core",
- "services.net",
- ],
- libs: [
- "android.net.ipsec.ike.stubs.module_lib",
- "android.test.runner",
- "android.test.base",
- "android.test.mock",
- "ServiceConnectivityResources",
- ],
- jni_libs: [
- "libservice-connectivity",
- ],
-}
diff --git a/packages/Connectivity/tests/unit/AndroidManifest.xml b/packages/Connectivity/tests/unit/AndroidManifest.xml
deleted file mode 100644
index 4c60ccf..0000000
--- a/packages/Connectivity/tests/unit/AndroidManifest.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.frameworks.tests.net">
-
- <uses-permission android:name="android.permission.READ_LOGS" />
- <uses-permission android:name="android.permission.WRITE_SETTINGS" />
- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
- <uses-permission android:name="android.permission.READ_PHONE_STATE" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.BROADCAST_STICKY" />
- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
- <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
- <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
- <uses-permission android:name="android.permission.REAL_GET_TASKS" />
- <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
- <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
- <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
- <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.MANAGE_USERS" />
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
- <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
- <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
- <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
- <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
- <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS" />
- <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
- <uses-permission android:name="android.permission.NETWORK_STACK" />
- <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
- <uses-permission android:name="android.permission.NETWORK_FACTORY" />
- <uses-permission android:name="android.permission.NETWORK_STATS_PROVIDER" />
- <uses-permission android:name="android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE" />
-
- <application>
- <uses-library android:name="android.test.runner" />
- <uses-library android:name="android.net.ipsec.ike" />
- </application>
-
- <instrumentation
- android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.frameworks.tests.net"
- android:label="Frameworks Networking Tests" />
-</manifest>
diff --git a/packages/Connectivity/tests/unit/AndroidTest.xml b/packages/Connectivity/tests/unit/AndroidTest.xml
deleted file mode 100644
index 939ae49..0000000
--- a/packages/Connectivity/tests/unit/AndroidTest.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-<configuration description="Runs Frameworks Networking Tests.">
- <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
- <option name="test-file-name" value="FrameworksNetTests.apk" />
- </target_preparer>
-
- <option name="test-suite-tag" value="apct" />
- <option name="test-tag" value="FrameworksNetTests" />
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="com.android.frameworks.tests.net" />
- <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
- <option name="hidden-api-checks" value="false"/>
- </test>
-</configuration>
diff --git a/packages/Connectivity/tests/unit/jarjar-rules.txt b/packages/Connectivity/tests/unit/jarjar-rules.txt
deleted file mode 100644
index ca88672..0000000
--- a/packages/Connectivity/tests/unit/jarjar-rules.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-# Module library in frameworks/libs/net
-rule com.android.net.module.util.** android.net.frameworktests.util.@1
diff --git a/packages/Connectivity/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java b/packages/Connectivity/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
deleted file mode 100644
index 899295a..0000000
--- a/packages/Connectivity/tests/unit/java/android/app/usage/NetworkStatsManagerTest.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2018 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.app.usage;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.net.ConnectivityManager;
-import android.net.INetworkStatsService;
-import android.net.INetworkStatsSession;
-import android.net.NetworkStats.Entry;
-import android.net.NetworkStatsHistory;
-import android.net.NetworkTemplate;
-import android.os.RemoteException;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkStatsManagerTest {
-
- private @Mock INetworkStatsService mService;
- private @Mock INetworkStatsSession mStatsSession;
-
- private NetworkStatsManager mManager;
-
- // TODO: change to NetworkTemplate.MATCH_MOBILE once internal constant rename is merged to aosp.
- private static final int MATCH_MOBILE_ALL = 1;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mManager = new NetworkStatsManager(InstrumentationRegistry.getContext(), mService);
- }
-
- @Test
- public void testQueryDetails() throws RemoteException {
- final String subscriberId = "subid";
- final long startTime = 1;
- final long endTime = 100;
- final int uid1 = 10001;
- final int uid2 = 10002;
- final int uid3 = 10003;
-
- Entry uid1Entry1 = new Entry("if1", uid1,
- android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
- 100, 10, 200, 20, 0);
-
- Entry uid1Entry2 = new Entry(
- "if2", uid1,
- android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
- 100, 10, 200, 20, 0);
-
- Entry uid2Entry1 = new Entry("if1", uid2,
- android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
- 150, 10, 250, 20, 0);
-
- Entry uid2Entry2 = new Entry(
- "if2", uid2,
- android.net.NetworkStats.SET_DEFAULT, android.net.NetworkStats.TAG_NONE,
- 150, 10, 250, 20, 0);
-
- NetworkStatsHistory history1 = new NetworkStatsHistory(10, 2);
- history1.recordData(10, 20, uid1Entry1);
- history1.recordData(20, 30, uid1Entry2);
-
- NetworkStatsHistory history2 = new NetworkStatsHistory(10, 2);
- history1.recordData(30, 40, uid2Entry1);
- history1.recordData(35, 45, uid2Entry2);
-
-
- when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession);
- when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2, uid3 });
-
- when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
- eq(uid1), eq(android.net.NetworkStats.SET_ALL),
- eq(android.net.NetworkStats.TAG_NONE),
- eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime)))
- .then((InvocationOnMock inv) -> {
- NetworkTemplate template = inv.getArgument(0);
- assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
- assertEquals(subscriberId, template.getSubscriberId());
- return history1;
- });
-
- when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
- eq(uid2), eq(android.net.NetworkStats.SET_ALL),
- eq(android.net.NetworkStats.TAG_NONE),
- eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime)))
- .then((InvocationOnMock inv) -> {
- NetworkTemplate template = inv.getArgument(0);
- assertEquals(MATCH_MOBILE_ALL, template.getMatchRule());
- assertEquals(subscriberId, template.getSubscriberId());
- return history2;
- });
-
-
- NetworkStats stats = mManager.queryDetails(
- ConnectivityManager.TYPE_MOBILE, subscriberId, startTime, endTime);
-
- NetworkStats.Bucket bucket = new NetworkStats.Bucket();
-
- // First 2 buckets exactly match entry timings
- assertTrue(stats.getNextBucket(bucket));
- assertEquals(10, bucket.getStartTimeStamp());
- assertEquals(20, bucket.getEndTimeStamp());
- assertBucketMatches(uid1Entry1, bucket);
-
- assertTrue(stats.getNextBucket(bucket));
- assertEquals(20, bucket.getStartTimeStamp());
- assertEquals(30, bucket.getEndTimeStamp());
- assertBucketMatches(uid1Entry2, bucket);
-
- // 30 -> 40: contains uid2Entry1 and half of uid2Entry2
- assertTrue(stats.getNextBucket(bucket));
- assertEquals(30, bucket.getStartTimeStamp());
- assertEquals(40, bucket.getEndTimeStamp());
- assertEquals(225, bucket.getRxBytes());
- assertEquals(15, bucket.getRxPackets());
- assertEquals(375, bucket.getTxBytes());
- assertEquals(30, bucket.getTxPackets());
-
- // 40 -> 50: contains half of uid2Entry2
- assertTrue(stats.getNextBucket(bucket));
- assertEquals(40, bucket.getStartTimeStamp());
- assertEquals(50, bucket.getEndTimeStamp());
- assertEquals(75, bucket.getRxBytes());
- assertEquals(5, bucket.getRxPackets());
- assertEquals(125, bucket.getTxBytes());
- assertEquals(10, bucket.getTxPackets());
-
- assertFalse(stats.hasNextBucket());
- }
-
- @Test
- public void testQueryDetails_NoSubscriberId() throws RemoteException {
- final long startTime = 1;
- final long endTime = 100;
- final int uid1 = 10001;
- final int uid2 = 10002;
-
- when(mService.openSessionForUsageStats(anyInt(), anyString())).thenReturn(mStatsSession);
- when(mStatsSession.getRelevantUids()).thenReturn(new int[] { uid1, uid2 });
-
- NetworkStats stats = mManager.queryDetails(
- ConnectivityManager.TYPE_MOBILE, null, startTime, endTime);
-
- when(mStatsSession.getHistoryIntervalForUid(any(NetworkTemplate.class),
- anyInt(), anyInt(), anyInt(), anyInt(), anyLong(), anyLong()))
- .thenReturn(new NetworkStatsHistory(10, 0));
-
- verify(mStatsSession, times(1)).getHistoryIntervalForUid(
- argThat((NetworkTemplate t) ->
- // No subscriberId: MATCH_MOBILE_WILDCARD template
- t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD),
- eq(uid1), eq(android.net.NetworkStats.SET_ALL),
- eq(android.net.NetworkStats.TAG_NONE),
- eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
-
- verify(mStatsSession, times(1)).getHistoryIntervalForUid(
- argThat((NetworkTemplate t) ->
- // No subscriberId: MATCH_MOBILE_WILDCARD template
- t.getMatchRule() == NetworkTemplate.MATCH_MOBILE_WILDCARD),
- eq(uid2), eq(android.net.NetworkStats.SET_ALL),
- eq(android.net.NetworkStats.TAG_NONE),
- eq(NetworkStatsHistory.FIELD_ALL), eq(startTime), eq(endTime));
-
- assertFalse(stats.hasNextBucket());
- }
-
- private void assertBucketMatches(Entry expected, NetworkStats.Bucket actual) {
- assertEquals(expected.uid, actual.getUid());
- assertEquals(expected.rxBytes, actual.getRxBytes());
- assertEquals(expected.rxPackets, actual.getRxPackets());
- assertEquals(expected.txBytes, actual.getTxBytes());
- assertEquals(expected.txPackets, actual.getTxPackets());
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/ConnectivityDiagnosticsManagerTest.java b/packages/Connectivity/tests/unit/java/android/net/ConnectivityDiagnosticsManagerTest.java
deleted file mode 100644
index 06e9405..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/ConnectivityDiagnosticsManagerTest.java
+++ /dev/null
@@ -1,384 +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.net;
-
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsBinder;
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback;
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
-import static android.net.ConnectivityDiagnosticsManager.DataStallReport;
-
-import static com.android.testutils.ParcelUtils.assertParcelSane;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import android.content.Context;
-import android.os.PersistableBundle;
-
-import androidx.test.InstrumentationRegistry;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.Mock;
-
-import java.util.concurrent.Executor;
-
-@RunWith(JUnit4.class)
-public class ConnectivityDiagnosticsManagerTest {
- private static final int NET_ID = 1;
- private static final int DETECTION_METHOD = 2;
- private static final long TIMESTAMP = 10L;
- private static final String INTERFACE_NAME = "interface";
- private static final String BUNDLE_KEY = "key";
- private static final String BUNDLE_VALUE = "value";
-
- private static final Executor INLINE_EXECUTOR = x -> x.run();
-
- @Mock private IConnectivityManager mService;
- @Mock private ConnectivityDiagnosticsCallback mCb;
-
- private Context mContext;
- private ConnectivityDiagnosticsBinder mBinder;
- private ConnectivityDiagnosticsManager mManager;
-
- private String mPackageName;
-
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getContext();
-
- mService = mock(IConnectivityManager.class);
- mCb = mock(ConnectivityDiagnosticsCallback.class);
-
- mBinder = new ConnectivityDiagnosticsBinder(mCb, INLINE_EXECUTOR);
- mManager = new ConnectivityDiagnosticsManager(mContext, mService);
-
- mPackageName = mContext.getOpPackageName();
- }
-
- @After
- public void tearDown() {
- // clear ConnectivityDiagnosticsManager callbacks map
- ConnectivityDiagnosticsManager.sCallbacks.clear();
- }
-
- private ConnectivityReport createSampleConnectivityReport() {
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setInterfaceName(INTERFACE_NAME);
-
- final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
- networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
-
- final PersistableBundle bundle = new PersistableBundle();
- bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
-
- return new ConnectivityReport(
- new Network(NET_ID), TIMESTAMP, linkProperties, networkCapabilities, bundle);
- }
-
- private ConnectivityReport createDefaultConnectivityReport() {
- return new ConnectivityReport(
- new Network(0),
- 0L,
- new LinkProperties(),
- new NetworkCapabilities(),
- PersistableBundle.EMPTY);
- }
-
- @Test
- public void testPersistableBundleEquals() {
- assertFalse(
- ConnectivityDiagnosticsManager.persistableBundleEquals(
- null, PersistableBundle.EMPTY));
- assertFalse(
- ConnectivityDiagnosticsManager.persistableBundleEquals(
- PersistableBundle.EMPTY, null));
- assertTrue(
- ConnectivityDiagnosticsManager.persistableBundleEquals(
- PersistableBundle.EMPTY, PersistableBundle.EMPTY));
-
- final PersistableBundle a = new PersistableBundle();
- a.putString(BUNDLE_KEY, BUNDLE_VALUE);
-
- final PersistableBundle b = new PersistableBundle();
- b.putString(BUNDLE_KEY, BUNDLE_VALUE);
-
- final PersistableBundle c = new PersistableBundle();
- c.putString(BUNDLE_KEY, null);
-
- assertFalse(
- ConnectivityDiagnosticsManager.persistableBundleEquals(PersistableBundle.EMPTY, a));
- assertFalse(
- ConnectivityDiagnosticsManager.persistableBundleEquals(a, PersistableBundle.EMPTY));
-
- assertTrue(ConnectivityDiagnosticsManager.persistableBundleEquals(a, b));
- assertTrue(ConnectivityDiagnosticsManager.persistableBundleEquals(b, a));
-
- assertFalse(ConnectivityDiagnosticsManager.persistableBundleEquals(a, c));
- assertFalse(ConnectivityDiagnosticsManager.persistableBundleEquals(c, a));
- }
-
- @Test
- public void testConnectivityReportEquals() {
- final ConnectivityReport defaultReport = createDefaultConnectivityReport();
- final ConnectivityReport sampleReport = createSampleConnectivityReport();
- assertEquals(sampleReport, createSampleConnectivityReport());
- assertEquals(defaultReport, createDefaultConnectivityReport());
-
- final LinkProperties linkProperties = sampleReport.getLinkProperties();
- final NetworkCapabilities networkCapabilities = sampleReport.getNetworkCapabilities();
- final PersistableBundle bundle = sampleReport.getAdditionalInfo();
-
- assertNotEquals(
- createDefaultConnectivityReport(),
- new ConnectivityReport(
- new Network(NET_ID),
- 0L,
- new LinkProperties(),
- new NetworkCapabilities(),
- PersistableBundle.EMPTY));
- assertNotEquals(
- createDefaultConnectivityReport(),
- new ConnectivityReport(
- new Network(0),
- TIMESTAMP,
- new LinkProperties(),
- new NetworkCapabilities(),
- PersistableBundle.EMPTY));
- assertNotEquals(
- createDefaultConnectivityReport(),
- new ConnectivityReport(
- new Network(0),
- 0L,
- linkProperties,
- new NetworkCapabilities(),
- PersistableBundle.EMPTY));
- assertNotEquals(
- createDefaultConnectivityReport(),
- new ConnectivityReport(
- new Network(0),
- TIMESTAMP,
- new LinkProperties(),
- networkCapabilities,
- PersistableBundle.EMPTY));
- assertNotEquals(
- createDefaultConnectivityReport(),
- new ConnectivityReport(
- new Network(0),
- TIMESTAMP,
- new LinkProperties(),
- new NetworkCapabilities(),
- bundle));
- }
-
- @Test
- public void testConnectivityReportParcelUnparcel() {
- assertParcelSane(createSampleConnectivityReport(), 5);
- }
-
- private DataStallReport createSampleDataStallReport() {
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setInterfaceName(INTERFACE_NAME);
-
- final PersistableBundle bundle = new PersistableBundle();
- bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
-
- final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
- networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
-
- return new DataStallReport(
- new Network(NET_ID),
- TIMESTAMP,
- DETECTION_METHOD,
- linkProperties,
- networkCapabilities,
- bundle);
- }
-
- private DataStallReport createDefaultDataStallReport() {
- return new DataStallReport(
- new Network(0),
- 0L,
- 0,
- new LinkProperties(),
- new NetworkCapabilities(),
- PersistableBundle.EMPTY);
- }
-
- @Test
- public void testDataStallReportEquals() {
- final DataStallReport defaultReport = createDefaultDataStallReport();
- final DataStallReport sampleReport = createSampleDataStallReport();
- assertEquals(sampleReport, createSampleDataStallReport());
- assertEquals(defaultReport, createDefaultDataStallReport());
-
- final LinkProperties linkProperties = sampleReport.getLinkProperties();
- final NetworkCapabilities networkCapabilities = sampleReport.getNetworkCapabilities();
- final PersistableBundle bundle = sampleReport.getStallDetails();
-
- assertNotEquals(
- defaultReport,
- new DataStallReport(
- new Network(NET_ID),
- 0L,
- 0,
- new LinkProperties(),
- new NetworkCapabilities(),
- PersistableBundle.EMPTY));
- assertNotEquals(
- defaultReport,
- new DataStallReport(
- new Network(0),
- TIMESTAMP,
- 0,
- new LinkProperties(),
- new NetworkCapabilities(),
- PersistableBundle.EMPTY));
- assertNotEquals(
- defaultReport,
- new DataStallReport(
- new Network(0),
- 0L,
- DETECTION_METHOD,
- new LinkProperties(),
- new NetworkCapabilities(),
- PersistableBundle.EMPTY));
- assertNotEquals(
- defaultReport,
- new DataStallReport(
- new Network(0),
- 0L,
- 0,
- linkProperties,
- new NetworkCapabilities(),
- PersistableBundle.EMPTY));
- assertNotEquals(
- defaultReport,
- new DataStallReport(
- new Network(0),
- 0L,
- 0,
- new LinkProperties(),
- networkCapabilities,
- PersistableBundle.EMPTY));
- assertNotEquals(
- defaultReport,
- new DataStallReport(
- new Network(0),
- 0L,
- 0,
- new LinkProperties(),
- new NetworkCapabilities(),
- bundle));
- }
-
- @Test
- public void testDataStallReportParcelUnparcel() {
- assertParcelSane(createSampleDataStallReport(), 6);
- }
-
- @Test
- public void testConnectivityDiagnosticsCallbackOnConnectivityReportAvailable() {
- mBinder.onConnectivityReportAvailable(createSampleConnectivityReport());
-
- // The callback will be invoked synchronously by inline executor. Immediately check the
- // latch without waiting.
- verify(mCb).onConnectivityReportAvailable(eq(createSampleConnectivityReport()));
- }
-
- @Test
- public void testConnectivityDiagnosticsCallbackOnDataStallSuspected() {
- mBinder.onDataStallSuspected(createSampleDataStallReport());
-
- // The callback will be invoked synchronously by inline executor. Immediately check the
- // latch without waiting.
- verify(mCb).onDataStallSuspected(eq(createSampleDataStallReport()));
- }
-
- @Test
- public void testConnectivityDiagnosticsCallbackOnNetworkConnectivityReported() {
- final Network n = new Network(NET_ID);
- final boolean connectivity = true;
-
- mBinder.onNetworkConnectivityReported(n, connectivity);
-
- // The callback will be invoked synchronously by inline executor. Immediately check the
- // latch without waiting.
- verify(mCb).onNetworkConnectivityReported(eq(n), eq(connectivity));
- }
-
- @Test
- public void testRegisterConnectivityDiagnosticsCallback() throws Exception {
- final NetworkRequest request = new NetworkRequest.Builder().build();
-
- mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
-
- verify(mService).registerConnectivityDiagnosticsCallback(
- any(ConnectivityDiagnosticsBinder.class), eq(request), eq(mPackageName));
- assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
- }
-
- @Test
- public void testRegisterDuplicateConnectivityDiagnosticsCallback() throws Exception {
- final NetworkRequest request = new NetworkRequest.Builder().build();
-
- mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
-
- try {
- mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
- fail("Duplicate callback registration should fail");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testUnregisterConnectivityDiagnosticsCallback() throws Exception {
- final NetworkRequest request = new NetworkRequest.Builder().build();
- mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
-
- mManager.unregisterConnectivityDiagnosticsCallback(mCb);
-
- verify(mService).unregisterConnectivityDiagnosticsCallback(
- any(ConnectivityDiagnosticsBinder.class));
- assertFalse(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
-
- // verify that re-registering is successful
- mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
- verify(mService, times(2)).registerConnectivityDiagnosticsCallback(
- any(ConnectivityDiagnosticsBinder.class), eq(request), eq(mPackageName));
- assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
- }
-
- @Test
- public void testUnregisterUnknownConnectivityDiagnosticsCallback() throws Exception {
- mManager.unregisterConnectivityDiagnosticsCallback(mCb);
-
- verifyNoMoreInteractions(mService);
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/ConnectivityManagerTest.java b/packages/Connectivity/tests/unit/java/android/net/ConnectivityManagerTest.java
deleted file mode 100644
index c804e10..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/ConnectivityManagerTest.java
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.ConnectivityManager.TYPE_NONE;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
-import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
-import static android.net.NetworkRequest.Type.REQUEST;
-import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
-import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.os.Build.VERSION_CODES;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.Process;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ConnectivityManagerTest {
-
- @Mock Context mCtx;
- @Mock IConnectivityManager mService;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- }
-
- static NetworkCapabilities verifyNetworkCapabilities(
- int legacyType, int transportType, int... capabilities) {
- final NetworkCapabilities nc = ConnectivityManager.networkCapabilitiesForType(legacyType);
- assertNotNull(nc);
- assertTrue(nc.hasTransport(transportType));
- for (int capability : capabilities) {
- assertTrue(nc.hasCapability(capability));
- }
-
- return nc;
- }
-
- static void verifyUnrestrictedNetworkCapabilities(int legacyType, int transportType) {
- verifyNetworkCapabilities(
- legacyType,
- transportType,
- NET_CAPABILITY_INTERNET,
- NET_CAPABILITY_NOT_RESTRICTED,
- NET_CAPABILITY_NOT_VPN,
- NET_CAPABILITY_TRUSTED);
- }
-
- static void verifyRestrictedMobileNetworkCapabilities(int legacyType, int capability) {
- final NetworkCapabilities nc = verifyNetworkCapabilities(
- legacyType,
- TRANSPORT_CELLULAR,
- capability,
- NET_CAPABILITY_NOT_VPN,
- NET_CAPABILITY_TRUSTED);
-
- assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeMobile() {
- verifyUnrestrictedNetworkCapabilities(
- ConnectivityManager.TYPE_MOBILE, TRANSPORT_CELLULAR);
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeMobileCbs() {
- verifyRestrictedMobileNetworkCapabilities(
- ConnectivityManager.TYPE_MOBILE_CBS, NET_CAPABILITY_CBS);
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeMobileDun() {
- verifyRestrictedMobileNetworkCapabilities(
- ConnectivityManager.TYPE_MOBILE_DUN, NET_CAPABILITY_DUN);
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeMobileFota() {
- verifyRestrictedMobileNetworkCapabilities(
- ConnectivityManager.TYPE_MOBILE_FOTA, NET_CAPABILITY_FOTA);
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeMobileHipri() {
- verifyUnrestrictedNetworkCapabilities(
- ConnectivityManager.TYPE_MOBILE_HIPRI, TRANSPORT_CELLULAR);
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeMobileIms() {
- verifyRestrictedMobileNetworkCapabilities(
- ConnectivityManager.TYPE_MOBILE_IMS, NET_CAPABILITY_IMS);
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeMobileMms() {
- final NetworkCapabilities nc = verifyNetworkCapabilities(
- ConnectivityManager.TYPE_MOBILE_MMS,
- TRANSPORT_CELLULAR,
- NET_CAPABILITY_MMS,
- NET_CAPABILITY_NOT_VPN,
- NET_CAPABILITY_TRUSTED);
-
- assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeMobileSupl() {
- final NetworkCapabilities nc = verifyNetworkCapabilities(
- ConnectivityManager.TYPE_MOBILE_SUPL,
- TRANSPORT_CELLULAR,
- NET_CAPABILITY_SUPL,
- NET_CAPABILITY_NOT_VPN,
- NET_CAPABILITY_TRUSTED);
-
- assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeWifi() {
- verifyUnrestrictedNetworkCapabilities(
- ConnectivityManager.TYPE_WIFI, TRANSPORT_WIFI);
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeWifiP2p() {
- final NetworkCapabilities nc = verifyNetworkCapabilities(
- ConnectivityManager.TYPE_WIFI_P2P,
- TRANSPORT_WIFI,
- NET_CAPABILITY_NOT_RESTRICTED, NET_CAPABILITY_NOT_VPN,
- NET_CAPABILITY_TRUSTED, NET_CAPABILITY_WIFI_P2P);
-
- assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET));
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeBluetooth() {
- verifyUnrestrictedNetworkCapabilities(
- ConnectivityManager.TYPE_BLUETOOTH, TRANSPORT_BLUETOOTH);
- }
-
- @Test
- public void testNetworkCapabilitiesForTypeEthernet() {
- verifyUnrestrictedNetworkCapabilities(
- ConnectivityManager.TYPE_ETHERNET, TRANSPORT_ETHERNET);
- }
-
- @Test
- public void testCallbackRelease() throws Exception {
- ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
- NetworkRequest request = makeRequest(1);
- NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class);
- Handler handler = new Handler(Looper.getMainLooper());
- ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
-
- // register callback
- when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
- anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(request);
- manager.requestNetwork(request, callback, handler);
-
- // callback triggers
- captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_AVAILABLE));
- verify(callback, timeout(500).times(1)).onAvailable(any(Network.class),
- any(NetworkCapabilities.class), any(LinkProperties.class), anyBoolean());
-
- // unregister callback
- manager.unregisterNetworkCallback(callback);
- verify(mService, times(1)).releaseNetworkRequest(request);
-
- // callback does not trigger anymore.
- captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_LOSING));
- verify(callback, timeout(500).times(0)).onLosing(any(), anyInt());
- }
-
- @Test
- public void testCallbackRecycling() throws Exception {
- ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
- NetworkRequest req1 = makeRequest(1);
- NetworkRequest req2 = makeRequest(2);
- NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class);
- Handler handler = new Handler(Looper.getMainLooper());
- ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
-
- // register callback
- when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
- anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req1);
- manager.requestNetwork(req1, callback, handler);
-
- // callback triggers
- captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_AVAILABLE));
- verify(callback, timeout(100).times(1)).onAvailable(any(Network.class),
- any(NetworkCapabilities.class), any(LinkProperties.class), anyBoolean());
-
- // unregister callback
- manager.unregisterNetworkCallback(callback);
- verify(mService, times(1)).releaseNetworkRequest(req1);
-
- // callback does not trigger anymore.
- captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_LOSING));
- verify(callback, timeout(100).times(0)).onLosing(any(), anyInt());
-
- // callback can be registered again
- when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
- anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req2);
- manager.requestNetwork(req2, callback, handler);
-
- // callback triggers
- captor.getValue().send(makeMessage(req2, ConnectivityManager.CALLBACK_LOST));
- verify(callback, timeout(100).times(1)).onLost(any());
-
- // unregister callback
- manager.unregisterNetworkCallback(callback);
- verify(mService, times(1)).releaseNetworkRequest(req2);
- }
-
- // TODO: turn on this test when request callback 1:1 mapping is enforced
- //@Test
- private void noDoubleCallbackRegistration() throws Exception {
- ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
- NetworkRequest request = makeRequest(1);
- NetworkCallback callback = new ConnectivityManager.NetworkCallback();
- ApplicationInfo info = new ApplicationInfo();
- // TODO: update version when starting to enforce 1:1 mapping
- info.targetSdkVersion = VERSION_CODES.N_MR1 + 1;
-
- when(mCtx.getApplicationInfo()).thenReturn(info);
- when(mService.requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(), anyInt(),
- anyInt(), any(), nullable(String.class))).thenReturn(request);
-
- Handler handler = new Handler(Looper.getMainLooper());
- manager.requestNetwork(request, callback, handler);
-
- // callback is already registered, reregistration should fail.
- Class<IllegalArgumentException> wantException = IllegalArgumentException.class;
- expectThrowable(() -> manager.requestNetwork(request, callback), wantException);
-
- manager.unregisterNetworkCallback(callback);
- verify(mService, times(1)).releaseNetworkRequest(request);
-
- // unregistering the callback should make it registrable again.
- manager.requestNetwork(request, callback);
- }
-
- @Test
- public void testArgumentValidation() throws Exception {
- ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
-
- NetworkRequest request = mock(NetworkRequest.class);
- NetworkCallback callback = mock(NetworkCallback.class);
- Handler handler = mock(Handler.class);
- NetworkCallback nullCallback = null;
- PendingIntent nullIntent = null;
-
- mustFail(() -> manager.requestNetwork(null, callback));
- mustFail(() -> manager.requestNetwork(request, nullCallback));
- mustFail(() -> manager.requestNetwork(request, callback, null));
- mustFail(() -> manager.requestNetwork(request, callback, -1));
- mustFail(() -> manager.requestNetwork(request, nullIntent));
-
- mustFail(() -> manager.requestBackgroundNetwork(null, callback, handler));
- mustFail(() -> manager.requestBackgroundNetwork(request, null, handler));
- mustFail(() -> manager.requestBackgroundNetwork(request, callback, null));
-
- mustFail(() -> manager.registerNetworkCallback(null, callback, handler));
- mustFail(() -> manager.registerNetworkCallback(request, null, handler));
- mustFail(() -> manager.registerNetworkCallback(request, callback, null));
- mustFail(() -> manager.registerNetworkCallback(request, nullIntent));
-
- mustFail(() -> manager.registerDefaultNetworkCallback(null, handler));
- mustFail(() -> manager.registerDefaultNetworkCallback(callback, null));
-
- mustFail(() -> manager.registerSystemDefaultNetworkCallback(null, handler));
- mustFail(() -> manager.registerSystemDefaultNetworkCallback(callback, null));
-
- mustFail(() -> manager.registerBestMatchingNetworkCallback(null, callback, handler));
- mustFail(() -> manager.registerBestMatchingNetworkCallback(request, null, handler));
- mustFail(() -> manager.registerBestMatchingNetworkCallback(request, callback, null));
-
- mustFail(() -> manager.unregisterNetworkCallback(nullCallback));
- mustFail(() -> manager.unregisterNetworkCallback(nullIntent));
- mustFail(() -> manager.releaseNetworkRequest(nullIntent));
- }
-
- static void mustFail(Runnable fn) {
- try {
- fn.run();
- fail();
- } catch (Exception expected) {
- }
- }
-
- @Test
- public void testRequestType() throws Exception {
- final String testPkgName = "MyPackage";
- final String testAttributionTag = "MyTag";
- final ConnectivityManager manager = new ConnectivityManager(mCtx, mService);
- when(mCtx.getOpPackageName()).thenReturn(testPkgName);
- when(mCtx.getAttributionTag()).thenReturn(testAttributionTag);
- final NetworkRequest request = makeRequest(1);
- final NetworkCallback callback = new ConnectivityManager.NetworkCallback();
-
- manager.requestNetwork(request, callback);
- verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities),
- eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
- eq(testPkgName), eq(testAttributionTag));
- reset(mService);
-
- // Verify that register network callback does not calls requestNetwork at all.
- manager.registerNetworkCallback(request, callback);
- verify(mService, never()).requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(),
- anyInt(), anyInt(), any(), any());
- verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(), anyInt(),
- eq(testPkgName), eq(testAttributionTag));
- reset(mService);
-
- Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
-
- manager.registerDefaultNetworkCallback(callback);
- verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null),
- eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
- eq(testPkgName), eq(testAttributionTag));
- reset(mService);
-
- manager.registerDefaultNetworkCallbackForUid(42, callback, handler);
- verify(mService).requestNetwork(eq(42), eq(null),
- eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
- eq(testPkgName), eq(testAttributionTag));
-
- manager.requestBackgroundNetwork(request, callback, handler);
- verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities),
- eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
- eq(testPkgName), eq(testAttributionTag));
- reset(mService);
-
- manager.registerSystemDefaultNetworkCallback(callback, handler);
- verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null),
- eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
- eq(testPkgName), eq(testAttributionTag));
- reset(mService);
- }
-
- static Message makeMessage(NetworkRequest req, int messageType) {
- Bundle bundle = new Bundle();
- bundle.putParcelable(NetworkRequest.class.getSimpleName(), req);
- // Pass default objects as we don't care which get passed here
- bundle.putParcelable(Network.class.getSimpleName(), new Network(1));
- bundle.putParcelable(NetworkCapabilities.class.getSimpleName(), new NetworkCapabilities());
- bundle.putParcelable(LinkProperties.class.getSimpleName(), new LinkProperties());
- Message msg = Message.obtain();
- msg.what = messageType;
- msg.setData(bundle);
- return msg;
- }
-
- static NetworkRequest makeRequest(int requestId) {
- NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
- return new NetworkRequest(request.networkCapabilities, ConnectivityManager.TYPE_NONE,
- requestId, NetworkRequest.Type.NONE);
- }
-
- static void expectThrowable(Runnable block, Class<? extends Throwable> throwableType) {
- try {
- block.run();
- } catch (Throwable t) {
- if (t.getClass().equals(throwableType)) {
- return;
- }
- fail("expected exception of type " + throwableType + ", but was " + t.getClass());
- }
- fail("expected exception of type " + throwableType);
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/Ikev2VpnProfileTest.java b/packages/Connectivity/tests/unit/java/android/net/Ikev2VpnProfileTest.java
deleted file mode 100644
index 1abd39a..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/Ikev2VpnProfileTest.java
+++ /dev/null
@@ -1,439 +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 android.net;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.test.mock.MockContext;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.net.VpnProfile;
-import com.android.net.module.util.ProxyUtils;
-import com.android.internal.org.bouncycastle.x509.X509V1CertificateGenerator;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.math.BigInteger;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import javax.security.auth.x500.X500Principal;
-
-/** Unit tests for {@link Ikev2VpnProfile.Builder}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class Ikev2VpnProfileTest {
- private static final String SERVER_ADDR_STRING = "1.2.3.4";
- private static final String IDENTITY_STRING = "Identity";
- private static final String USERNAME_STRING = "username";
- private static final String PASSWORD_STRING = "pa55w0rd";
- private static final String EXCL_LIST = "exclList";
- private static final byte[] PSK_BYTES = "preSharedKey".getBytes();
- private static final int TEST_MTU = 1300;
-
- private final MockContext mMockContext =
- new MockContext() {
- @Override
- public String getOpPackageName() {
- return "fooPackage";
- }
- };
- private final ProxyInfo mProxy = ProxyInfo.buildDirectProxy(
- SERVER_ADDR_STRING, -1, ProxyUtils.exclusionStringAsList(EXCL_LIST));
-
- private X509Certificate mUserCert;
- private X509Certificate mServerRootCa;
- private PrivateKey mPrivateKey;
-
- @Before
- public void setUp() throws Exception {
- mServerRootCa = generateRandomCertAndKeyPair().cert;
-
- final CertificateAndKey userCertKey = generateRandomCertAndKeyPair();
- mUserCert = userCertKey.cert;
- mPrivateKey = userCertKey.key;
- }
-
- private Ikev2VpnProfile.Builder getBuilderWithDefaultOptions() {
- final Ikev2VpnProfile.Builder builder =
- new Ikev2VpnProfile.Builder(SERVER_ADDR_STRING, IDENTITY_STRING);
-
- builder.setBypassable(true);
- builder.setProxy(mProxy);
- builder.setMaxMtu(TEST_MTU);
- builder.setMetered(true);
-
- return builder;
- }
-
- @Test
- public void testBuildValidProfileWithOptions() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
- final Ikev2VpnProfile profile = builder.build();
- assertNotNull(profile);
-
- // Check non-auth parameters correctly stored
- assertEquals(SERVER_ADDR_STRING, profile.getServerAddr());
- assertEquals(IDENTITY_STRING, profile.getUserIdentity());
- assertEquals(mProxy, profile.getProxyInfo());
- assertTrue(profile.isBypassable());
- assertTrue(profile.isMetered());
- assertEquals(TEST_MTU, profile.getMaxMtu());
- assertEquals(Ikev2VpnProfile.DEFAULT_ALGORITHMS, profile.getAllowedAlgorithms());
- }
-
- @Test
- public void testBuildUsernamePasswordProfile() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
- final Ikev2VpnProfile profile = builder.build();
- assertNotNull(profile);
-
- assertEquals(USERNAME_STRING, profile.getUsername());
- assertEquals(PASSWORD_STRING, profile.getPassword());
- assertEquals(mServerRootCa, profile.getServerRootCaCert());
-
- assertNull(profile.getPresharedKey());
- assertNull(profile.getRsaPrivateKey());
- assertNull(profile.getUserCert());
- }
-
- @Test
- public void testBuildDigitalSignatureProfile() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
- final Ikev2VpnProfile profile = builder.build();
- assertNotNull(profile);
-
- assertEquals(profile.getUserCert(), mUserCert);
- assertEquals(mPrivateKey, profile.getRsaPrivateKey());
- assertEquals(profile.getServerRootCaCert(), mServerRootCa);
-
- assertNull(profile.getPresharedKey());
- assertNull(profile.getUsername());
- assertNull(profile.getPassword());
- }
-
- @Test
- public void testBuildPresharedKeyProfile() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthPsk(PSK_BYTES);
- final Ikev2VpnProfile profile = builder.build();
- assertNotNull(profile);
-
- assertArrayEquals(PSK_BYTES, profile.getPresharedKey());
-
- assertNull(profile.getServerRootCaCert());
- assertNull(profile.getUsername());
- assertNull(profile.getPassword());
- assertNull(profile.getRsaPrivateKey());
- assertNull(profile.getUserCert());
- }
-
- @Test
- public void testBuildWithAllowedAlgorithmsAead() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
- builder.setAuthPsk(PSK_BYTES);
-
- List<String> allowedAlgorithms = Arrays.asList(IpSecAlgorithm.AUTH_CRYPT_AES_GCM);
- builder.setAllowedAlgorithms(allowedAlgorithms);
-
- final Ikev2VpnProfile profile = builder.build();
- assertEquals(allowedAlgorithms, profile.getAllowedAlgorithms());
- }
-
- @Test
- public void testBuildWithAllowedAlgorithmsNormal() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
- builder.setAuthPsk(PSK_BYTES);
-
- List<String> allowedAlgorithms =
- Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA512, IpSecAlgorithm.CRYPT_AES_CBC);
- builder.setAllowedAlgorithms(allowedAlgorithms);
-
- final Ikev2VpnProfile profile = builder.build();
- assertEquals(allowedAlgorithms, profile.getAllowedAlgorithms());
- }
-
- @Test
- public void testSetAllowedAlgorithmsEmptyList() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- try {
- builder.setAllowedAlgorithms(new ArrayList<>());
- fail("Expected exception due to no valid algorithm set");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testSetAllowedAlgorithmsInvalidList() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
- List<String> allowedAlgorithms = new ArrayList<>();
-
- try {
- builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA256));
- fail("Expected exception due to missing encryption");
- } catch (IllegalArgumentException expected) {
- }
-
- try {
- builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.CRYPT_AES_CBC));
- fail("Expected exception due to missing authentication");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testSetAllowedAlgorithmsInsecureAlgorithm() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
- List<String> allowedAlgorithms = new ArrayList<>();
-
- try {
- builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_MD5));
- fail("Expected exception due to insecure algorithm");
- } catch (IllegalArgumentException expected) {
- }
-
- try {
- builder.setAllowedAlgorithms(Arrays.asList(IpSecAlgorithm.AUTH_HMAC_SHA1));
- fail("Expected exception due to insecure algorithm");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testBuildNoAuthMethodSet() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- try {
- builder.build();
- fail("Expected exception due to lack of auth method");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testBuildInvalidMtu() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- try {
- builder.setMaxMtu(500);
- fail("Expected exception due to too-small MTU");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- private void verifyVpnProfileCommon(VpnProfile profile) {
- assertEquals(SERVER_ADDR_STRING, profile.server);
- assertEquals(IDENTITY_STRING, profile.ipsecIdentifier);
- assertEquals(mProxy, profile.proxy);
- assertTrue(profile.isBypassable);
- assertTrue(profile.isMetered);
- assertEquals(TEST_MTU, profile.maxMtu);
- }
-
- @Test
- public void testPskConvertToVpnProfile() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthPsk(PSK_BYTES);
- final VpnProfile profile = builder.build().toVpnProfile();
-
- verifyVpnProfileCommon(profile);
- assertEquals(Ikev2VpnProfile.encodeForIpsecSecret(PSK_BYTES), profile.ipsecSecret);
-
- // Check nothing else is set
- assertEquals("", profile.username);
- assertEquals("", profile.password);
- assertEquals("", profile.ipsecUserCert);
- assertEquals("", profile.ipsecCaCert);
- }
-
- @Test
- public void testUsernamePasswordConvertToVpnProfile() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
- final VpnProfile profile = builder.build().toVpnProfile();
-
- verifyVpnProfileCommon(profile);
- assertEquals(USERNAME_STRING, profile.username);
- assertEquals(PASSWORD_STRING, profile.password);
- assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert);
-
- // Check nothing else is set
- assertEquals("", profile.ipsecUserCert);
- assertEquals("", profile.ipsecSecret);
- }
-
- @Test
- public void testRsaConvertToVpnProfile() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
- final VpnProfile profile = builder.build().toVpnProfile();
-
- final String expectedSecret = Ikev2VpnProfile.PREFIX_INLINE
- + Ikev2VpnProfile.encodeForIpsecSecret(mPrivateKey.getEncoded());
- verifyVpnProfileCommon(profile);
- assertEquals(Ikev2VpnProfile.certificateToPemString(mUserCert), profile.ipsecUserCert);
- assertEquals(
- expectedSecret,
- profile.ipsecSecret);
- assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert);
-
- // Check nothing else is set
- assertEquals("", profile.username);
- assertEquals("", profile.password);
- }
-
- @Test
- public void testPskFromVpnProfileDiscardsIrrelevantValues() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthPsk(PSK_BYTES);
- final VpnProfile profile = builder.build().toVpnProfile();
- profile.username = USERNAME_STRING;
- profile.password = PASSWORD_STRING;
- profile.ipsecCaCert = Ikev2VpnProfile.certificateToPemString(mServerRootCa);
- profile.ipsecUserCert = Ikev2VpnProfile.certificateToPemString(mUserCert);
-
- final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
- assertNull(result.getUsername());
- assertNull(result.getPassword());
- assertNull(result.getUserCert());
- assertNull(result.getRsaPrivateKey());
- assertNull(result.getServerRootCaCert());
- }
-
- @Test
- public void testUsernamePasswordFromVpnProfileDiscardsIrrelevantValues() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
- final VpnProfile profile = builder.build().toVpnProfile();
- profile.ipsecSecret = new String(PSK_BYTES);
- profile.ipsecUserCert = Ikev2VpnProfile.certificateToPemString(mUserCert);
-
- final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
- assertNull(result.getPresharedKey());
- assertNull(result.getUserCert());
- assertNull(result.getRsaPrivateKey());
- }
-
- @Test
- public void testRsaFromVpnProfileDiscardsIrrelevantValues() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
- final VpnProfile profile = builder.build().toVpnProfile();
- profile.username = USERNAME_STRING;
- profile.password = PASSWORD_STRING;
-
- final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
- assertNull(result.getUsername());
- assertNull(result.getPassword());
- assertNull(result.getPresharedKey());
- }
-
- @Test
- public void testPskConversionIsLossless() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthPsk(PSK_BYTES);
- final Ikev2VpnProfile ikeProfile = builder.build();
-
- assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
- }
-
- @Test
- public void testUsernamePasswordConversionIsLossless() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
- final Ikev2VpnProfile ikeProfile = builder.build();
-
- assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
- }
-
- @Test
- public void testRsaConversionIsLossless() throws Exception {
- final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
-
- builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
- final Ikev2VpnProfile ikeProfile = builder.build();
-
- assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
- }
-
- private static class CertificateAndKey {
- public final X509Certificate cert;
- public final PrivateKey key;
-
- CertificateAndKey(X509Certificate cert, PrivateKey key) {
- this.cert = cert;
- this.key = key;
- }
- }
-
- private static CertificateAndKey generateRandomCertAndKeyPair() throws Exception {
- final Date validityBeginDate =
- new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1L));
- final Date validityEndDate =
- new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1L));
-
- // Generate a keypair
- final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
- keyPairGenerator.initialize(512);
- final KeyPair keyPair = keyPairGenerator.generateKeyPair();
-
- final X500Principal dnName = new X500Principal("CN=test.android.com");
- final X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
- certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
- certGen.setSubjectDN(dnName);
- certGen.setIssuerDN(dnName);
- certGen.setNotBefore(validityBeginDate);
- certGen.setNotAfter(validityEndDate);
- certGen.setPublicKey(keyPair.getPublic());
- certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
-
- final X509Certificate cert = certGen.generate(keyPair.getPrivate(), "AndroidOpenSSL");
- return new CertificateAndKey(cert, keyPair.getPrivate());
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/IpMemoryStoreTest.java b/packages/Connectivity/tests/unit/java/android/net/IpMemoryStoreTest.java
deleted file mode 100644
index 0b13800..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/IpMemoryStoreTest.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.net.ipmemorystore.Blob;
-import android.net.ipmemorystore.IOnStatusListener;
-import android.net.ipmemorystore.NetworkAttributes;
-import android.net.ipmemorystore.NetworkAttributesParcelable;
-import android.net.ipmemorystore.Status;
-import android.net.networkstack.ModuleNetworkStackClient;
-import android.os.RemoteException;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.net.UnknownHostException;
-import java.util.Arrays;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpMemoryStoreTest {
- private static final String TAG = IpMemoryStoreTest.class.getSimpleName();
- private static final String TEST_CLIENT_ID = "testClientId";
- private static final String TEST_DATA_NAME = "testData";
- private static final String TEST_OTHER_DATA_NAME = TEST_DATA_NAME + "Other";
- private static final byte[] TEST_BLOB_DATA = new byte[] { -3, 6, 8, -9, 12,
- -128, 0, 89, 112, 91, -34 };
- private static final NetworkAttributes TEST_NETWORK_ATTRIBUTES = buildTestNetworkAttributes(
- "hint", 219);
-
- @Mock
- Context mMockContext;
- @Mock
- ModuleNetworkStackClient mModuleNetworkStackClient;
- @Mock
- IIpMemoryStore mMockService;
- @Mock
- IOnStatusListener mIOnStatusListener;
- IpMemoryStore mStore;
-
- @Captor
- ArgumentCaptor<IIpMemoryStoreCallbacks> mCbCaptor;
- @Captor
- ArgumentCaptor<NetworkAttributesParcelable> mNapCaptor;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- }
-
- private void startIpMemoryStore(boolean supplyService) {
- if (supplyService) {
- doAnswer(invocation -> {
- ((IIpMemoryStoreCallbacks) invocation.getArgument(0))
- .onIpMemoryStoreFetched(mMockService);
- return null;
- }).when(mModuleNetworkStackClient).fetchIpMemoryStore(any());
- } else {
- doNothing().when(mModuleNetworkStackClient).fetchIpMemoryStore(mCbCaptor.capture());
- }
- mStore = new IpMemoryStore(mMockContext) {
- @Override
- protected ModuleNetworkStackClient getModuleNetworkStackClient(Context ctx) {
- return mModuleNetworkStackClient;
- }
- };
- }
-
- private static NetworkAttributes buildTestNetworkAttributes(String hint, int mtu) {
- return new NetworkAttributes.Builder()
- .setCluster(hint)
- .setMtu(mtu)
- .build();
- }
-
- @Test
- public void testNetworkAttributes() throws Exception {
- startIpMemoryStore(true /* supplyService */);
- final String l2Key = "fakeKey";
-
- mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
- status -> assertTrue("Store not successful : " + status.resultCode,
- status.isSuccess()));
- verify(mMockService, times(1)).storeNetworkAttributes(eq(l2Key),
- mNapCaptor.capture(), any());
- assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
-
- mStore.retrieveNetworkAttributes(l2Key,
- (status, key, attr) -> {
- assertTrue("Retrieve network attributes not successful : "
- + status.resultCode, status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
- });
-
- verify(mMockService, times(1)).retrieveNetworkAttributes(eq(l2Key), any());
- }
-
- @Test
- public void testPrivateData() throws RemoteException {
- startIpMemoryStore(true /* supplyService */);
- final Blob b = new Blob();
- b.data = TEST_BLOB_DATA;
- final String l2Key = "fakeKey";
-
- mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
- status -> {
- assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
- });
- verify(mMockService, times(1)).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
- eq(b), any());
-
- mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
- (status, key, name, data) -> {
- assertTrue("Retrieve blob status not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(name, TEST_DATA_NAME);
- assertTrue(Arrays.equals(b.data, data.data));
- });
- verify(mMockService, times(1)).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
- eq(TEST_OTHER_DATA_NAME), any());
- }
-
- @Test
- public void testFindL2Key()
- throws UnknownHostException, RemoteException, Exception {
- startIpMemoryStore(true /* supplyService */);
- final String l2Key = "fakeKey";
-
- mStore.findL2Key(TEST_NETWORK_ATTRIBUTES,
- (status, key) -> {
- assertTrue("Retrieve network sameness not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(l2Key, key);
- });
- verify(mMockService, times(1)).findL2Key(mNapCaptor.capture(), any());
- assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
- }
-
- @Test
- public void testIsSameNetwork() throws UnknownHostException, RemoteException {
- startIpMemoryStore(true /* supplyService */);
- final String l2Key1 = "fakeKey1";
- final String l2Key2 = "fakeKey2";
-
- mStore.isSameNetwork(l2Key1, l2Key2,
- (status, answer) -> {
- assertFalse("Retrieve network sameness suspiciously successful : "
- + status.resultCode, status.isSuccess());
- assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
- assertNull(answer);
- });
- verify(mMockService, times(1)).isSameNetwork(eq(l2Key1), eq(l2Key2), any());
- }
-
- @Test
- public void testEnqueuedIpMsRequests() throws Exception {
- startIpMemoryStore(false /* supplyService */);
-
- final Blob b = new Blob();
- b.data = TEST_BLOB_DATA;
- final String l2Key = "fakeKey";
-
- // enqueue multiple ipms requests
- mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
- status -> assertTrue("Store not successful : " + status.resultCode,
- status.isSuccess()));
- mStore.retrieveNetworkAttributes(l2Key,
- (status, key, attr) -> {
- assertTrue("Retrieve network attributes not successful : "
- + status.resultCode, status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
- });
- mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
- status -> assertTrue("Store not successful : " + status.resultCode,
- status.isSuccess()));
- mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
- (status, key, name, data) -> {
- assertTrue("Retrieve blob status not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(name, TEST_DATA_NAME);
- assertTrue(Arrays.equals(b.data, data.data));
- });
-
- // get ipms service ready
- mCbCaptor.getValue().onIpMemoryStoreFetched(mMockService);
-
- InOrder inOrder = inOrder(mMockService);
-
- inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any());
- inOrder.verify(mMockService).retrieveNetworkAttributes(eq(l2Key), any());
- inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
- eq(b), any());
- inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
- eq(TEST_OTHER_DATA_NAME), any());
- assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
- }
-
- @Test
- public void testEnqueuedIpMsRequestsWithException() throws Exception {
- startIpMemoryStore(true /* supplyService */);
- doThrow(RemoteException.class).when(mMockService).retrieveNetworkAttributes(any(), any());
-
- final Blob b = new Blob();
- b.data = TEST_BLOB_DATA;
- final String l2Key = "fakeKey";
-
- // enqueue multiple ipms requests
- mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
- status -> assertTrue("Store not successful : " + status.resultCode,
- status.isSuccess()));
- mStore.retrieveNetworkAttributes(l2Key,
- (status, key, attr) -> {
- assertTrue("Retrieve network attributes not successful : "
- + status.resultCode, status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(TEST_NETWORK_ATTRIBUTES, attr);
- });
- mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
- status -> assertTrue("Store not successful : " + status.resultCode,
- status.isSuccess()));
- mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
- (status, key, name, data) -> {
- assertTrue("Retrieve blob status not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(name, TEST_DATA_NAME);
- assertTrue(Arrays.equals(b.data, data.data));
- });
-
- // verify the rest of the queue is still processed in order even if the remote exception
- // occurs when calling one or more requests
- InOrder inOrder = inOrder(mMockService);
-
- inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(), any());
- inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
- eq(b), any());
- inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
- eq(TEST_OTHER_DATA_NAME), any());
- assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
- }
-
- @Test
- public void testEnqueuedIpMsRequestsCallbackFunctionWithException() throws Exception {
- startIpMemoryStore(true /* supplyService */);
-
- final Blob b = new Blob();
- b.data = TEST_BLOB_DATA;
- final String l2Key = "fakeKey";
-
- // enqueue multiple ipms requests
- mStore.storeNetworkAttributes(l2Key, TEST_NETWORK_ATTRIBUTES,
- status -> assertTrue("Store not successful : " + status.resultCode,
- status.isSuccess()));
- mStore.retrieveNetworkAttributes(l2Key,
- (status, key, attr) -> {
- throw new RuntimeException("retrieveNetworkAttributes test");
- });
- mStore.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
- status -> {
- throw new RuntimeException("storeBlob test");
- });
- mStore.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_OTHER_DATA_NAME,
- (status, key, name, data) -> {
- assertTrue("Retrieve blob status not successful : " + status.resultCode,
- status.isSuccess());
- assertEquals(l2Key, key);
- assertEquals(name, TEST_DATA_NAME);
- assertTrue(Arrays.equals(b.data, data.data));
- });
-
- // verify the rest of the queue is still processed in order even if when one or more
- // callback throw the remote exception
- InOrder inOrder = inOrder(mMockService);
-
- inOrder.verify(mMockService).storeNetworkAttributes(eq(l2Key), mNapCaptor.capture(),
- any());
- inOrder.verify(mMockService).retrieveNetworkAttributes(eq(l2Key), any());
- inOrder.verify(mMockService).storeBlob(eq(l2Key), eq(TEST_CLIENT_ID), eq(TEST_DATA_NAME),
- eq(b), any());
- inOrder.verify(mMockService).retrieveBlob(eq(l2Key), eq(TEST_CLIENT_ID),
- eq(TEST_OTHER_DATA_NAME), any());
- assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
- }
-
- @Test
- public void testFactoryReset() throws RemoteException {
- startIpMemoryStore(true /* supplyService */);
- mStore.factoryReset();
- verify(mMockService, times(1)).factoryReset();
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/IpSecAlgorithmTest.java b/packages/Connectivity/tests/unit/java/android/net/IpSecAlgorithmTest.java
deleted file mode 100644
index 5bd2214..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/IpSecAlgorithmTest.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.IpSecAlgorithm.ALGO_TO_REQUIRED_FIRST_SDK;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-
-import android.content.res.Resources;
-import android.os.Build;
-import android.os.Parcel;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.CollectionUtils;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.AbstractMap.SimpleEntry;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map.Entry;
-import java.util.Random;
-import java.util.Set;
-
-/** Unit tests for {@link IpSecAlgorithm}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class IpSecAlgorithmTest {
- private static final byte[] KEY_MATERIAL;
-
- private final Resources mMockResources = mock(Resources.class);
-
- static {
- KEY_MATERIAL = new byte[128];
- new Random().nextBytes(KEY_MATERIAL);
- };
-
- private static byte[] generateKey(int keyLenInBits) {
- return Arrays.copyOf(KEY_MATERIAL, keyLenInBits / 8);
- }
-
- @Test
- public void testNoTruncLen() throws Exception {
- Entry<String, Integer>[] authAndAeadList =
- new Entry[] {
- new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_MD5, 128),
- new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA1, 160),
- new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA256, 256),
- new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA384, 384),
- new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA512, 512),
- new SimpleEntry<>(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, 224),
- };
-
- // Expect auth and aead algorithms to throw errors if trunclen is omitted.
- for (Entry<String, Integer> algData : authAndAeadList) {
- try {
- new IpSecAlgorithm(
- algData.getKey(), Arrays.copyOf(KEY_MATERIAL, algData.getValue() / 8));
- fail("Expected exception on unprovided auth trunclen");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- // Ensure crypt works with no truncation length supplied.
- new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, 256 / 8));
- }
-
- private void checkAuthKeyAndTruncLenValidation(String algoName, int keyLen, int truncLen)
- throws Exception {
- new IpSecAlgorithm(algoName, generateKey(keyLen), truncLen);
-
- try {
- new IpSecAlgorithm(algoName, generateKey(keyLen));
- fail("Expected exception on unprovided auth trunclen");
- } catch (IllegalArgumentException pass) {
- }
-
- try {
- new IpSecAlgorithm(algoName, generateKey(keyLen + 8), truncLen);
- fail("Invalid key length not validated");
- } catch (IllegalArgumentException pass) {
- }
-
- try {
- new IpSecAlgorithm(algoName, generateKey(keyLen), truncLen + 1);
- fail("Invalid truncation length not validated");
- } catch (IllegalArgumentException pass) {
- }
- }
-
- private void checkCryptKeyLenValidation(String algoName, int keyLen) throws Exception {
- new IpSecAlgorithm(algoName, generateKey(keyLen));
-
- try {
- new IpSecAlgorithm(algoName, generateKey(keyLen + 8));
- fail("Invalid key length not validated");
- } catch (IllegalArgumentException pass) {
- }
- }
-
- @Test
- public void testValidationForAlgosAddedInS() throws Exception {
- if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.R) {
- return;
- }
-
- for (int len : new int[] {160, 224, 288}) {
- checkCryptKeyLenValidation(IpSecAlgorithm.CRYPT_AES_CTR, len);
- }
- checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_AES_XCBC, 128, 96);
- checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_AES_CMAC, 128, 96);
- checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305, 288, 128);
- }
-
- @Test
- public void testTruncLenValidation() throws Exception {
- for (int truncLen : new int[] {256, 512}) {
- new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA512,
- Arrays.copyOf(KEY_MATERIAL, 512 / 8),
- truncLen);
- }
-
- for (int truncLen : new int[] {255, 513}) {
- try {
- new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA512,
- Arrays.copyOf(KEY_MATERIAL, 512 / 8),
- truncLen);
- fail("Invalid truncation length not validated");
- } catch (IllegalArgumentException pass) {
- }
- }
- }
-
- @Test
- public void testLenValidation() throws Exception {
- for (int len : new int[] {128, 192, 256}) {
- new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, len / 8));
- }
- try {
- new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, 384 / 8));
- fail("Invalid key length not validated");
- } catch (IllegalArgumentException pass) {
- }
- }
-
- @Test
- public void testAlgoNameValidation() throws Exception {
- try {
- new IpSecAlgorithm("rot13", Arrays.copyOf(KEY_MATERIAL, 128 / 8));
- fail("Invalid algorithm name not validated");
- } catch (IllegalArgumentException pass) {
- }
- }
-
- @Test
- public void testParcelUnparcel() throws Exception {
- IpSecAlgorithm init =
- new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA512, Arrays.copyOf(KEY_MATERIAL, 512 / 8), 256);
-
- Parcel p = Parcel.obtain();
- p.setDataPosition(0);
- init.writeToParcel(p, 0);
-
- p.setDataPosition(0);
- IpSecAlgorithm fin = IpSecAlgorithm.CREATOR.createFromParcel(p);
- assertTrue("Parcel/Unparcel failed!", IpSecAlgorithm.equals(init, fin));
- p.recycle();
- }
-
- private static Set<String> getMandatoryAlgos() {
- return CollectionUtils.filter(
- ALGO_TO_REQUIRED_FIRST_SDK.keySet(),
- i -> Build.VERSION.DEVICE_INITIAL_SDK_INT >= ALGO_TO_REQUIRED_FIRST_SDK.get(i));
- }
-
- private static Set<String> getOptionalAlgos() {
- return CollectionUtils.filter(
- ALGO_TO_REQUIRED_FIRST_SDK.keySet(),
- i -> Build.VERSION.DEVICE_INITIAL_SDK_INT < ALGO_TO_REQUIRED_FIRST_SDK.get(i));
- }
-
- @Test
- public void testGetSupportedAlgorithms() throws Exception {
- assertTrue(IpSecAlgorithm.getSupportedAlgorithms().containsAll(getMandatoryAlgos()));
- assertTrue(ALGO_TO_REQUIRED_FIRST_SDK.keySet().containsAll(
- IpSecAlgorithm.getSupportedAlgorithms()));
- }
-
- @Test
- public void testLoadAlgos() throws Exception {
- final Set<String> optionalAlgoSet = getOptionalAlgos();
- final String[] optionalAlgos = optionalAlgoSet.toArray(new String[0]);
-
- doReturn(optionalAlgos).when(mMockResources)
- .getStringArray(com.android.internal.R.array.config_optionalIpSecAlgorithms);
-
- final Set<String> enabledAlgos = new HashSet<>(IpSecAlgorithm.loadAlgos(mMockResources));
- final Set<String> expectedAlgos = ALGO_TO_REQUIRED_FIRST_SDK.keySet();
-
- assertEquals(expectedAlgos, enabledAlgos);
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/IpSecConfigTest.java b/packages/Connectivity/tests/unit/java/android/net/IpSecConfigTest.java
deleted file mode 100644
index 25e225e..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/IpSecConfigTest.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static com.android.testutils.ParcelUtils.assertParcelSane;
-import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Unit tests for {@link IpSecConfig}. */
-@SmallTest
-@RunWith(JUnit4.class)
-public class IpSecConfigTest {
-
- @Test
- public void testDefaults() throws Exception {
- IpSecConfig c = new IpSecConfig();
- assertEquals(IpSecTransform.MODE_TRANSPORT, c.getMode());
- assertEquals("", c.getSourceAddress());
- assertEquals("", c.getDestinationAddress());
- assertNull(c.getNetwork());
- assertEquals(IpSecTransform.ENCAP_NONE, c.getEncapType());
- assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getEncapSocketResourceId());
- assertEquals(0, c.getEncapRemotePort());
- assertEquals(0, c.getNattKeepaliveInterval());
- assertNull(c.getEncryption());
- assertNull(c.getAuthentication());
- assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getSpiResourceId());
- assertEquals(0, c.getXfrmInterfaceId());
- }
-
- private IpSecConfig getSampleConfig() {
- IpSecConfig c = new IpSecConfig();
- c.setMode(IpSecTransform.MODE_TUNNEL);
- c.setSourceAddress("0.0.0.0");
- c.setDestinationAddress("1.2.3.4");
- c.setSpiResourceId(1984);
- c.setEncryption(
- new IpSecAlgorithm(
- IpSecAlgorithm.CRYPT_AES_CBC,
- new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF}));
- c.setAuthentication(
- new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_MD5,
- new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0},
- 128));
- c.setAuthenticatedEncryption(
- new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
- new byte[] {
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0, 1, 2, 3, 4
- },
- 128));
- c.setEncapType(android.system.OsConstants.UDP_ENCAP_ESPINUDP);
- c.setEncapSocketResourceId(7);
- c.setEncapRemotePort(22);
- c.setNattKeepaliveInterval(42);
- c.setMarkValue(12);
- c.setMarkMask(23);
- c.setXfrmInterfaceId(34);
-
- return c;
- }
-
- @Test
- public void testCopyConstructor() {
- IpSecConfig original = getSampleConfig();
- IpSecConfig copy = new IpSecConfig(original);
-
- assertEquals(original, copy);
- assertNotSame(original, copy);
- }
-
- @Test
- public void testParcelUnparcel() {
- assertParcelingIsLossless(new IpSecConfig());
-
- IpSecConfig c = getSampleConfig();
- assertParcelSane(c, 15);
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/IpSecManagerTest.java b/packages/Connectivity/tests/unit/java/android/net/IpSecManagerTest.java
deleted file mode 100644
index 730e2d5..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/IpSecManagerTest.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_DGRAM;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.system.Os;
-import android.test.mock.MockContext;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.IpSecService;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.net.Socket;
-import java.net.UnknownHostException;
-
-/** Unit tests for {@link IpSecManager}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class IpSecManagerTest {
-
- private static final int TEST_UDP_ENCAP_PORT = 34567;
- private static final int DROID_SPI = 0xD1201D;
- private static final int DUMMY_RESOURCE_ID = 0x1234;
-
- private static final InetAddress GOOGLE_DNS_4;
- private static final String VTI_INTF_NAME = "ipsec_test";
- private static final InetAddress VTI_LOCAL_ADDRESS;
- private static final LinkAddress VTI_INNER_ADDRESS = new LinkAddress("10.0.1.1/24");
-
- static {
- try {
- // Google Public DNS Addresses;
- GOOGLE_DNS_4 = InetAddress.getByName("8.8.8.8");
- VTI_LOCAL_ADDRESS = InetAddress.getByName("8.8.4.4");
- } catch (UnknownHostException e) {
- throw new RuntimeException("Could not resolve DNS Addresses", e);
- }
- }
-
- private IpSecService mMockIpSecService;
- private IpSecManager mIpSecManager;
- private MockContext mMockContext = new MockContext() {
- @Override
- public String getOpPackageName() {
- return "fooPackage";
- }
- };
-
- @Before
- public void setUp() throws Exception {
- mMockIpSecService = mock(IpSecService.class);
- mIpSecManager = new IpSecManager(mMockContext, mMockIpSecService);
- }
-
- /*
- * Allocate a specific SPI
- * Close SPIs
- */
- @Test
- public void testAllocSpi() throws Exception {
- IpSecSpiResponse spiResp =
- new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_RESOURCE_ID, DROID_SPI);
- when(mMockIpSecService.allocateSecurityParameterIndex(
- eq(GOOGLE_DNS_4.getHostAddress()),
- eq(DROID_SPI),
- anyObject()))
- .thenReturn(spiResp);
-
- IpSecManager.SecurityParameterIndex droidSpi =
- mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4, DROID_SPI);
- assertEquals(DROID_SPI, droidSpi.getSpi());
-
- droidSpi.close();
-
- verify(mMockIpSecService).releaseSecurityParameterIndex(DUMMY_RESOURCE_ID);
- }
-
- @Test
- public void testAllocRandomSpi() throws Exception {
- IpSecSpiResponse spiResp =
- new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_RESOURCE_ID, DROID_SPI);
- when(mMockIpSecService.allocateSecurityParameterIndex(
- eq(GOOGLE_DNS_4.getHostAddress()),
- eq(IpSecManager.INVALID_SECURITY_PARAMETER_INDEX),
- anyObject()))
- .thenReturn(spiResp);
-
- IpSecManager.SecurityParameterIndex randomSpi =
- mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4);
-
- assertEquals(DROID_SPI, randomSpi.getSpi());
-
- randomSpi.close();
-
- verify(mMockIpSecService).releaseSecurityParameterIndex(DUMMY_RESOURCE_ID);
- }
-
- /*
- * Throws resource unavailable exception
- */
- @Test
- public void testAllocSpiResUnavailableException() throws Exception {
- IpSecSpiResponse spiResp =
- new IpSecSpiResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE, 0, 0);
- when(mMockIpSecService.allocateSecurityParameterIndex(
- anyString(), anyInt(), anyObject()))
- .thenReturn(spiResp);
-
- try {
- mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4);
- fail("ResourceUnavailableException was not thrown");
- } catch (IpSecManager.ResourceUnavailableException e) {
- }
- }
-
- /*
- * Throws spi unavailable exception
- */
- @Test
- public void testAllocSpiSpiUnavailableException() throws Exception {
- IpSecSpiResponse spiResp = new IpSecSpiResponse(IpSecManager.Status.SPI_UNAVAILABLE, 0, 0);
- when(mMockIpSecService.allocateSecurityParameterIndex(
- anyString(), anyInt(), anyObject()))
- .thenReturn(spiResp);
-
- try {
- mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4);
- fail("ResourceUnavailableException was not thrown");
- } catch (IpSecManager.ResourceUnavailableException e) {
- }
- }
-
- /*
- * Should throw exception when request spi 0 in IpSecManager
- */
- @Test
- public void testRequestAllocInvalidSpi() throws Exception {
- try {
- mIpSecManager.allocateSecurityParameterIndex(GOOGLE_DNS_4, 0);
- fail("Able to allocate invalid spi");
- } catch (IllegalArgumentException e) {
- }
- }
-
- @Test
- public void testOpenEncapsulationSocket() throws Exception {
- IpSecUdpEncapResponse udpEncapResp =
- new IpSecUdpEncapResponse(
- IpSecManager.Status.OK,
- DUMMY_RESOURCE_ID,
- TEST_UDP_ENCAP_PORT,
- Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
- when(mMockIpSecService.openUdpEncapsulationSocket(eq(TEST_UDP_ENCAP_PORT), anyObject()))
- .thenReturn(udpEncapResp);
-
- IpSecManager.UdpEncapsulationSocket encapSocket =
- mIpSecManager.openUdpEncapsulationSocket(TEST_UDP_ENCAP_PORT);
- assertNotNull(encapSocket.getFileDescriptor());
- assertEquals(TEST_UDP_ENCAP_PORT, encapSocket.getPort());
-
- encapSocket.close();
-
- verify(mMockIpSecService).closeUdpEncapsulationSocket(DUMMY_RESOURCE_ID);
- }
-
- @Test
- public void testApplyTransportModeTransformEnsuresSocketCreation() throws Exception {
- Socket socket = new Socket();
- IpSecConfig dummyConfig = new IpSecConfig();
- IpSecTransform dummyTransform = new IpSecTransform(null, dummyConfig);
-
- // Even if underlying SocketImpl is not initalized, this should force the init, and
- // thereby succeed.
- mIpSecManager.applyTransportModeTransform(
- socket, IpSecManager.DIRECTION_IN, dummyTransform);
-
- // Check to make sure the FileDescriptor is non-null
- assertNotNull(socket.getFileDescriptor$());
- }
-
- @Test
- public void testRemoveTransportModeTransformsForcesSocketCreation() throws Exception {
- Socket socket = new Socket();
-
- // Even if underlying SocketImpl is not initalized, this should force the init, and
- // thereby succeed.
- mIpSecManager.removeTransportModeTransforms(socket);
-
- // Check to make sure the FileDescriptor is non-null
- assertNotNull(socket.getFileDescriptor$());
- }
-
- @Test
- public void testOpenEncapsulationSocketOnRandomPort() throws Exception {
- IpSecUdpEncapResponse udpEncapResp =
- new IpSecUdpEncapResponse(
- IpSecManager.Status.OK,
- DUMMY_RESOURCE_ID,
- TEST_UDP_ENCAP_PORT,
- Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
-
- when(mMockIpSecService.openUdpEncapsulationSocket(eq(0), anyObject()))
- .thenReturn(udpEncapResp);
-
- IpSecManager.UdpEncapsulationSocket encapSocket =
- mIpSecManager.openUdpEncapsulationSocket();
-
- assertNotNull(encapSocket.getFileDescriptor());
- assertEquals(TEST_UDP_ENCAP_PORT, encapSocket.getPort());
-
- encapSocket.close();
-
- verify(mMockIpSecService).closeUdpEncapsulationSocket(DUMMY_RESOURCE_ID);
- }
-
- @Test
- public void testOpenEncapsulationSocketWithInvalidPort() throws Exception {
- try {
- mIpSecManager.openUdpEncapsulationSocket(IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
- fail("IllegalArgumentException was not thrown");
- } catch (IllegalArgumentException e) {
- }
- }
-
- // TODO: add test when applicable transform builder interface is available
-
- private IpSecManager.IpSecTunnelInterface createAndValidateVti(int resourceId, String intfName)
- throws Exception {
- IpSecTunnelInterfaceResponse dummyResponse =
- new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
- when(mMockIpSecService.createTunnelInterface(
- eq(VTI_LOCAL_ADDRESS.getHostAddress()), eq(GOOGLE_DNS_4.getHostAddress()),
- anyObject(), anyObject(), anyString()))
- .thenReturn(dummyResponse);
-
- IpSecManager.IpSecTunnelInterface tunnelIntf = mIpSecManager.createIpSecTunnelInterface(
- VTI_LOCAL_ADDRESS, GOOGLE_DNS_4, mock(Network.class));
-
- assertNotNull(tunnelIntf);
- return tunnelIntf;
- }
-
- @Test
- public void testCreateVti() throws Exception {
- IpSecManager.IpSecTunnelInterface tunnelIntf =
- createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);
-
- assertEquals(VTI_INTF_NAME, tunnelIntf.getInterfaceName());
-
- tunnelIntf.close();
- verify(mMockIpSecService).deleteTunnelInterface(eq(DUMMY_RESOURCE_ID), anyString());
- }
-
- @Test
- public void testAddRemoveAddressesFromVti() throws Exception {
- IpSecManager.IpSecTunnelInterface tunnelIntf =
- createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);
-
- tunnelIntf.addAddress(VTI_INNER_ADDRESS.getAddress(),
- VTI_INNER_ADDRESS.getPrefixLength());
- verify(mMockIpSecService)
- .addAddressToTunnelInterface(
- eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
-
- tunnelIntf.removeAddress(VTI_INNER_ADDRESS.getAddress(),
- VTI_INNER_ADDRESS.getPrefixLength());
- verify(mMockIpSecService)
- .addAddressToTunnelInterface(
- eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/IpSecTransformTest.java b/packages/Connectivity/tests/unit/java/android/net/IpSecTransformTest.java
deleted file mode 100644
index 424f23d..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/IpSecTransformTest.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/** Unit tests for {@link IpSecTransform}. */
-@SmallTest
-@RunWith(JUnit4.class)
-public class IpSecTransformTest {
-
- @Test
- public void testCreateTransformCopiesConfig() {
- // Create a config with a few parameters to make sure it's not empty
- IpSecConfig config = new IpSecConfig();
- config.setSourceAddress("0.0.0.0");
- config.setDestinationAddress("1.2.3.4");
- config.setSpiResourceId(1984);
-
- IpSecTransform preModification = new IpSecTransform(null, config);
-
- config.setSpiResourceId(1985);
- IpSecTransform postModification = new IpSecTransform(null, config);
-
- assertNotEquals(preModification, postModification);
- }
-
- @Test
- public void testCreateTransformsWithSameConfigEqual() {
- // Create a config with a few parameters to make sure it's not empty
- IpSecConfig config = new IpSecConfig();
- config.setSourceAddress("0.0.0.0");
- config.setDestinationAddress("1.2.3.4");
- config.setSpiResourceId(1984);
-
- IpSecTransform config1 = new IpSecTransform(null, config);
- IpSecTransform config2 = new IpSecTransform(null, config);
-
- assertEquals(config1, config2);
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java b/packages/Connectivity/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
deleted file mode 100644
index fc739fb..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/KeepalivePacketDataUtilTest.java
+++ /dev/null
@@ -1,205 +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.net;
-
-import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.util.KeepalivePacketDataUtil;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.net.InetAddress;
-import java.nio.ByteBuffer;
-
-@RunWith(JUnit4.class)
-public final class KeepalivePacketDataUtilTest {
- private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 1};
- private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 5};
-
- @Before
- public void setUp() {}
-
- @Test
- public void testFromTcpKeepaliveStableParcelable() throws Exception {
- final int srcPort = 1234;
- final int dstPort = 4321;
- final int seq = 0x11111111;
- final int ack = 0x22222222;
- final int wnd = 8000;
- final int wndScale = 2;
- final int tos = 4;
- final int ttl = 64;
- TcpKeepalivePacketData resultData = null;
- final TcpKeepalivePacketDataParcelable testInfo = new TcpKeepalivePacketDataParcelable();
- testInfo.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
- testInfo.srcPort = srcPort;
- testInfo.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
- testInfo.dstPort = dstPort;
- testInfo.seq = seq;
- testInfo.ack = ack;
- testInfo.rcvWnd = wnd;
- testInfo.rcvWndScale = wndScale;
- testInfo.tos = tos;
- testInfo.ttl = ttl;
- try {
- resultData = KeepalivePacketDataUtil.fromStableParcelable(testInfo);
- } catch (InvalidPacketException e) {
- fail("InvalidPacketException: " + e);
- }
-
- assertEquals(InetAddress.getByAddress(testInfo.srcAddress), resultData.getSrcAddress());
- assertEquals(InetAddress.getByAddress(testInfo.dstAddress), resultData.getDstAddress());
- assertEquals(testInfo.srcPort, resultData.getSrcPort());
- assertEquals(testInfo.dstPort, resultData.getDstPort());
- assertEquals(testInfo.seq, resultData.tcpSeq);
- assertEquals(testInfo.ack, resultData.tcpAck);
- assertEquals(testInfo.rcvWnd, resultData.tcpWindow);
- assertEquals(testInfo.rcvWndScale, resultData.tcpWindowScale);
- assertEquals(testInfo.tos, resultData.ipTos);
- assertEquals(testInfo.ttl, resultData.ipTtl);
-
- assertParcelingIsLossless(resultData);
-
- final byte[] packet = resultData.getPacket();
- // IP version and IHL
- assertEquals(packet[0], 0x45);
- // TOS
- assertEquals(packet[1], tos);
- // TTL
- assertEquals(packet[8], ttl);
- // Source IP address.
- byte[] ip = new byte[4];
- ByteBuffer buf = ByteBuffer.wrap(packet, 12, 4);
- buf.get(ip);
- assertArrayEquals(ip, IPV4_KEEPALIVE_SRC_ADDR);
- // Destination IP address.
- buf = ByteBuffer.wrap(packet, 16, 4);
- buf.get(ip);
- assertArrayEquals(ip, IPV4_KEEPALIVE_DST_ADDR);
-
- buf = ByteBuffer.wrap(packet, 20, 12);
- // Source port.
- assertEquals(buf.getShort(), srcPort);
- // Destination port.
- assertEquals(buf.getShort(), dstPort);
- // Sequence number.
- assertEquals(buf.getInt(), seq);
- // Ack.
- assertEquals(buf.getInt(), ack);
- // Window size.
- buf = ByteBuffer.wrap(packet, 34, 2);
- assertEquals(buf.getShort(), wnd >> wndScale);
- }
-
- //TODO: add ipv6 test when ipv6 supported
-
- @Test
- public void testToTcpKeepaliveStableParcelable() throws Exception {
- final int srcPort = 1234;
- final int dstPort = 4321;
- final int sequence = 0x11111111;
- final int ack = 0x22222222;
- final int wnd = 48_000;
- final int wndScale = 2;
- final int tos = 4;
- final int ttl = 64;
- final TcpKeepalivePacketDataParcelable testInfo = new TcpKeepalivePacketDataParcelable();
- testInfo.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
- testInfo.srcPort = srcPort;
- testInfo.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
- testInfo.dstPort = dstPort;
- testInfo.seq = sequence;
- testInfo.ack = ack;
- testInfo.rcvWnd = wnd;
- testInfo.rcvWndScale = wndScale;
- testInfo.tos = tos;
- testInfo.ttl = ttl;
- TcpKeepalivePacketData testData = null;
- TcpKeepalivePacketDataParcelable resultData = null;
- testData = KeepalivePacketDataUtil.fromStableParcelable(testInfo);
- resultData = KeepalivePacketDataUtil.toStableParcelable(testData);
- assertArrayEquals(resultData.srcAddress, IPV4_KEEPALIVE_SRC_ADDR);
- assertArrayEquals(resultData.dstAddress, IPV4_KEEPALIVE_DST_ADDR);
- assertEquals(resultData.srcPort, srcPort);
- assertEquals(resultData.dstPort, dstPort);
- assertEquals(resultData.seq, sequence);
- assertEquals(resultData.ack, ack);
- assertEquals(resultData.rcvWnd, wnd);
- assertEquals(resultData.rcvWndScale, wndScale);
- assertEquals(resultData.tos, tos);
- assertEquals(resultData.ttl, ttl);
-
- final String expected = ""
- + "android.net.TcpKeepalivePacketDataParcelable{srcAddress: [10, 0, 0, 1],"
- + " srcPort: 1234, dstAddress: [10, 0, 0, 5], dstPort: 4321, seq: 286331153,"
- + " ack: 572662306, rcvWnd: 48000, rcvWndScale: 2, tos: 4, ttl: 64}";
- assertEquals(expected, resultData.toString());
- }
-
- @Test
- public void testParseTcpKeepalivePacketData() throws Exception {
- final int srcPort = 1234;
- final int dstPort = 4321;
- final int sequence = 0x11111111;
- final int ack = 0x22222222;
- final int wnd = 4800;
- final int wndScale = 2;
- final int tos = 4;
- final int ttl = 64;
- final TcpKeepalivePacketDataParcelable testParcel = new TcpKeepalivePacketDataParcelable();
- testParcel.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
- testParcel.srcPort = srcPort;
- testParcel.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
- testParcel.dstPort = dstPort;
- testParcel.seq = sequence;
- testParcel.ack = ack;
- testParcel.rcvWnd = wnd;
- testParcel.rcvWndScale = wndScale;
- testParcel.tos = tos;
- testParcel.ttl = ttl;
-
- final KeepalivePacketData testData =
- KeepalivePacketDataUtil.fromStableParcelable(testParcel);
- final TcpKeepalivePacketDataParcelable parsedParcelable =
- KeepalivePacketDataUtil.parseTcpKeepalivePacketData(testData);
- final TcpKeepalivePacketData roundTripData =
- KeepalivePacketDataUtil.fromStableParcelable(parsedParcelable);
-
- // Generated packet is the same, but rcvWnd / wndScale will differ if scale is non-zero
- assertTrue(testData.getPacket().length > 0);
- assertArrayEquals(testData.getPacket(), roundTripData.getPacket());
-
- testParcel.rcvWndScale = 0;
- final KeepalivePacketData noScaleTestData =
- KeepalivePacketDataUtil.fromStableParcelable(testParcel);
- final TcpKeepalivePacketDataParcelable noScaleParsedParcelable =
- KeepalivePacketDataUtil.parseTcpKeepalivePacketData(noScaleTestData);
- final TcpKeepalivePacketData noScaleRoundTripData =
- KeepalivePacketDataUtil.fromStableParcelable(noScaleParsedParcelable);
- assertEquals(noScaleTestData, noScaleRoundTripData);
- assertTrue(noScaleTestData.getPacket().length > 0);
- assertArrayEquals(noScaleTestData.getPacket(), noScaleRoundTripData.getPacket());
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/MacAddressTest.java b/packages/Connectivity/tests/unit/java/android/net/MacAddressTest.java
deleted file mode 100644
index 6de31f6..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/MacAddressTest.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.net.module.util.MacAddressUtils;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.Inet6Address;
-import java.util.Arrays;
-import java.util.Random;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class MacAddressTest {
-
- static class AddrTypeTestCase {
- byte[] addr;
- int expectedType;
-
- static AddrTypeTestCase of(int expectedType, int... addr) {
- AddrTypeTestCase t = new AddrTypeTestCase();
- t.expectedType = expectedType;
- t.addr = toByteArray(addr);
- return t;
- }
- }
-
- @Test
- public void testMacAddrTypes() {
- AddrTypeTestCase[] testcases = {
- AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN),
- AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 0),
- AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 1, 2, 3, 4, 5),
- AddrTypeTestCase.of(MacAddress.TYPE_UNKNOWN, 1, 2, 3, 4, 5, 6, 7),
- AddrTypeTestCase.of(MacAddress.TYPE_UNICAST, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0),
- AddrTypeTestCase.of(MacAddress.TYPE_BROADCAST, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
- AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 1, 2, 3, 4, 5, 6),
- AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 11, 22, 33, 44, 55, 66),
- AddrTypeTestCase.of(MacAddress.TYPE_MULTICAST, 33, 33, 0xaa, 0xbb, 0xcc, 0xdd)
- };
-
- for (AddrTypeTestCase t : testcases) {
- int got = MacAddress.macAddressType(t.addr);
- String msg = String.format("expected type of %s to be %s, but got %s",
- Arrays.toString(t.addr), t.expectedType, got);
- assertEquals(msg, t.expectedType, got);
-
- if (got != MacAddress.TYPE_UNKNOWN) {
- assertEquals(got, MacAddress.fromBytes(t.addr).getAddressType());
- }
- }
- }
-
- @Test
- public void testToOuiString() {
- String[][] macs = {
- {"07:00:d3:56:8a:c4", "07:00:d3"},
- {"33:33:aa:bb:cc:dd", "33:33:aa"},
- {"06:00:00:00:00:00", "06:00:00"},
- {"07:00:d3:56:8a:c4", "07:00:d3"}
- };
-
- for (String[] pair : macs) {
- String mac = pair[0];
- String expected = pair[1];
- assertEquals(expected, MacAddress.fromString(mac).toOuiString());
- }
- }
-
- @Test
- public void testHexPaddingWhenPrinting() {
- String[] macs = {
- "07:00:d3:56:8a:c4",
- "33:33:aa:bb:cc:dd",
- "06:00:00:00:00:00",
- "07:00:d3:56:8a:c4"
- };
-
- for (String mac : macs) {
- assertEquals(mac, MacAddress.fromString(mac).toString());
- assertEquals(mac,
- MacAddress.stringAddrFromByteAddr(MacAddress.byteAddrFromStringAddr(mac)));
- }
- }
-
- @Test
- public void testIsMulticastAddress() {
- MacAddress[] multicastAddresses = {
- MacAddress.BROADCAST_ADDRESS,
- MacAddress.fromString("07:00:d3:56:8a:c4"),
- MacAddress.fromString("33:33:aa:bb:cc:dd"),
- };
- MacAddress[] unicastAddresses = {
- MacAddress.ALL_ZEROS_ADDRESS,
- MacAddress.fromString("00:01:44:55:66:77"),
- MacAddress.fromString("08:00:22:33:44:55"),
- MacAddress.fromString("06:00:00:00:00:00"),
- };
-
- for (MacAddress mac : multicastAddresses) {
- String msg = mac.toString() + " expected to be a multicast address";
- assertTrue(msg, MacAddressUtils.isMulticastAddress(mac));
- }
- for (MacAddress mac : unicastAddresses) {
- String msg = mac.toString() + " expected not to be a multicast address";
- assertFalse(msg, MacAddressUtils.isMulticastAddress(mac));
- }
- }
-
- @Test
- public void testIsLocallyAssignedAddress() {
- MacAddress[] localAddresses = {
- MacAddress.fromString("06:00:00:00:00:00"),
- MacAddress.fromString("07:00:d3:56:8a:c4"),
- MacAddress.fromString("33:33:aa:bb:cc:dd"),
- };
- MacAddress[] universalAddresses = {
- MacAddress.fromString("00:01:44:55:66:77"),
- MacAddress.fromString("08:00:22:33:44:55"),
- };
-
- for (MacAddress mac : localAddresses) {
- String msg = mac.toString() + " expected to be a locally assigned address";
- assertTrue(msg, mac.isLocallyAssigned());
- }
- for (MacAddress mac : universalAddresses) {
- String msg = mac.toString() + " expected not to be globally unique address";
- assertFalse(msg, mac.isLocallyAssigned());
- }
- }
-
- @Test
- public void testMacAddressConversions() {
- final int iterations = 10000;
- for (int i = 0; i < iterations; i++) {
- MacAddress mac = MacAddressUtils.createRandomUnicastAddress();
-
- String stringRepr = mac.toString();
- byte[] bytesRepr = mac.toByteArray();
-
- assertEquals(mac, MacAddress.fromString(stringRepr));
- assertEquals(mac, MacAddress.fromBytes(bytesRepr));
-
- assertEquals(mac, MacAddress.fromString(MacAddress.stringAddrFromByteAddr(bytesRepr)));
- assertEquals(mac, MacAddress.fromBytes(MacAddress.byteAddrFromStringAddr(stringRepr)));
- }
- }
-
- @Test
- public void testMacAddressRandomGeneration() {
- final int iterations = 1000;
- final String expectedAndroidOui = "da:a1:19";
- for (int i = 0; i < iterations; i++) {
- MacAddress mac = MacAddress.createRandomUnicastAddressWithGoogleBase();
- String stringRepr = mac.toString();
-
- assertTrue(stringRepr + " expected to be a locally assigned address",
- mac.isLocallyAssigned());
- assertTrue(stringRepr + " expected to begin with " + expectedAndroidOui,
- stringRepr.startsWith(expectedAndroidOui));
- }
-
- final Random r = new Random();
- final String anotherOui = "24:5f:78";
- final String expectedLocalOui = "26:5f:78";
- final MacAddress base = MacAddress.fromString(anotherOui + ":0:0:0");
- for (int i = 0; i < iterations; i++) {
- MacAddress mac = MacAddressUtils.createRandomUnicastAddress(base, r);
- String stringRepr = mac.toString();
-
- assertTrue(stringRepr + " expected to be a locally assigned address",
- mac.isLocallyAssigned());
- assertEquals(MacAddress.TYPE_UNICAST, mac.getAddressType());
- assertTrue(stringRepr + " expected to begin with " + expectedLocalOui,
- stringRepr.startsWith(expectedLocalOui));
- }
-
- for (int i = 0; i < iterations; i++) {
- MacAddress mac = MacAddressUtils.createRandomUnicastAddress();
- String stringRepr = mac.toString();
-
- assertTrue(stringRepr + " expected to be a locally assigned address",
- mac.isLocallyAssigned());
- assertEquals(MacAddress.TYPE_UNICAST, mac.getAddressType());
- }
- }
-
- @Test
- public void testConstructorInputValidation() {
- String[] invalidStringAddresses = {
- "",
- "abcd",
- "1:2:3:4:5",
- "1:2:3:4:5:6:7",
- "10000:2:3:4:5:6",
- };
-
- for (String s : invalidStringAddresses) {
- try {
- MacAddress mac = MacAddress.fromString(s);
- fail("MacAddress.fromString(" + s + ") should have failed, but returned " + mac);
- } catch (IllegalArgumentException excepted) {
- }
- }
-
- try {
- MacAddress mac = MacAddress.fromString(null);
- fail("MacAddress.fromString(null) should have failed, but returned " + mac);
- } catch (NullPointerException excepted) {
- }
-
- byte[][] invalidBytesAddresses = {
- {},
- {1,2,3,4,5},
- {1,2,3,4,5,6,7},
- };
-
- for (byte[] b : invalidBytesAddresses) {
- try {
- MacAddress mac = MacAddress.fromBytes(b);
- fail("MacAddress.fromBytes(" + Arrays.toString(b)
- + ") should have failed, but returned " + mac);
- } catch (IllegalArgumentException excepted) {
- }
- }
-
- try {
- MacAddress mac = MacAddress.fromBytes(null);
- fail("MacAddress.fromBytes(null) should have failed, but returned " + mac);
- } catch (NullPointerException excepted) {
- }
- }
-
- @Test
- public void testMatches() {
- // match 4 bytes prefix
- assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("aa:bb:cc:dd:00:00"),
- MacAddress.fromString("ff:ff:ff:ff:00:00")));
-
- // match bytes 0,1,2 and 5
- assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("aa:bb:cc:00:00:11"),
- MacAddress.fromString("ff:ff:ff:00:00:ff")));
-
- // match 34 bit prefix
- assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("aa:bb:cc:dd:c0:00"),
- MacAddress.fromString("ff:ff:ff:ff:c0:00")));
-
- // fail to match 36 bit prefix
- assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("aa:bb:cc:dd:40:00"),
- MacAddress.fromString("ff:ff:ff:ff:f0:00")));
-
- // match all 6 bytes
- assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("aa:bb:cc:dd:ee:11"),
- MacAddress.fromString("ff:ff:ff:ff:ff:ff")));
-
- // match none of 6 bytes
- assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
- MacAddress.fromString("00:00:00:00:00:00"),
- MacAddress.fromString("00:00:00:00:00:00")));
- }
-
- /**
- * Tests that link-local address generation from MAC is valid.
- */
- @Test
- public void testLinkLocalFromMacGeneration() {
- MacAddress mac = MacAddress.fromString("52:74:f2:b1:a8:7f");
- byte[] inet6ll = {(byte) 0xfe, (byte) 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x74,
- (byte) 0xf2, (byte) 0xff, (byte) 0xfe, (byte) 0xb1, (byte) 0xa8, 0x7f};
- Inet6Address llv6 = mac.getLinkLocalIpv6FromEui48Mac();
- assertTrue(llv6.isLinkLocalAddress());
- assertArrayEquals(inet6ll, llv6.getAddress());
- }
-
- static byte[] toByteArray(int... in) {
- byte[] out = new byte[in.length];
- for (int i = 0; i < in.length; i++) {
- out[i] = (byte) in[i];
- }
- return out;
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/NetworkIdentityTest.kt b/packages/Connectivity/tests/unit/java/android/net/NetworkIdentityTest.kt
deleted file mode 100644
index eb2b85c..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/NetworkIdentityTest.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net
-
-import android.net.NetworkIdentity.OEM_NONE
-import android.net.NetworkIdentity.OEM_PAID
-import android.net.NetworkIdentity.OEM_PRIVATE
-import android.net.NetworkIdentity.getOemBitfield
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import kotlin.test.assertEquals
-
-@RunWith(JUnit4::class)
-class NetworkIdentityTest {
- @Test
- fun testGetOemBitfield() {
- val oemNone = NetworkCapabilities().apply {
- setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, false)
- setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, false)
- }
- val oemPaid = NetworkCapabilities().apply {
- setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, true)
- setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, false)
- }
- val oemPrivate = NetworkCapabilities().apply {
- setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, false)
- setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, true)
- }
- val oemAll = NetworkCapabilities().apply {
- setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, true)
- setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, true)
- }
-
- assertEquals(getOemBitfield(oemNone), OEM_NONE)
- assertEquals(getOemBitfield(oemPaid), OEM_PAID)
- assertEquals(getOemBitfield(oemPrivate), OEM_PRIVATE)
- assertEquals(getOemBitfield(oemAll), OEM_PAID or OEM_PRIVATE)
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/NetworkStatsHistoryTest.java b/packages/Connectivity/tests/unit/java/android/net/NetworkStatsHistoryTest.java
deleted file mode 100644
index 13558cd..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/NetworkStatsHistoryTest.java
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLong;
-import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLong;
-import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
-import static android.net.NetworkStatsHistory.FIELD_ALL;
-import static android.net.NetworkStatsHistory.FIELD_OPERATIONS;
-import static android.net.NetworkStatsHistory.FIELD_RX_BYTES;
-import static android.net.NetworkStatsHistory.FIELD_RX_PACKETS;
-import static android.net.NetworkStatsHistory.FIELD_TX_BYTES;
-import static android.net.TrafficStats.GB_IN_BYTES;
-import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.text.format.DateUtils.DAY_IN_MILLIS;
-import static android.text.format.DateUtils.HOUR_IN_MILLIS;
-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
-import static android.text.format.DateUtils.WEEK_IN_MILLIS;
-import static android.text.format.DateUtils.YEAR_IN_MILLIS;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.frameworks.tests.net.R;
-
-import org.junit.After;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.util.Random;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkStatsHistoryTest {
- private static final String TAG = "NetworkStatsHistoryTest";
-
- private static final long TEST_START = 1194220800000L;
-
- private NetworkStatsHistory stats;
-
- @After
- public void tearDown() throws Exception {
- if (stats != null) {
- assertConsistent(stats);
- }
- }
-
- @Test
- public void testReadOriginalVersion() throws Exception {
- final Context context = InstrumentationRegistry.getContext();
- final DataInputStream in =
- new DataInputStream(context.getResources().openRawResource(R.raw.history_v1));
-
- NetworkStatsHistory.Entry entry = null;
- try {
- final NetworkStatsHistory history = new NetworkStatsHistory(in);
- assertEquals(15 * SECOND_IN_MILLIS, history.getBucketDuration());
-
- entry = history.getValues(0, entry);
- assertEquals(29143L, entry.rxBytes);
- assertEquals(6223L, entry.txBytes);
-
- entry = history.getValues(history.size() - 1, entry);
- assertEquals(1476L, entry.rxBytes);
- assertEquals(838L, entry.txBytes);
-
- entry = history.getValues(Long.MIN_VALUE, Long.MAX_VALUE, entry);
- assertEquals(332401L, entry.rxBytes);
- assertEquals(64314L, entry.txBytes);
-
- } finally {
- in.close();
- }
- }
-
- @Test
- public void testRecordSingleBucket() throws Exception {
- final long BUCKET_SIZE = HOUR_IN_MILLIS;
- stats = new NetworkStatsHistory(BUCKET_SIZE);
-
- // record data into narrow window to get single bucket
- stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
-
- assertEquals(1, stats.size());
- assertValues(stats, 0, SECOND_IN_MILLIS, 1024L, 10L, 2048L, 20L, 2L);
- }
-
- @Test
- public void testRecordEqualBuckets() throws Exception {
- final long bucketDuration = HOUR_IN_MILLIS;
- stats = new NetworkStatsHistory(bucketDuration);
-
- // split equally across two buckets
- final long recordStart = TEST_START + (bucketDuration / 2);
- stats.recordData(recordStart, recordStart + bucketDuration,
- new NetworkStats.Entry(1024L, 10L, 128L, 2L, 2L));
-
- assertEquals(2, stats.size());
- assertValues(stats, 0, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L);
- assertValues(stats, 1, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L);
- }
-
- @Test
- public void testRecordTouchingBuckets() throws Exception {
- final long BUCKET_SIZE = 15 * MINUTE_IN_MILLIS;
- stats = new NetworkStatsHistory(BUCKET_SIZE);
-
- // split almost completely into middle bucket, but with a few minutes
- // overlap into neighboring buckets. total record is 20 minutes.
- final long recordStart = (TEST_START + BUCKET_SIZE) - MINUTE_IN_MILLIS;
- final long recordEnd = (TEST_START + (BUCKET_SIZE * 2)) + (MINUTE_IN_MILLIS * 4);
- stats.recordData(recordStart, recordEnd,
- new NetworkStats.Entry(1000L, 2000L, 5000L, 10000L, 100L));
-
- assertEquals(3, stats.size());
- // first bucket should have (1/20 of value)
- assertValues(stats, 0, MINUTE_IN_MILLIS, 50L, 100L, 250L, 500L, 5L);
- // second bucket should have (15/20 of value)
- assertValues(stats, 1, 15 * MINUTE_IN_MILLIS, 750L, 1500L, 3750L, 7500L, 75L);
- // final bucket should have (4/20 of value)
- assertValues(stats, 2, 4 * MINUTE_IN_MILLIS, 200L, 400L, 1000L, 2000L, 20L);
- }
-
- @Test
- public void testRecordGapBuckets() throws Exception {
- final long BUCKET_SIZE = HOUR_IN_MILLIS;
- stats = new NetworkStatsHistory(BUCKET_SIZE);
-
- // record some data today and next week with large gap
- final long firstStart = TEST_START;
- final long lastStart = TEST_START + WEEK_IN_MILLIS;
- stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS,
- new NetworkStats.Entry(128L, 2L, 256L, 4L, 1L));
- stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS,
- new NetworkStats.Entry(64L, 1L, 512L, 8L, 2L));
-
- // we should have two buckets, far apart from each other
- assertEquals(2, stats.size());
- assertValues(stats, 0, SECOND_IN_MILLIS, 128L, 2L, 256L, 4L, 1L);
- assertValues(stats, 1, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L);
-
- // now record something in middle, spread across two buckets
- final long middleStart = TEST_START + DAY_IN_MILLIS;
- final long middleEnd = middleStart + (HOUR_IN_MILLIS * 2);
- stats.recordData(middleStart, middleEnd,
- new NetworkStats.Entry(2048L, 4L, 2048L, 4L, 2L));
-
- // now should have four buckets, with new record in middle two buckets
- assertEquals(4, stats.size());
- assertValues(stats, 0, SECOND_IN_MILLIS, 128L, 2L, 256L, 4L, 1L);
- assertValues(stats, 1, HOUR_IN_MILLIS, 1024L, 2L, 1024L, 2L, 1L);
- assertValues(stats, 2, HOUR_IN_MILLIS, 1024L, 2L, 1024L, 2L, 1L);
- assertValues(stats, 3, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L);
- }
-
- @Test
- public void testRecordOverlapBuckets() throws Exception {
- final long BUCKET_SIZE = HOUR_IN_MILLIS;
- stats = new NetworkStatsHistory(BUCKET_SIZE);
-
- // record some data in one bucket, and another overlapping buckets
- stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS,
- new NetworkStats.Entry(256L, 2L, 256L, 2L, 1L));
- final long midStart = TEST_START + (HOUR_IN_MILLIS / 2);
- stats.recordData(midStart, midStart + HOUR_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 1024L, 10L, 10L));
-
- // should have two buckets, with some data mixed together
- assertEquals(2, stats.size());
- assertValues(stats, 0, SECOND_IN_MILLIS + (HOUR_IN_MILLIS / 2), 768L, 7L, 768L, 7L, 6L);
- assertValues(stats, 1, (HOUR_IN_MILLIS / 2), 512L, 5L, 512L, 5L, 5L);
- }
-
- @Test
- public void testRecordEntireGapIdentical() throws Exception {
- // first, create two separate histories far apart
- final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
- stats1.recordData(TEST_START, TEST_START + 2 * HOUR_IN_MILLIS, 2000L, 1000L);
-
- final long TEST_START_2 = TEST_START + DAY_IN_MILLIS;
- final NetworkStatsHistory stats2 = new NetworkStatsHistory(HOUR_IN_MILLIS);
- stats2.recordData(TEST_START_2, TEST_START_2 + 2 * HOUR_IN_MILLIS, 1000L, 500L);
-
- // combine together with identical bucket size
- stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
- stats.recordEntireHistory(stats1);
- stats.recordEntireHistory(stats2);
-
- // first verify that totals match up
- assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 3000L, 1500L);
-
- // now inspect internal buckets
- assertValues(stats, 0, 1000L, 500L);
- assertValues(stats, 1, 1000L, 500L);
- assertValues(stats, 2, 500L, 250L);
- assertValues(stats, 3, 500L, 250L);
- }
-
- @Test
- public void testRecordEntireOverlapVaryingBuckets() throws Exception {
- // create history just over hour bucket boundary
- final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
- stats1.recordData(TEST_START, TEST_START + MINUTE_IN_MILLIS * 60, 600L, 600L);
-
- final long TEST_START_2 = TEST_START + MINUTE_IN_MILLIS;
- final NetworkStatsHistory stats2 = new NetworkStatsHistory(MINUTE_IN_MILLIS);
- stats2.recordData(TEST_START_2, TEST_START_2 + MINUTE_IN_MILLIS * 5, 50L, 50L);
-
- // combine together with minute bucket size
- stats = new NetworkStatsHistory(MINUTE_IN_MILLIS);
- stats.recordEntireHistory(stats1);
- stats.recordEntireHistory(stats2);
-
- // first verify that totals match up
- assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L);
-
- // now inspect internal buckets
- assertValues(stats, 0, 10L, 10L);
- assertValues(stats, 1, 20L, 20L);
- assertValues(stats, 2, 20L, 20L);
- assertValues(stats, 3, 20L, 20L);
- assertValues(stats, 4, 20L, 20L);
- assertValues(stats, 5, 20L, 20L);
- assertValues(stats, 6, 10L, 10L);
-
- // now combine using 15min buckets
- stats = new NetworkStatsHistory(HOUR_IN_MILLIS / 4);
- stats.recordEntireHistory(stats1);
- stats.recordEntireHistory(stats2);
-
- // first verify that totals match up
- assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L);
-
- // and inspect buckets
- assertValues(stats, 0, 200L, 200L);
- assertValues(stats, 1, 150L, 150L);
- assertValues(stats, 2, 150L, 150L);
- assertValues(stats, 3, 150L, 150L);
- }
-
- @Test
- public void testRemove() throws Exception {
- stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
-
- // record some data across 24 buckets
- stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 24L, 24L);
- assertEquals(24, stats.size());
-
- // try removing invalid data; should be no change
- stats.removeBucketsBefore(0 - DAY_IN_MILLIS);
- assertEquals(24, stats.size());
-
- // try removing far before buckets; should be no change
- stats.removeBucketsBefore(TEST_START - YEAR_IN_MILLIS);
- assertEquals(24, stats.size());
-
- // try removing just moments into first bucket; should be no change
- // since that bucket contains data beyond the cutoff
- stats.removeBucketsBefore(TEST_START + SECOND_IN_MILLIS);
- assertEquals(24, stats.size());
-
- // try removing single bucket
- stats.removeBucketsBefore(TEST_START + HOUR_IN_MILLIS);
- assertEquals(23, stats.size());
-
- // try removing multiple buckets
- stats.removeBucketsBefore(TEST_START + (4 * HOUR_IN_MILLIS));
- assertEquals(20, stats.size());
-
- // try removing all buckets
- stats.removeBucketsBefore(TEST_START + YEAR_IN_MILLIS);
- assertEquals(0, stats.size());
- }
-
- @Test
- public void testTotalData() throws Exception {
- final long BUCKET_SIZE = HOUR_IN_MILLIS;
- stats = new NetworkStatsHistory(BUCKET_SIZE);
-
- // record uniform data across day
- stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 2400L, 4800L);
-
- // verify that total outside range is 0
- assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, 0L, 0L);
-
- // verify total in first hour
- assertValues(stats, TEST_START, TEST_START + HOUR_IN_MILLIS, 100L, 200L);
-
- // verify total across 1.5 hours
- assertValues(stats, TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), 150L, 300L);
-
- // verify total beyond end
- assertValues(stats, TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, 100L, 200L);
-
- // verify everything total
- assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 2400L, 4800L);
-
- }
-
- @Test
- public void testFuzzing() throws Exception {
- try {
- // fuzzing with random events, looking for crashes
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- final Random r = new Random();
- for (int i = 0; i < 500; i++) {
- stats = new NetworkStatsHistory(r.nextLong());
- for (int j = 0; j < 10000; j++) {
- if (r.nextBoolean()) {
- // add range
- final long start = r.nextLong();
- final long end = start + r.nextInt();
- entry.rxBytes = nextPositiveLong(r);
- entry.rxPackets = nextPositiveLong(r);
- entry.txBytes = nextPositiveLong(r);
- entry.txPackets = nextPositiveLong(r);
- entry.operations = nextPositiveLong(r);
- stats.recordData(start, end, entry);
- } else {
- // trim something
- stats.removeBucketsBefore(r.nextLong());
- }
- }
- assertConsistent(stats);
- }
- } catch (Throwable e) {
- Log.e(TAG, String.valueOf(stats));
- throw new RuntimeException(e);
- }
- }
-
- private static long nextPositiveLong(Random r) {
- final long value = r.nextLong();
- return value < 0 ? -value : value;
- }
-
- @Test
- public void testIgnoreFields() throws Exception {
- final NetworkStatsHistory history = new NetworkStatsHistory(
- MINUTE_IN_MILLIS, 0, FIELD_RX_BYTES | FIELD_TX_BYTES);
-
- history.recordData(0, MINUTE_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
- history.recordData(0, 2 * MINUTE_IN_MILLIS,
- new NetworkStats.Entry(2L, 2L, 2L, 2L, 2L));
-
- assertFullValues(history, UNKNOWN, 1026L, UNKNOWN, 2050L, UNKNOWN, UNKNOWN);
- }
-
- @Test
- public void testIgnoreFieldsRecordIn() throws Exception {
- final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
- final NetworkStatsHistory partial = new NetworkStatsHistory(
- MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
-
- full.recordData(0, MINUTE_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
- partial.recordEntireHistory(full);
-
- assertFullValues(partial, UNKNOWN, UNKNOWN, 10L, UNKNOWN, UNKNOWN, 4L);
- }
-
- @Test
- public void testIgnoreFieldsRecordOut() throws Exception {
- final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
- final NetworkStatsHistory partial = new NetworkStatsHistory(
- MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS);
-
- partial.recordData(0, MINUTE_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
- full.recordEntireHistory(partial);
-
- assertFullValues(full, MINUTE_IN_MILLIS, 0L, 10L, 0L, 0L, 4L);
- }
-
- @Test
- public void testSerialize() throws Exception {
- final NetworkStatsHistory before = new NetworkStatsHistory(MINUTE_IN_MILLIS, 40, FIELD_ALL);
- before.recordData(0, 4 * MINUTE_IN_MILLIS,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L));
- before.recordData(DAY_IN_MILLIS, DAY_IN_MILLIS + MINUTE_IN_MILLIS,
- new NetworkStats.Entry(10L, 20L, 30L, 40L, 50L));
-
- final ByteArrayOutputStream out = new ByteArrayOutputStream();
- before.writeToStream(new DataOutputStream(out));
- out.close();
-
- final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
- final NetworkStatsHistory after = new NetworkStatsHistory(new DataInputStream(in));
-
- // must have identical totals before and after
- assertFullValues(before, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L);
- assertFullValues(after, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L);
- }
-
- @Test
- public void testVarLong() throws Exception {
- assertEquals(0L, performVarLong(0L));
- assertEquals(-1L, performVarLong(-1L));
- assertEquals(1024L, performVarLong(1024L));
- assertEquals(-1024L, performVarLong(-1024L));
- assertEquals(40 * MB_IN_BYTES, performVarLong(40 * MB_IN_BYTES));
- assertEquals(512 * GB_IN_BYTES, performVarLong(512 * GB_IN_BYTES));
- assertEquals(Long.MIN_VALUE, performVarLong(Long.MIN_VALUE));
- assertEquals(Long.MAX_VALUE, performVarLong(Long.MAX_VALUE));
- assertEquals(Long.MIN_VALUE + 40, performVarLong(Long.MIN_VALUE + 40));
- assertEquals(Long.MAX_VALUE - 40, performVarLong(Long.MAX_VALUE - 40));
- }
-
- @Test
- public void testIndexBeforeAfter() throws Exception {
- final long BUCKET_SIZE = HOUR_IN_MILLIS;
- stats = new NetworkStatsHistory(BUCKET_SIZE);
-
- final long FIRST_START = TEST_START;
- final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS);
- final long SECOND_START = TEST_START + WEEK_IN_MILLIS;
- final long SECOND_END = SECOND_START + HOUR_IN_MILLIS;
- final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS);
- final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
-
- stats.recordData(FIRST_START, FIRST_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
- stats.recordData(SECOND_START, SECOND_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
- stats.recordData(THIRD_START, THIRD_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
-
- // should have buckets: 2+1+2
- assertEquals(5, stats.size());
-
- assertIndexBeforeAfter(stats, 0, 0, Long.MIN_VALUE);
- assertIndexBeforeAfter(stats, 0, 1, FIRST_START);
- assertIndexBeforeAfter(stats, 0, 1, FIRST_START + MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 0, 2, FIRST_START + HOUR_IN_MILLIS);
- assertIndexBeforeAfter(stats, 1, 2, FIRST_START + HOUR_IN_MILLIS + MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 1, 2, FIRST_END - MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 1, 2, FIRST_END);
- assertIndexBeforeAfter(stats, 1, 2, FIRST_END + MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 1, 2, SECOND_START - MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 1, 3, SECOND_START);
- assertIndexBeforeAfter(stats, 2, 3, SECOND_END);
- assertIndexBeforeAfter(stats, 2, 3, SECOND_END + MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 2, 3, THIRD_START - MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 2, 4, THIRD_START);
- assertIndexBeforeAfter(stats, 3, 4, THIRD_START + MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 3, 4, THIRD_START + HOUR_IN_MILLIS);
- assertIndexBeforeAfter(stats, 4, 4, THIRD_END);
- assertIndexBeforeAfter(stats, 4, 4, THIRD_END + MINUTE_IN_MILLIS);
- assertIndexBeforeAfter(stats, 4, 4, Long.MAX_VALUE);
- }
-
- @Test
- public void testIntersects() throws Exception {
- final long BUCKET_SIZE = HOUR_IN_MILLIS;
- stats = new NetworkStatsHistory(BUCKET_SIZE);
-
- final long FIRST_START = TEST_START;
- final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS);
- final long SECOND_START = TEST_START + WEEK_IN_MILLIS;
- final long SECOND_END = SECOND_START + HOUR_IN_MILLIS;
- final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS);
- final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS);
-
- stats.recordData(FIRST_START, FIRST_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
- stats.recordData(SECOND_START, SECOND_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
- stats.recordData(THIRD_START, THIRD_END,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
-
- assertFalse(stats.intersects(10, 20));
- assertFalse(stats.intersects(TEST_START + YEAR_IN_MILLIS, TEST_START + YEAR_IN_MILLIS + 1));
- assertFalse(stats.intersects(Long.MAX_VALUE, Long.MIN_VALUE));
-
- assertTrue(stats.intersects(Long.MIN_VALUE, Long.MAX_VALUE));
- assertTrue(stats.intersects(10, TEST_START + YEAR_IN_MILLIS));
- assertTrue(stats.intersects(TEST_START, TEST_START));
- assertTrue(stats.intersects(TEST_START + DAY_IN_MILLIS, TEST_START + DAY_IN_MILLIS + 1));
- assertTrue(stats.intersects(TEST_START + DAY_IN_MILLIS, Long.MAX_VALUE));
- assertTrue(stats.intersects(TEST_START + 1, Long.MAX_VALUE));
-
- assertFalse(stats.intersects(Long.MIN_VALUE, TEST_START - 1));
- assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START));
- assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START + 1));
- }
-
- @Test
- public void testSetValues() throws Exception {
- stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
- stats.recordData(TEST_START, TEST_START + 1,
- new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
-
- assertEquals(1024L + 2048L, stats.getTotalBytes());
-
- final NetworkStatsHistory.Entry entry = stats.getValues(0, null);
- entry.rxBytes /= 2;
- entry.txBytes *= 2;
- stats.setValues(0, entry);
-
- assertEquals(512L + 4096L, stats.getTotalBytes());
- }
-
- private static void assertIndexBeforeAfter(
- NetworkStatsHistory stats, int before, int after, long time) {
- assertEquals("unexpected before", before, stats.getIndexBefore(time));
- assertEquals("unexpected after", after, stats.getIndexAfter(time));
- }
-
- private static long performVarLong(long before) throws Exception {
- final ByteArrayOutputStream out = new ByteArrayOutputStream();
- writeVarLong(new DataOutputStream(out), before);
-
- final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
- return readVarLong(new DataInputStream(in));
- }
-
- private static void assertConsistent(NetworkStatsHistory stats) {
- // verify timestamps are monotonic
- long lastStart = Long.MIN_VALUE;
- NetworkStatsHistory.Entry entry = null;
- for (int i = 0; i < stats.size(); i++) {
- entry = stats.getValues(i, entry);
- assertTrue(lastStart < entry.bucketStart);
- lastStart = entry.bucketStart;
- }
- }
-
- private static void assertValues(
- NetworkStatsHistory stats, int index, long rxBytes, long txBytes) {
- final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- }
-
- private static void assertValues(
- NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) {
- final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- }
-
- private static void assertValues(NetworkStatsHistory stats, int index, long activeTime,
- long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
- final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
- assertEquals("unexpected activeTime", activeTime, entry.activeTime);
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- assertEquals("unexpected txPackets", txPackets, entry.txPackets);
- assertEquals("unexpected operations", operations, entry.operations);
- }
-
- private static void assertFullValues(NetworkStatsHistory stats, long activeTime, long rxBytes,
- long rxPackets, long txBytes, long txPackets, long operations) {
- assertValues(stats, Long.MIN_VALUE, Long.MAX_VALUE, activeTime, rxBytes, rxPackets, txBytes,
- txPackets, operations);
- }
-
- private static void assertValues(NetworkStatsHistory stats, long start, long end,
- long activeTime, long rxBytes, long rxPackets, long txBytes, long txPackets,
- long operations) {
- final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
- assertEquals("unexpected activeTime", activeTime, entry.activeTime);
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- assertEquals("unexpected txPackets", txPackets, entry.txPackets);
- assertEquals("unexpected operations", operations, entry.operations);
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/NetworkStatsTest.java b/packages/Connectivity/tests/unit/java/android/net/NetworkStatsTest.java
deleted file mode 100644
index 23d5a7e..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/NetworkStatsTest.java
+++ /dev/null
@@ -1,1024 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
-import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
-import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
-import static android.net.NetworkStats.IFACE_ALL;
-import static android.net.NetworkStats.INTERFACES_ALL;
-import static android.net.NetworkStats.METERED_ALL;
-import static android.net.NetworkStats.METERED_NO;
-import static android.net.NetworkStats.METERED_YES;
-import static android.net.NetworkStats.ROAMING_ALL;
-import static android.net.NetworkStats.ROAMING_NO;
-import static android.net.NetworkStats.ROAMING_YES;
-import static android.net.NetworkStats.SET_ALL;
-import static android.net.NetworkStats.SET_DBG_VPN_IN;
-import static android.net.NetworkStats.SET_DBG_VPN_OUT;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.SET_FOREGROUND;
-import static android.net.NetworkStats.TAG_ALL;
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkStats.UID_ALL;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.os.Process;
-import android.util.ArrayMap;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.google.android.collect.Sets;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-import java.util.HashSet;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkStatsTest {
-
- private static final String TEST_IFACE = "test0";
- private static final String TEST_IFACE2 = "test2";
- private static final int TEST_UID = 1001;
- private static final long TEST_START = 1194220800000L;
-
- @Test
- public void testFindIndex() throws Exception {
- final NetworkStats stats = new NetworkStats(TEST_START, 5)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1024L, 8L, 0L, 0L, 10)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 0L, 0L, 1024L, 8L, 11)
- .insertEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 12)
- .insertEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
- DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12);
-
- assertEquals(4, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES,
- ROAMING_YES, DEFAULT_NETWORK_YES));
- assertEquals(3, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO));
- assertEquals(2, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES,
- ROAMING_NO, DEFAULT_NETWORK_YES));
- assertEquals(1, stats.findIndex(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO));
- assertEquals(0, stats.findIndex(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_YES));
- assertEquals(-1, stats.findIndex(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO));
- assertEquals(-1, stats.findIndex(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO));
- }
-
- @Test
- public void testFindIndexHinted() {
- final NetworkStats stats = new NetworkStats(TEST_START, 3)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1024L, 8L, 0L, 0L, 10)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11)
- .insertEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12)
- .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1024L, 8L, 0L, 0L, 10)
- .insertEntry(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 0L, 0L, 1024L, 8L, 11)
- .insertEntry(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11)
- .insertEntry(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12)
- .insertEntry(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
- DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 12);
-
- // verify that we correctly find across regardless of hinting
- for (int hint = 0; hint < stats.size(); hint++) {
- assertEquals(0, stats.findIndexHinted(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, hint));
- assertEquals(1, stats.findIndexHinted(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, hint));
- assertEquals(2, stats.findIndexHinted(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, hint));
- assertEquals(3, stats.findIndexHinted(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, hint));
- assertEquals(4, stats.findIndexHinted(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, hint));
- assertEquals(5, stats.findIndexHinted(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D,
- METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, hint));
- assertEquals(6, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, hint));
- assertEquals(7, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
- METERED_YES, ROAMING_YES, DEFAULT_NETWORK_NO, hint));
- assertEquals(-1, stats.findIndexHinted(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE,
- METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, hint));
- assertEquals(-1, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE,
- METERED_YES, ROAMING_YES, DEFAULT_NETWORK_YES, hint));
- }
- }
-
- @Test
- public void testAddEntryGrow() throws Exception {
- final NetworkStats stats = new NetworkStats(TEST_START, 4);
-
- assertEquals(0, stats.size());
- assertEquals(4, stats.internalSize());
-
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1L, 1L, 2L, 2L, 3);
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 2L, 2L, 2L, 2L, 4);
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
- DEFAULT_NETWORK_YES, 3L, 3L, 2L, 2L, 5);
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
- DEFAULT_NETWORK_NO, 3L, 3L, 2L, 2L, 5);
-
- assertEquals(4, stats.size());
- assertEquals(4, stats.internalSize());
-
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 4L, 40L, 4L, 40L, 7);
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 5L, 50L, 4L, 40L, 8);
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 6L, 60L, 5L, 50L, 10);
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
- DEFAULT_NETWORK_YES, 7L, 70L, 5L, 50L, 11);
- stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES,
- DEFAULT_NETWORK_NO, 7L, 70L, 5L, 50L, 11);
-
- assertEquals(9, stats.size());
- assertTrue(stats.internalSize() >= 9);
-
- assertValues(stats, 0, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1L, 1L, 2L, 2L, 3);
- assertValues(stats, 1, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 2L, 2L, 2L, 2L, 4);
- assertValues(stats, 2, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
- DEFAULT_NETWORK_YES, 3L, 3L, 2L, 2L, 5);
- assertValues(stats, 3, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES,
- ROAMING_YES, DEFAULT_NETWORK_NO, 3L, 3L, 2L, 2L, 5);
- assertValues(stats, 4, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 4L, 40L, 4L, 40L, 7);
- assertValues(stats, 5, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 5L, 50L, 4L, 40L, 8);
- assertValues(stats, 6, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 6L, 60L, 5L, 50L, 10);
- assertValues(stats, 7, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
- DEFAULT_NETWORK_YES, 7L, 70L, 5L, 50L, 11);
- assertValues(stats, 8, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES,
- ROAMING_YES, DEFAULT_NETWORK_NO, 7L, 70L, 5L, 50L, 11);
- }
-
- @Test
- public void testCombineExisting() throws Exception {
- final NetworkStats stats = new NetworkStats(TEST_START, 10);
-
- stats.insertEntry(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 10);
- stats.insertEntry(TEST_IFACE, 1001, SET_DEFAULT, 0xff, 128L, 1L, 128L, 1L, 2);
- stats.combineValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, -128L, -1L,
- -128L, -1L, -1);
-
- assertValues(stats, 0, TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 384L, 3L, 128L, 1L, 9);
- assertValues(stats, 1, TEST_IFACE, 1001, SET_DEFAULT, 0xff, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 128L, 1L, 128L, 1L, 2);
-
- // now try combining that should create row
- stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 3);
- assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 128L, 1L, 128L, 1L, 3);
- stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 3);
- assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 256L, 2L, 256L, 2L, 6);
- }
-
- @Test
- public void testSubtractIdenticalData() throws Exception {
- final NetworkStats before = new NetworkStats(TEST_START, 2)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
-
- final NetworkStats after = new NetworkStats(TEST_START, 2)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
-
- final NetworkStats result = after.subtract(before);
-
- // identical data should result in zero delta
- assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0);
- assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0);
- }
-
- @Test
- public void testSubtractIdenticalRows() throws Exception {
- final NetworkStats before = new NetworkStats(TEST_START, 2)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
-
- final NetworkStats after = new NetworkStats(TEST_START, 2)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1025L, 9L, 2L, 1L, 15)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 3L, 1L, 1028L, 9L, 20);
-
- final NetworkStats result = after.subtract(before);
-
- // expect delta between measurements
- assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1L, 1L, 2L, 1L, 4);
- assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 3L, 1L, 4L, 1L, 8);
- }
-
- @Test
- public void testSubtractNewRows() throws Exception {
- final NetworkStats before = new NetworkStats(TEST_START, 2)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12);
-
- final NetworkStats after = new NetworkStats(TEST_START, 3)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12)
- .insertEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20);
-
- final NetworkStats result = after.subtract(before);
-
- // its okay to have new rows
- assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0);
- assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0);
- assertValues(result, 2, TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 20);
- }
-
- @Test
- public void testSubtractMissingRows() throws Exception {
- final NetworkStats before = new NetworkStats(TEST_START, 2)
- .insertEntry(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0)
- .insertEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2048L, 0L, 0L, 0L, 0);
-
- final NetworkStats after = new NetworkStats(TEST_START, 1)
- .insertEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2049L, 2L, 3L, 4L, 0);
-
- final NetworkStats result = after.subtract(before);
-
- // should silently drop omitted rows
- assertEquals(1, result.size());
- assertValues(result, 0, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 1L, 2L, 3L, 4L, 0);
- assertEquals(4L, result.getTotalBytes());
- }
-
- @Test
- public void testTotalBytes() throws Exception {
- final NetworkStats iface = new NetworkStats(TEST_START, 2)
- .insertEntry(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 256L, 0L, 0L, 0L, 0L);
- assertEquals(384L, iface.getTotalBytes());
-
- final NetworkStats uidSet = new NetworkStats(TEST_START, 3)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L);
- assertEquals(96L, uidSet.getTotalBytes());
-
- final NetworkStats uidTag = new NetworkStats(TEST_START, 6)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L);
- assertEquals(64L, uidTag.getTotalBytes());
-
- final NetworkStats uidMetered = new NetworkStats(TEST_START, 3)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
- assertEquals(96L, uidMetered.getTotalBytes());
-
- final NetworkStats uidRoaming = new NetworkStats(TEST_START, 3)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
- DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
- assertEquals(96L, uidRoaming.getTotalBytes());
- }
-
- @Test
- public void testGroupedByIfaceEmpty() throws Exception {
- final NetworkStats uidStats = new NetworkStats(TEST_START, 3);
- final NetworkStats grouped = uidStats.groupedByIface();
-
- assertEquals(0, uidStats.size());
- assertEquals(0, grouped.size());
- }
-
- @Test
- public void testGroupedByIfaceAll() throws Exception {
- final NetworkStats uidStats = new NetworkStats(TEST_START, 3)
- .insertEntry(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L)
- .insertEntry(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_NO, 128L, 8L, 0L, 2L, 20L)
- .insertEntry(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES,
- DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L);
- final NetworkStats grouped = uidStats.groupedByIface();
-
- assertEquals(3, uidStats.size());
- assertEquals(1, grouped.size());
-
- assertValues(grouped, 0, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 384L, 24L, 0L, 6L, 0L);
- }
-
- @Test
- public void testGroupedByIface() throws Exception {
- final NetworkStats uidStats = new NetworkStats(TEST_START, 7)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 4L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
- DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L);
-
- final NetworkStats grouped = uidStats.groupedByIface();
-
- assertEquals(7, uidStats.size());
-
- assertEquals(2, grouped.size());
- assertValues(grouped, 0, TEST_IFACE, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 384L, 24L, 0L, 2L, 0L);
- assertValues(grouped, 1, TEST_IFACE2, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 1024L, 64L, 0L, 0L, 0L);
- }
-
- @Test
- public void testAddAllValues() {
- final NetworkStats first = new NetworkStats(TEST_START, 5)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
- DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
-
- final NetworkStats second = new NetworkStats(TEST_START, 2)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
- DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L);
-
- first.combineAllValues(second);
-
- assertEquals(4, first.size());
- assertValues(first, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 0L, 0L, 0L, 0L);
- assertValues(first, 1, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L);
- assertValues(first, 2, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES,
- DEFAULT_NETWORK_YES, 64L, 0L, 0L, 0L, 0L);
- assertValues(first, 3, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L);
- }
-
- @Test
- public void testGetTotal() {
- final NetworkStats stats = new NetworkStats(TEST_START, 7)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 4L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 512L,32L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES,
- DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L);
-
- assertValues(stats.getTotal(null), 1408L, 88L, 0L, 2L, 20L);
- assertValues(stats.getTotal(null, 100), 1280L, 80L, 0L, 2L, 20L);
- assertValues(stats.getTotal(null, 101), 128L, 8L, 0L, 0L, 0L);
-
- final HashSet<String> ifaces = Sets.newHashSet();
- assertValues(stats.getTotal(null, ifaces), 0L, 0L, 0L, 0L, 0L);
-
- ifaces.add(TEST_IFACE2);
- assertValues(stats.getTotal(null, ifaces), 1024L, 64L, 0L, 0L, 0L);
- }
-
- @Test
- public void testRemoveUids() throws Exception {
- final NetworkStats before = new NetworkStats(TEST_START, 3);
-
- // Test 0 item stats.
- NetworkStats after = before.clone();
- after.removeUids(new int[0]);
- assertEquals(0, after.size());
- after.removeUids(new int[] {100});
- assertEquals(0, after.size());
-
- // Test 1 item stats.
- before.insertEntry(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, 1L, 128L, 0L, 2L, 20L);
- after = before.clone();
- after.removeUids(new int[0]);
- assertEquals(1, after.size());
- assertValues(after, 0, TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1L, 128L, 0L, 2L, 20L);
- after.removeUids(new int[] {99});
- assertEquals(0, after.size());
-
- // Append remaining test items.
- before.insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 16L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 8L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 4L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 64L, 2L, 0L, 0L, 0L);
- assertEquals(7, before.size());
-
- // Test remove with empty uid list.
- after = before.clone();
- after.removeUids(new int[0]);
- assertValues(after.getTotalIncludingTags(null), 127L, 254L, 0L, 4L, 40L);
-
- // Test remove uids don't exist in stats.
- after.removeUids(new int[] {98, 0, Integer.MIN_VALUE, Integer.MAX_VALUE});
- assertValues(after.getTotalIncludingTags(null), 127L, 254L, 0L, 4L, 40L);
-
- // Test remove all uids.
- after.removeUids(new int[] {99, 100, 100, 101});
- assertEquals(0, after.size());
-
- // Test remove in the middle.
- after = before.clone();
- after.removeUids(new int[] {100});
- assertEquals(3, after.size());
- assertValues(after, 0, TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1L, 128L, 0L, 2L, 20L);
- assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 32L, 4L, 0L, 0L, 0L);
- assertValues(after, 2, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 64L, 2L, 0L, 0L, 0L);
- }
-
- @Test
- public void testRemoveEmptyEntries() throws Exception {
- // Test empty stats.
- final NetworkStats statsEmpty = new NetworkStats(TEST_START, 3);
- assertEquals(0, statsEmpty.removeEmptyEntries().size());
-
- // Test stats with non-zero entry.
- final NetworkStats statsNonZero = new NetworkStats(TEST_START, 1)
- .insertEntry(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 1L, 128L, 0L, 2L, 20L);
- assertEquals(1, statsNonZero.size());
- final NetworkStats expectedNonZero = statsNonZero.removeEmptyEntries();
- assertEquals(1, expectedNonZero.size());
- assertValues(expectedNonZero, 0, TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 1L, 128L, 0L, 2L, 20L);
-
- // Test stats with empty entry.
- final NetworkStats statsZero = new NetworkStats(TEST_START, 1)
- .insertEntry(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
- assertEquals(1, statsZero.size());
- final NetworkStats expectedZero = statsZero.removeEmptyEntries();
- assertEquals(1, statsZero.size()); // Assert immutable.
- assertEquals(0, expectedZero.size());
-
- // Test stats with multiple entries.
- final NetworkStats statsMultiple = new NetworkStats(TEST_START, 0)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 0L, 8L, 0L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 4L, 0L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 0L, 2L, 0L)
- .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 0L, 0L, 1L);
- assertEquals(9, statsMultiple.size());
- final NetworkStats expectedMultiple = statsMultiple.removeEmptyEntries();
- assertEquals(9, statsMultiple.size()); // Assert immutable.
- assertEquals(7, expectedMultiple.size());
- assertValues(expectedMultiple.getTotalIncludingTags(null), 14L, 104L, 4L, 4L, 21L);
-
- // Test stats with multiple empty entries.
- assertEquals(statsMultiple.size(), statsMultiple.subtract(statsMultiple).size());
- assertEquals(0, statsMultiple.subtract(statsMultiple).removeEmptyEntries().size());
- }
-
- @Test
- public void testClone() throws Exception {
- final NetworkStats original = new NetworkStats(TEST_START, 5)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L);
-
- // make clone and mutate original
- final NetworkStats clone = original.clone();
- original.insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L);
-
- assertEquals(3, original.size());
- assertEquals(2, clone.size());
-
- assertEquals(128L + 512L + 128L, original.getTotalBytes());
- assertEquals(128L + 512L, clone.getTotalBytes());
- }
-
- @Test
- public void testAddWhenEmpty() throws Exception {
- final NetworkStats red = new NetworkStats(TEST_START, -1);
- final NetworkStats blue = new NetworkStats(TEST_START, 5)
- .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L)
- .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L);
-
- // We're mostly checking that we don't crash
- red.combineAllValues(blue);
- }
-
- @Test
- public void testMigrateTun() throws Exception {
- final int tunUid = 10030;
- final String tunIface = "tun0";
- final String underlyingIface = "wlan0";
- final int testTag1 = 8888;
- NetworkStats delta = new NetworkStats(TEST_START, 17)
- .insertEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 39605L, 46L, 12259L, 55L, 0L)
- .insertEntry(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
- .insertEntry(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 72667L, 197L, 43909L, 241L, 0L)
- .insertEntry(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 9297L, 17L, 4128L, 21L, 0L)
- // VPN package also uses some traffic through unprotected network.
- .insertEntry(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 4983L, 10L, 1801L, 12L, 0L)
- .insertEntry(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
- // Tag entries
- .insertEntry(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 21691L, 41L, 13820L, 51L, 0L)
- .insertEntry(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1281L, 2L, 665L, 2L, 0L)
- // Irrelevant entries
- .insertEntry(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1685L, 5L, 2070L, 6L, 0L)
- // Underlying Iface entries
- .insertEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 5178L, 8L, 2139L, 11L, 0L)
- .insertEntry(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L)
- .insertEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 149873L, 287L, 59217L /* smaller than sum(tun0) */,
- 299L /* smaller than sum(tun0) */, 0L)
- .insertEntry(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
-
- delta.migrateTun(tunUid, tunIface, Arrays.asList(underlyingIface));
- assertEquals(20, delta.size());
-
- // tunIface and TEST_IFACE entries are not changed.
- assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 39605L, 46L, 12259L, 55L, 0L);
- assertValues(delta, 1, tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
- assertValues(delta, 2, tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 72667L, 197L, 43909L, 241L, 0L);
- assertValues(delta, 3, tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 9297L, 17L, 4128L, 21L, 0L);
- assertValues(delta, 4, tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 4983L, 10L, 1801L, 12L, 0L);
- assertValues(delta, 5, tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
- assertValues(delta, 6, tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 21691L, 41L, 13820L, 51L, 0L);
- assertValues(delta, 7, tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1281L, 2L, 665L, 2L, 0L);
- assertValues(delta, 8, TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1685L, 5L, 2070L, 6L, 0L);
-
- // Existing underlying Iface entries are updated
- assertValues(delta, 9, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 44783L, 54L, 14178L, 62L, 0L);
- assertValues(delta, 10, underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
-
- // VPN underlying Iface entries are updated
- assertValues(delta, 11, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 28304L, 27L, 1L, 2L, 0L);
- assertValues(delta, 12, underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L);
-
- // New entries are added for new application's underlying Iface traffic
- assertContains(delta, underlyingIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 72667L, 197L, 43123L, 227L, 0L);
- assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 9297L, 17L, 4054, 19L, 0L);
- assertContains(delta, underlyingIface, 10120, SET_DEFAULT, testTag1, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 21691L, 41L, 13572L, 48L, 0L);
- assertContains(delta, underlyingIface, 10120, SET_FOREGROUND, testTag1, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 1281L, 2L, 653L, 1L, 0L);
-
- // New entries are added for debug purpose
- assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 39605L, 46L, 12039, 51, 0);
- assertContains(delta, underlyingIface, 10120, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 81964, 214, 47177, 246, 0);
- assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, METERED_ALL,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, 121569, 260, 59216, 297, 0);
-
- }
-
- // Tests a case where all of the data received by the tun0 interface is echo back into the tun0
- // interface by the vpn app before it's sent out of the underlying interface. The VPN app should
- // not be charged for the echoed data but it should still be charged for any extra data it sends
- // via the underlying interface.
- @Test
- public void testMigrateTun_VpnAsLoopback() {
- final int tunUid = 10030;
- final String tunIface = "tun0";
- final String underlyingIface = "wlan0";
- NetworkStats delta = new NetworkStats(TEST_START, 9)
- // 2 different apps sent/receive data via tun0.
- .insertEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L)
- .insertEntry(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L)
- // VPN package resends data through the tunnel (with exaggerated overhead)
- .insertEntry(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 240000, 100L, 120000L, 60L, 0L)
- // 1 app already has some traffic on the underlying interface, the other doesn't yet
- .insertEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 1000L, 10L, 2000L, 20L, 0L)
- // Traffic through the underlying interface via the vpn app.
- // This test should redistribute this data correctly.
- .insertEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 75500L, 37L, 130000L, 70L, 0L);
-
- delta.migrateTun(tunUid, tunIface, Arrays.asList(underlyingIface));
- assertEquals(9, delta.size());
-
- // tunIface entries should not be changed.
- assertValues(delta, 0, tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
- assertValues(delta, 1, tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L);
- assertValues(delta, 2, tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 240000L, 100L, 120000L, 60L, 0L);
-
- // Existing underlying Iface entries are updated
- assertValues(delta, 3, underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 51000L, 35L, 102000L, 70L, 0L);
-
- // VPN underlying Iface entries are updated
- assertValues(delta, 4, underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 25000L, 10L, 29800L, 15L, 0L);
-
- // New entries are added for new application's underlying Iface traffic
- assertContains(delta, underlyingIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L);
-
- // New entries are added for debug purpose
- assertContains(delta, underlyingIface, 10100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
- assertContains(delta, underlyingIface, 20100, SET_DBG_VPN_IN, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, 500, 2L, 200L, 5L, 0L);
- assertContains(delta, underlyingIface, tunUid, SET_DBG_VPN_OUT, TAG_NONE, METERED_ALL,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, 50500L, 27L, 100200L, 55, 0);
- }
-
- @Test
- public void testFilter_NoFilter() {
- NetworkStats.Entry entry1 = new NetworkStats.Entry(
- "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry2 = new NetworkStats.Entry(
- "test2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry3 = new NetworkStats.Entry(
- "test2", 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats stats = new NetworkStats(TEST_START, 3)
- .insertEntry(entry1)
- .insertEntry(entry2)
- .insertEntry(entry3);
-
- stats.filter(UID_ALL, INTERFACES_ALL, TAG_ALL);
- assertEquals(3, stats.size());
- assertEquals(entry1, stats.getValues(0, null));
- assertEquals(entry2, stats.getValues(1, null));
- assertEquals(entry3, stats.getValues(2, null));
- }
-
- @Test
- public void testFilter_UidFilter() {
- final int testUid = 10101;
- NetworkStats.Entry entry1 = new NetworkStats.Entry(
- "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry2 = new NetworkStats.Entry(
- "test2", testUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry3 = new NetworkStats.Entry(
- "test2", testUid, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats stats = new NetworkStats(TEST_START, 3)
- .insertEntry(entry1)
- .insertEntry(entry2)
- .insertEntry(entry3);
-
- stats.filter(testUid, INTERFACES_ALL, TAG_ALL);
- assertEquals(2, stats.size());
- assertEquals(entry2, stats.getValues(0, null));
- assertEquals(entry3, stats.getValues(1, null));
- }
-
- @Test
- public void testFilter_InterfaceFilter() {
- final String testIf1 = "testif1";
- final String testIf2 = "testif2";
- NetworkStats.Entry entry1 = new NetworkStats.Entry(
- testIf1, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry2 = new NetworkStats.Entry(
- "otherif", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry3 = new NetworkStats.Entry(
- testIf1, 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry4 = new NetworkStats.Entry(
- testIf2, 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats stats = new NetworkStats(TEST_START, 4)
- .insertEntry(entry1)
- .insertEntry(entry2)
- .insertEntry(entry3)
- .insertEntry(entry4);
-
- stats.filter(UID_ALL, new String[] { testIf1, testIf2 }, TAG_ALL);
- assertEquals(3, stats.size());
- assertEquals(entry1, stats.getValues(0, null));
- assertEquals(entry3, stats.getValues(1, null));
- assertEquals(entry4, stats.getValues(2, null));
- }
-
- @Test
- public void testFilter_EmptyInterfaceFilter() {
- NetworkStats.Entry entry1 = new NetworkStats.Entry(
- "if1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry2 = new NetworkStats.Entry(
- "if2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats stats = new NetworkStats(TEST_START, 3)
- .insertEntry(entry1)
- .insertEntry(entry2);
-
- stats.filter(UID_ALL, new String[] { }, TAG_ALL);
- assertEquals(0, stats.size());
- }
-
- @Test
- public void testFilter_TagFilter() {
- final int testTag = 123;
- final int otherTag = 456;
- NetworkStats.Entry entry1 = new NetworkStats.Entry(
- "test1", 10100, SET_DEFAULT, testTag, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry2 = new NetworkStats.Entry(
- "test2", 10101, SET_DEFAULT, testTag, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry3 = new NetworkStats.Entry(
- "test2", 10101, SET_DEFAULT, otherTag, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats stats = new NetworkStats(TEST_START, 3)
- .insertEntry(entry1)
- .insertEntry(entry2)
- .insertEntry(entry3);
-
- stats.filter(UID_ALL, INTERFACES_ALL, testTag);
- assertEquals(2, stats.size());
- assertEquals(entry1, stats.getValues(0, null));
- assertEquals(entry2, stats.getValues(1, null));
- }
-
- @Test
- public void testFilterDebugEntries() {
- NetworkStats.Entry entry1 = new NetworkStats.Entry(
- "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry2 = new NetworkStats.Entry(
- "test2", 10101, SET_DBG_VPN_IN, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry3 = new NetworkStats.Entry(
- "test2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats.Entry entry4 = new NetworkStats.Entry(
- "test2", 10101, SET_DBG_VPN_OUT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L);
-
- NetworkStats stats = new NetworkStats(TEST_START, 4)
- .insertEntry(entry1)
- .insertEntry(entry2)
- .insertEntry(entry3)
- .insertEntry(entry4);
-
- stats.filterDebugEntries();
-
- assertEquals(2, stats.size());
- assertEquals(entry1, stats.getValues(0, null));
- assertEquals(entry3, stats.getValues(1, null));
- }
-
- @Test
- public void testApply464xlatAdjustments() {
- final String v4Iface = "v4-wlan0";
- final String baseIface = "wlan0";
- final String otherIface = "other";
- final int appUid = 10001;
- final int rootUid = Process.ROOT_UID;
- ArrayMap<String, String> stackedIface = new ArrayMap<>();
- stackedIface.put(v4Iface, baseIface);
-
- // Ipv4 traffic sent/received by an app on stacked interface.
- final NetworkStats.Entry appEntry = new NetworkStats.Entry(
- v4Iface, appUid, SET_DEFAULT, TAG_NONE,
- 30501490 /* rxBytes */,
- 22401 /* rxPackets */,
- 876235 /* txBytes */,
- 13805 /* txPackets */,
- 0 /* operations */);
-
- // Traffic measured for the root uid on the base interface.
- final NetworkStats.Entry rootUidEntry = new NetworkStats.Entry(
- baseIface, rootUid, SET_DEFAULT, TAG_NONE,
- 163577 /* rxBytes */,
- 187 /* rxPackets */,
- 17607 /* txBytes */,
- 97 /* txPackets */,
- 0 /* operations */);
-
- final NetworkStats.Entry otherEntry = new NetworkStats.Entry(
- otherIface, appUid, SET_DEFAULT, TAG_NONE,
- 2600 /* rxBytes */,
- 2 /* rxPackets */,
- 3800 /* txBytes */,
- 3 /* txPackets */,
- 0 /* operations */);
-
- final NetworkStats stats = new NetworkStats(TEST_START, 3)
- .insertEntry(appEntry)
- .insertEntry(rootUidEntry)
- .insertEntry(otherEntry);
-
- stats.apply464xlatAdjustments(stackedIface);
-
- assertEquals(3, stats.size());
- final NetworkStats.Entry expectedAppUid = new NetworkStats.Entry(
- v4Iface, appUid, SET_DEFAULT, TAG_NONE,
- 30949510,
- 22401,
- 1152335,
- 13805,
- 0);
- final NetworkStats.Entry expectedRootUid = new NetworkStats.Entry(
- baseIface, 0, SET_DEFAULT, TAG_NONE,
- 163577,
- 187,
- 17607,
- 97,
- 0);
- assertEquals(expectedAppUid, stats.getValues(0, null));
- assertEquals(expectedRootUid, stats.getValues(1, null));
- assertEquals(otherEntry, stats.getValues(2, null));
- }
-
- @Test
- public void testApply464xlatAdjustments_noStackedIface() {
- NetworkStats.Entry firstEntry = new NetworkStats.Entry(
- "if1", 10002, SET_DEFAULT, TAG_NONE,
- 2600 /* rxBytes */,
- 2 /* rxPackets */,
- 3800 /* txBytes */,
- 3 /* txPackets */,
- 0 /* operations */);
- NetworkStats.Entry secondEntry = new NetworkStats.Entry(
- "if2", 10002, SET_DEFAULT, TAG_NONE,
- 5000 /* rxBytes */,
- 3 /* rxPackets */,
- 6000 /* txBytes */,
- 4 /* txPackets */,
- 0 /* operations */);
-
- NetworkStats stats = new NetworkStats(TEST_START, 2)
- .insertEntry(firstEntry)
- .insertEntry(secondEntry);
-
- // Empty map: no adjustment
- stats.apply464xlatAdjustments(new ArrayMap<>());
-
- assertEquals(2, stats.size());
- assertEquals(firstEntry, stats.getValues(0, null));
- assertEquals(secondEntry, stats.getValues(1, null));
- }
-
- private static void assertContains(NetworkStats stats, String iface, int uid, int set,
- int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
- long txBytes, long txPackets, long operations) {
- int index = stats.findIndex(iface, uid, set, tag, metered, roaming, defaultNetwork);
- assertTrue(index != -1);
- assertValues(stats, index, iface, uid, set, tag, metered, roaming, defaultNetwork,
- rxBytes, rxPackets, txBytes, txPackets, operations);
- }
-
- private static void assertValues(NetworkStats stats, int index, String iface, int uid, int set,
- int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
- long txBytes, long txPackets, long operations) {
- final NetworkStats.Entry entry = stats.getValues(index, null);
- assertValues(entry, iface, uid, set, tag, metered, roaming, defaultNetwork);
- assertValues(entry, rxBytes, rxPackets, txBytes, txPackets, operations);
- }
-
- private static void assertValues(
- NetworkStats.Entry entry, String iface, int uid, int set, int tag, int metered,
- int roaming, int defaultNetwork) {
- assertEquals(iface, entry.iface);
- assertEquals(uid, entry.uid);
- assertEquals(set, entry.set);
- assertEquals(tag, entry.tag);
- assertEquals(metered, entry.metered);
- assertEquals(roaming, entry.roaming);
- assertEquals(defaultNetwork, entry.defaultNetwork);
- }
-
- private static void assertValues(NetworkStats.Entry entry, long rxBytes, long rxPackets,
- long txBytes, long txPackets, long operations) {
- assertEquals(rxBytes, entry.rxBytes);
- assertEquals(rxPackets, entry.rxPackets);
- assertEquals(txBytes, entry.txBytes);
- assertEquals(txPackets, entry.txPackets);
- assertEquals(operations, entry.operations);
- }
-
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/NetworkTemplateTest.kt b/packages/Connectivity/tests/unit/java/android/net/NetworkTemplateTest.kt
deleted file mode 100644
index cb39a0c..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/NetworkTemplateTest.kt
+++ /dev/null
@@ -1,365 +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.net
-
-import android.content.Context
-import android.net.ConnectivityManager.TYPE_MOBILE
-import android.net.ConnectivityManager.TYPE_WIFI
-import android.net.NetworkIdentity.SUBTYPE_COMBINED
-import android.net.NetworkIdentity.OEM_NONE
-import android.net.NetworkIdentity.OEM_PAID
-import android.net.NetworkIdentity.OEM_PRIVATE
-import android.net.NetworkIdentity.buildNetworkIdentity
-import android.net.NetworkStats.DEFAULT_NETWORK_ALL
-import android.net.NetworkStats.METERED_ALL
-import android.net.NetworkStats.ROAMING_ALL
-import android.net.NetworkTemplate.MATCH_MOBILE
-import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD
-import android.net.NetworkTemplate.MATCH_WIFI
-import android.net.NetworkTemplate.MATCH_WIFI_WILDCARD
-import android.net.NetworkTemplate.WIFI_NETWORKID_ALL
-import android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA
-import android.net.NetworkTemplate.NETWORK_TYPE_ALL
-import android.net.NetworkTemplate.OEM_MANAGED_ALL
-import android.net.NetworkTemplate.OEM_MANAGED_NO
-import android.net.NetworkTemplate.OEM_MANAGED_YES
-import android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT
-import android.net.NetworkTemplate.buildTemplateWifi
-import android.net.NetworkTemplate.buildTemplateWifiWildcard
-import android.net.NetworkTemplate.buildTemplateCarrierMetered
-import android.net.NetworkTemplate.buildTemplateMobileWithRatType
-import android.telephony.TelephonyManager
-import com.android.testutils.assertParcelSane
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import org.mockito.Mockito.mock
-import org.mockito.MockitoAnnotations
-import kotlin.test.assertEquals
-import kotlin.test.assertFalse
-import kotlin.test.assertNotEquals
-import kotlin.test.assertTrue
-
-private const val TEST_IMSI1 = "imsi1"
-private const val TEST_IMSI2 = "imsi2"
-private const val TEST_SSID1 = "ssid1"
-private const val TEST_SSID2 = "ssid2"
-
-@RunWith(JUnit4::class)
-class NetworkTemplateTest {
- private val mockContext = mock(Context::class.java)
-
- private fun buildMobileNetworkState(subscriberId: String): NetworkStateSnapshot =
- buildNetworkState(TYPE_MOBILE, subscriberId = subscriberId)
- private fun buildWifiNetworkState(subscriberId: String?, ssid: String?): NetworkStateSnapshot =
- buildNetworkState(TYPE_WIFI, subscriberId = subscriberId, ssid = ssid)
-
- private fun buildNetworkState(
- type: Int,
- subscriberId: String? = null,
- ssid: String? = null,
- oemManaged: Int = OEM_NONE,
- metered: Boolean = true
- ): NetworkStateSnapshot {
- val lp = LinkProperties()
- val caps = NetworkCapabilities().apply {
- setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, !metered)
- setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true)
- setSSID(ssid)
- setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID,
- (oemManaged and OEM_PAID) == OEM_PAID)
- setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
- (oemManaged and OEM_PRIVATE) == OEM_PRIVATE)
- }
- return NetworkStateSnapshot(mock(Network::class.java), caps, lp, subscriberId, type)
- }
-
- private fun NetworkTemplate.assertMatches(ident: NetworkIdentity) =
- assertTrue(matches(ident), "$this does not match $ident")
-
- private fun NetworkTemplate.assertDoesNotMatch(ident: NetworkIdentity) =
- assertFalse(matches(ident), "$this should match $ident")
-
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
- }
-
- @Test
- fun testWifiWildcardMatches() {
- val templateWifiWildcard = buildTemplateWifiWildcard()
-
- val identMobileImsi1 = buildNetworkIdentity(mockContext,
- buildMobileNetworkState(TEST_IMSI1),
- false, TelephonyManager.NETWORK_TYPE_UMTS)
- val identWifiImsiNullSsid1 = buildNetworkIdentity(
- mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0)
- val identWifiImsi1Ssid1 = buildNetworkIdentity(
- mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0)
-
- templateWifiWildcard.assertDoesNotMatch(identMobileImsi1)
- templateWifiWildcard.assertMatches(identWifiImsiNullSsid1)
- templateWifiWildcard.assertMatches(identWifiImsi1Ssid1)
- }
-
- @Test
- fun testWifiMatches() {
- val templateWifiSsid1 = buildTemplateWifi(TEST_SSID1)
- val templateWifiSsid1ImsiNull = buildTemplateWifi(TEST_SSID1, null)
- val templateWifiSsid1Imsi1 = buildTemplateWifi(TEST_SSID1, TEST_IMSI1)
- val templateWifiSsidAllImsi1 = buildTemplateWifi(WIFI_NETWORKID_ALL, TEST_IMSI1)
-
- val identMobile1 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI1),
- false, TelephonyManager.NETWORK_TYPE_UMTS)
- val identWifiImsiNullSsid1 = buildNetworkIdentity(
- mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0)
- val identWifiImsi1Ssid1 = buildNetworkIdentity(
- mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID1), true, 0)
- val identWifiImsi2Ssid1 = buildNetworkIdentity(
- mockContext, buildWifiNetworkState(TEST_IMSI2, TEST_SSID1), true, 0)
- val identWifiImsi1Ssid2 = buildNetworkIdentity(
- mockContext, buildWifiNetworkState(TEST_IMSI1, TEST_SSID2), true, 0)
-
- // Verify that template with SSID only matches any subscriberId and specific SSID.
- templateWifiSsid1.assertDoesNotMatch(identMobile1)
- templateWifiSsid1.assertMatches(identWifiImsiNullSsid1)
- templateWifiSsid1.assertMatches(identWifiImsi1Ssid1)
- templateWifiSsid1.assertMatches(identWifiImsi2Ssid1)
- templateWifiSsid1.assertDoesNotMatch(identWifiImsi1Ssid2)
-
- // Verify that template with SSID1 and null imsi matches any network with
- // SSID1 and null imsi.
- templateWifiSsid1ImsiNull.assertDoesNotMatch(identMobile1)
- templateWifiSsid1ImsiNull.assertMatches(identWifiImsiNullSsid1)
- templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi1Ssid1)
- templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi2Ssid1)
- templateWifiSsid1ImsiNull.assertDoesNotMatch(identWifiImsi1Ssid2)
-
- // Verify that template with SSID1 and imsi1 matches any network with
- // SSID1 and imsi1.
- templateWifiSsid1Imsi1.assertDoesNotMatch(identMobile1)
- templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsiNullSsid1)
- templateWifiSsid1Imsi1.assertMatches(identWifiImsi1Ssid1)
- templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsi2Ssid1)
- templateWifiSsid1Imsi1.assertDoesNotMatch(identWifiImsi1Ssid2)
-
- // Verify that template with SSID all and imsi1 matches any network with
- // any SSID and imsi1.
- templateWifiSsidAllImsi1.assertDoesNotMatch(identMobile1)
- templateWifiSsidAllImsi1.assertDoesNotMatch(identWifiImsiNullSsid1)
- templateWifiSsidAllImsi1.assertMatches(identWifiImsi1Ssid1)
- templateWifiSsidAllImsi1.assertDoesNotMatch(identWifiImsi2Ssid1)
- templateWifiSsidAllImsi1.assertMatches(identWifiImsi1Ssid2)
- }
-
- @Test
- fun testCarrierMeteredMatches() {
- val templateCarrierImsi1Metered = buildTemplateCarrierMetered(TEST_IMSI1)
-
- val mobileImsi1 = buildMobileNetworkState(TEST_IMSI1)
- val mobileImsi1Unmetered = buildNetworkState(TYPE_MOBILE, TEST_IMSI1, null /* ssid */,
- OEM_NONE, false /* metered */)
- val mobileImsi2 = buildMobileNetworkState(TEST_IMSI2)
- val wifiSsid1 = buildWifiNetworkState(null /* subscriberId */, TEST_SSID1)
- val wifiImsi1Ssid1 = buildWifiNetworkState(TEST_IMSI1, TEST_SSID1)
- val wifiImsi1Ssid1Unmetered = buildNetworkState(TYPE_WIFI, TEST_IMSI1, TEST_SSID1,
- OEM_NONE, false /* metered */)
-
- val identMobileImsi1Metered = buildNetworkIdentity(mockContext,
- mobileImsi1, false /* defaultNetwork */, TelephonyManager.NETWORK_TYPE_UMTS)
- val identMobileImsi1Unmetered = buildNetworkIdentity(mockContext,
- mobileImsi1Unmetered, false /* defaultNetwork */,
- TelephonyManager.NETWORK_TYPE_UMTS)
- val identMobileImsi2Metered = buildNetworkIdentity(mockContext,
- mobileImsi2, false /* defaultNetwork */, TelephonyManager.NETWORK_TYPE_UMTS)
- val identWifiSsid1Metered = buildNetworkIdentity(
- mockContext, wifiSsid1, true /* defaultNetwork */, 0 /* subType */)
- val identCarrierWifiImsi1Metered = buildNetworkIdentity(
- mockContext, wifiImsi1Ssid1, true /* defaultNetwork */, 0 /* subType */)
- val identCarrierWifiImsi1NonMetered = buildNetworkIdentity(mockContext,
- wifiImsi1Ssid1Unmetered, true /* defaultNetwork */, 0 /* subType */)
-
- templateCarrierImsi1Metered.assertMatches(identMobileImsi1Metered)
- templateCarrierImsi1Metered.assertDoesNotMatch(identMobileImsi1Unmetered)
- templateCarrierImsi1Metered.assertDoesNotMatch(identMobileImsi2Metered)
- templateCarrierImsi1Metered.assertDoesNotMatch(identWifiSsid1Metered)
- templateCarrierImsi1Metered.assertMatches(identCarrierWifiImsi1Metered)
- templateCarrierImsi1Metered.assertDoesNotMatch(identCarrierWifiImsi1NonMetered)
- }
-
- @Test
- fun testRatTypeGroupMatches() {
- val stateMobile = buildMobileNetworkState(TEST_IMSI1)
- // Build UMTS template that matches mobile identities with RAT in the same
- // group with any IMSI. See {@link NetworkTemplate#getCollapsedRatType}.
- val templateUmts = buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS)
- // Build normal template that matches mobile identities with any RAT and IMSI.
- val templateAll = buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL)
- // Build template with UNKNOWN RAT that matches mobile identities with RAT that
- // cannot be determined.
- val templateUnknown =
- buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UNKNOWN)
-
- val identUmts = buildNetworkIdentity(
- mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_UMTS)
- val identHsdpa = buildNetworkIdentity(
- mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_HSDPA)
- val identLte = buildNetworkIdentity(
- mockContext, stateMobile, false, TelephonyManager.NETWORK_TYPE_LTE)
- val identCombined = buildNetworkIdentity(
- mockContext, stateMobile, false, SUBTYPE_COMBINED)
- val identImsi2 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI2),
- false, TelephonyManager.NETWORK_TYPE_UMTS)
- val identWifi = buildNetworkIdentity(
- mockContext, buildWifiNetworkState(null, TEST_SSID1), true, 0)
-
- // Assert that identity with the same RAT matches.
- templateUmts.assertMatches(identUmts)
- templateAll.assertMatches(identUmts)
- templateUnknown.assertDoesNotMatch(identUmts)
- // Assert that identity with the RAT within the same group matches.
- templateUmts.assertMatches(identHsdpa)
- templateAll.assertMatches(identHsdpa)
- templateUnknown.assertDoesNotMatch(identHsdpa)
- // Assert that identity with the RAT out of the same group only matches template with
- // NETWORK_TYPE_ALL.
- templateUmts.assertDoesNotMatch(identLte)
- templateAll.assertMatches(identLte)
- templateUnknown.assertDoesNotMatch(identLte)
- // Assert that identity with combined RAT only matches with template with NETWORK_TYPE_ALL
- // and NETWORK_TYPE_UNKNOWN.
- templateUmts.assertDoesNotMatch(identCombined)
- templateAll.assertMatches(identCombined)
- templateUnknown.assertMatches(identCombined)
- // Assert that identity with different IMSI matches.
- templateUmts.assertMatches(identImsi2)
- templateAll.assertMatches(identImsi2)
- templateUnknown.assertDoesNotMatch(identImsi2)
- // Assert that wifi identity does not match.
- templateUmts.assertDoesNotMatch(identWifi)
- templateAll.assertDoesNotMatch(identWifi)
- templateUnknown.assertDoesNotMatch(identWifi)
- }
-
- @Test
- fun testParcelUnparcel() {
- val templateMobile = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1, null, null, METERED_ALL,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE,
- OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT)
- val templateWifi = NetworkTemplate(MATCH_WIFI, null, null, TEST_SSID1, METERED_ALL,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_ALL,
- SUBSCRIBER_ID_MATCH_RULE_EXACT)
- val templateOem = NetworkTemplate(MATCH_MOBILE, null, null, null, METERED_ALL,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_YES,
- SUBSCRIBER_ID_MATCH_RULE_EXACT)
- assertParcelSane(templateMobile, 10)
- assertParcelSane(templateWifi, 10)
- assertParcelSane(templateOem, 10)
- }
-
- // Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with
- // TelephonyManager#NETWORK_TYPE_* constants.
- @Test
- fun testNetworkTypeConstants() {
- for (ratType in TelephonyManager.getAllNetworkTypes()) {
- assertNotEquals(NETWORK_TYPE_ALL, ratType)
- assertNotEquals(NETWORK_TYPE_5G_NSA, ratType)
- }
- }
-
- @Test
- fun testOemNetworkConstants() {
- val constantValues = arrayOf(OEM_MANAGED_YES, OEM_MANAGED_ALL, OEM_MANAGED_NO,
- OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
-
- // Verify that "not OEM managed network" constants are equal.
- assertEquals(OEM_MANAGED_NO, OEM_NONE)
-
- // Verify the constants don't conflict.
- assertEquals(constantValues.size, constantValues.distinct().count())
- }
-
- /**
- * Helper to enumerate and assert OEM managed wifi and mobile {@code NetworkTemplate}s match
- * their the appropriate OEM managed {@code NetworkIdentity}s.
- *
- * @param networkType {@code TYPE_MOBILE} or {@code TYPE_WIFI}
- * @param matchType A match rule from {@code NetworkTemplate.MATCH_*} corresponding to the
- * networkType.
- * @param subscriberId To be populated with {@code TEST_IMSI*} only if networkType is
- * {@code TYPE_MOBILE}. May be left as null when matchType is
- * {@link NetworkTemplate.MATCH_MOBILE_WILDCARD}.
- * @param templateSsid Top be populated with {@code TEST_SSID*} only if networkType is
- * {@code TYPE_WIFI}. May be left as null when matchType is
- * {@link NetworkTemplate.MATCH_WIFI_WILDCARD}.
- * @param identSsid If networkType is {@code TYPE_WIFI}, this value must *NOT* be null. Provide
- * one of {@code TEST_SSID*}.
- */
- private fun matchOemManagedIdent(
- networkType: Int,
- matchType: Int,
- subscriberId: String? = null,
- templateSsid: String? = null,
- identSsid: String? = null
- ) {
- val oemManagedStates = arrayOf(OEM_NONE, OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
- val matchSubscriberIds = arrayOf(subscriberId)
-
- val templateOemYes = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
- templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
- OEM_MANAGED_YES, SUBSCRIBER_ID_MATCH_RULE_EXACT)
- val templateOemAll = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
- templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
- OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT)
-
- for (identityOemManagedState in oemManagedStates) {
- val ident = buildNetworkIdentity(mockContext, buildNetworkState(networkType,
- subscriberId, identSsid, identityOemManagedState), /*defaultNetwork=*/false,
- /*subType=*/0)
-
- // Create a template with each OEM managed type and match it against the NetworkIdentity
- for (templateOemManagedState in oemManagedStates) {
- val template = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
- templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
- NETWORK_TYPE_ALL, templateOemManagedState, SUBSCRIBER_ID_MATCH_RULE_EXACT)
- if (identityOemManagedState == templateOemManagedState) {
- template.assertMatches(ident)
- } else {
- template.assertDoesNotMatch(ident)
- }
- }
- // OEM_MANAGED_ALL ignores OEM state.
- templateOemAll.assertMatches(ident)
- if (identityOemManagedState == OEM_NONE) {
- // OEM_MANAGED_YES matches everything except OEM_NONE.
- templateOemYes.assertDoesNotMatch(ident)
- } else {
- templateOemYes.assertMatches(ident)
- }
- }
- }
-
- @Test
- fun testOemManagedMatchesIdent() {
- matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE, subscriberId = TEST_IMSI1)
- matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE_WILDCARD)
- matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI, templateSsid = TEST_SSID1,
- identSsid = TEST_SSID1)
- matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI_WILDCARD, identSsid = TEST_SSID1)
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/NetworkUtilsTest.java b/packages/Connectivity/tests/unit/java/android/net/NetworkUtilsTest.java
deleted file mode 100644
index 7748288..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/NetworkUtilsTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static junit.framework.Assert.assertEquals;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.math.BigInteger;
-import java.util.TreeSet;
-
-@RunWith(AndroidJUnit4.class)
-@androidx.test.filters.SmallTest
-public class NetworkUtilsTest {
- @Test
- public void testRoutedIPv4AddressCount() {
- final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
- // No routes routes to no addresses.
- assertEquals(0, NetworkUtils.routedIPv4AddressCount(set));
-
- set.add(new IpPrefix("0.0.0.0/0"));
- assertEquals(1l << 32, NetworkUtils.routedIPv4AddressCount(set));
-
- set.add(new IpPrefix("20.18.0.0/16"));
- set.add(new IpPrefix("20.18.0.0/24"));
- set.add(new IpPrefix("20.18.0.0/8"));
- // There is a default route, still covers everything
- assertEquals(1l << 32, NetworkUtils.routedIPv4AddressCount(set));
-
- set.clear();
- set.add(new IpPrefix("20.18.0.0/24"));
- set.add(new IpPrefix("20.18.0.0/8"));
- // The 8-length includes the 24-length prefix
- assertEquals(1l << 24, NetworkUtils.routedIPv4AddressCount(set));
-
- set.add(new IpPrefix("10.10.10.126/25"));
- // The 8-length does not include this 25-length prefix
- assertEquals((1l << 24) + (1 << 7), NetworkUtils.routedIPv4AddressCount(set));
-
- set.clear();
- set.add(new IpPrefix("1.2.3.4/32"));
- set.add(new IpPrefix("1.2.3.4/32"));
- set.add(new IpPrefix("1.2.3.4/32"));
- set.add(new IpPrefix("1.2.3.4/32"));
- assertEquals(1l, NetworkUtils.routedIPv4AddressCount(set));
-
- set.add(new IpPrefix("1.2.3.5/32"));
- set.add(new IpPrefix("1.2.3.6/32"));
-
- set.add(new IpPrefix("1.2.3.7/32"));
- set.add(new IpPrefix("1.2.3.8/32"));
- set.add(new IpPrefix("1.2.3.9/32"));
- set.add(new IpPrefix("1.2.3.0/32"));
- assertEquals(7l, NetworkUtils.routedIPv4AddressCount(set));
-
- // 1.2.3.4/30 eats 1.2.3.{4-7}/32
- set.add(new IpPrefix("1.2.3.4/30"));
- set.add(new IpPrefix("6.2.3.4/28"));
- set.add(new IpPrefix("120.2.3.4/16"));
- assertEquals(7l - 4 + 4 + 16 + 65536, NetworkUtils.routedIPv4AddressCount(set));
- }
-
- @Test
- public void testRoutedIPv6AddressCount() {
- final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
- // No routes routes to no addresses.
- assertEquals(BigInteger.ZERO, NetworkUtils.routedIPv6AddressCount(set));
-
- set.add(new IpPrefix("::/0"));
- assertEquals(BigInteger.ONE.shiftLeft(128), NetworkUtils.routedIPv6AddressCount(set));
-
- set.add(new IpPrefix("1234:622a::18/64"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/96"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/8"));
- // There is a default route, still covers everything
- assertEquals(BigInteger.ONE.shiftLeft(128), NetworkUtils.routedIPv6AddressCount(set));
-
- set.clear();
- set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/96"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/8"));
- // The 8-length includes the 96-length prefix
- assertEquals(BigInteger.ONE.shiftLeft(120), NetworkUtils.routedIPv6AddressCount(set));
-
- set.add(new IpPrefix("10::26/64"));
- // The 8-length does not include this 64-length prefix
- assertEquals(BigInteger.ONE.shiftLeft(120).add(BigInteger.ONE.shiftLeft(64)),
- NetworkUtils.routedIPv6AddressCount(set));
-
- set.clear();
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
- assertEquals(BigInteger.ONE, NetworkUtils.routedIPv6AddressCount(set));
-
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad5/128"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad6/128"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad7/128"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad8/128"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad9/128"));
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad0/128"));
- assertEquals(BigInteger.valueOf(7), NetworkUtils.routedIPv6AddressCount(set));
-
- // add4:f00:80:f7:1111::6ad4/126 eats add4:f00:8[:f7:1111::6ad{4-7}/128
- set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/126"));
- set.add(new IpPrefix("d00d:f00:80:f7:1111::6ade/124"));
- set.add(new IpPrefix("f00b:a33::/112"));
- assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536),
- NetworkUtils.routedIPv6AddressCount(set));
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/QosSocketFilterTest.java b/packages/Connectivity/tests/unit/java/android/net/QosSocketFilterTest.java
deleted file mode 100644
index 40f8f1b..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/QosSocketFilterTest.java
+++ /dev/null
@@ -1,75 +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.net;
-
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-
-@RunWith(AndroidJUnit4.class)
-@androidx.test.filters.SmallTest
-public class QosSocketFilterTest {
-
- @Test
- public void testPortExactMatch() {
- final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
- final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
- assertTrue(QosSocketFilter.matchesAddress(
- new InetSocketAddress(addressA, 10), addressB, 10, 10));
-
- }
-
- @Test
- public void testPortLessThanStart() {
- final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
- final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
- assertFalse(QosSocketFilter.matchesAddress(
- new InetSocketAddress(addressA, 8), addressB, 10, 10));
- }
-
- @Test
- public void testPortGreaterThanEnd() {
- final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
- final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
- assertFalse(QosSocketFilter.matchesAddress(
- new InetSocketAddress(addressA, 18), addressB, 10, 10));
- }
-
- @Test
- public void testPortBetweenStartAndEnd() {
- final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
- final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
- assertTrue(QosSocketFilter.matchesAddress(
- new InetSocketAddress(addressA, 10), addressB, 8, 18));
- }
-
- @Test
- public void testAddressesDontMatch() {
- final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
- final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.5");
- assertFalse(QosSocketFilter.matchesAddress(
- new InetSocketAddress(addressA, 10), addressB, 10, 10));
- }
-}
-
diff --git a/packages/Connectivity/tests/unit/java/android/net/TelephonyNetworkSpecifierTest.java b/packages/Connectivity/tests/unit/java/android/net/TelephonyNetworkSpecifierTest.java
deleted file mode 100644
index 6714bb1..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/TelephonyNetworkSpecifierTest.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static com.android.testutils.ParcelUtils.assertParcelSane;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.net.wifi.WifiNetworkSpecifier;
-import android.telephony.SubscriptionManager;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-
-/**
- * Unit test for {@link android.net.TelephonyNetworkSpecifier}.
- */
-@SmallTest
-public class TelephonyNetworkSpecifierTest {
- private static final int TEST_SUBID = 5;
- private static final String TEST_SSID = "Test123";
-
- /**
- * Validate that IllegalArgumentException will be thrown if build TelephonyNetworkSpecifier
- * without calling {@link TelephonyNetworkSpecifier.Builder#setSubscriptionId(int)}.
- */
- @Test
- public void testBuilderBuildWithDefault() {
- try {
- new TelephonyNetworkSpecifier.Builder().build();
- } catch (IllegalArgumentException iae) {
- // expected, test pass
- }
- }
-
- /**
- * Validate that no exception will be thrown even if pass invalid subscription id to
- * {@link TelephonyNetworkSpecifier.Builder#setSubscriptionId(int)}.
- */
- @Test
- public void testBuilderBuildWithInvalidSubId() {
- TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
- .setSubscriptionId(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
- .build();
- assertEquals(specifier.getSubscriptionId(), SubscriptionManager.INVALID_SUBSCRIPTION_ID);
- }
-
- /**
- * Validate the correctness of TelephonyNetworkSpecifier when provide valid subId.
- */
- @Test
- public void testBuilderBuildWithValidSubId() {
- final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
- .setSubscriptionId(TEST_SUBID)
- .build();
- assertEquals(TEST_SUBID, specifier.getSubscriptionId());
- }
-
- /**
- * Validate that parcel marshalling/unmarshalling works.
- */
- @Test
- public void testParcel() {
- TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
- .setSubscriptionId(TEST_SUBID)
- .build();
- assertParcelSane(specifier, 1 /* fieldCount */);
- }
-
- /**
- * Validate the behavior of method canBeSatisfiedBy().
- */
- @Test
- public void testCanBeSatisfiedBy() {
- final TelephonyNetworkSpecifier tns1 = new TelephonyNetworkSpecifier.Builder()
- .setSubscriptionId(TEST_SUBID)
- .build();
- final TelephonyNetworkSpecifier tns2 = new TelephonyNetworkSpecifier.Builder()
- .setSubscriptionId(TEST_SUBID)
- .build();
- final WifiNetworkSpecifier wns = new WifiNetworkSpecifier.Builder()
- .setSsid(TEST_SSID)
- .build();
- final MatchAllNetworkSpecifier mans = new MatchAllNetworkSpecifier();
-
- // Test equality
- assertEquals(tns1, tns2);
- assertTrue(tns1.canBeSatisfiedBy(tns1));
- assertTrue(tns1.canBeSatisfiedBy(tns2));
-
- // Test other edge cases.
- assertFalse(tns1.canBeSatisfiedBy(null));
- assertFalse(tns1.canBeSatisfiedBy(wns));
- assertTrue(tns1.canBeSatisfiedBy(mans));
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/VpnManagerTest.java b/packages/Connectivity/tests/unit/java/android/net/VpnManagerTest.java
deleted file mode 100644
index 3135062..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/VpnManagerTest.java
+++ /dev/null
@@ -1,138 +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 android.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.test.mock.MockContext;
-import android.util.SparseArray;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.net.VpnProfile;
-import com.android.internal.util.MessageUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/** Unit tests for {@link VpnManager}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class VpnManagerTest {
- private static final String PKG_NAME = "fooPackage";
-
- private static final String SESSION_NAME_STRING = "testSession";
- private static final String SERVER_ADDR_STRING = "1.2.3.4";
- private static final String IDENTITY_STRING = "Identity";
- private static final byte[] PSK_BYTES = "preSharedKey".getBytes();
-
- private IVpnManager mMockService;
- private VpnManager mVpnManager;
- private final MockContext mMockContext =
- new MockContext() {
- @Override
- public String getOpPackageName() {
- return PKG_NAME;
- }
- };
-
- @Before
- public void setUp() throws Exception {
- mMockService = mock(IVpnManager.class);
- mVpnManager = new VpnManager(mMockContext, mMockService);
- }
-
- @Test
- public void testProvisionVpnProfilePreconsented() throws Exception {
- final PlatformVpnProfile profile = getPlatformVpnProfile();
- when(mMockService.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME)))
- .thenReturn(true);
-
- // Expect there to be no intent returned, as consent has already been granted.
- assertNull(mVpnManager.provisionVpnProfile(profile));
- verify(mMockService).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
- }
-
- @Test
- public void testProvisionVpnProfileNeedsConsent() throws Exception {
- final PlatformVpnProfile profile = getPlatformVpnProfile();
- when(mMockService.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME)))
- .thenReturn(false);
-
- // Expect intent to be returned, as consent has not already been granted.
- final Intent intent = mVpnManager.provisionVpnProfile(profile);
- assertNotNull(intent);
-
- final ComponentName expectedComponentName =
- ComponentName.unflattenFromString(
- "com.android.vpndialogs/com.android.vpndialogs.PlatformVpnConfirmDialog");
- assertEquals(expectedComponentName, intent.getComponent());
- verify(mMockService).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
- }
-
- @Test
- public void testDeleteProvisionedVpnProfile() throws Exception {
- mVpnManager.deleteProvisionedVpnProfile();
- verify(mMockService).deleteVpnProfile(eq(PKG_NAME));
- }
-
- @Test
- public void testStartProvisionedVpnProfile() throws Exception {
- mVpnManager.startProvisionedVpnProfile();
- verify(mMockService).startVpnProfile(eq(PKG_NAME));
- }
-
- @Test
- public void testStopProvisionedVpnProfile() throws Exception {
- mVpnManager.stopProvisionedVpnProfile();
- verify(mMockService).stopVpnProfile(eq(PKG_NAME));
- }
-
- private Ikev2VpnProfile getPlatformVpnProfile() throws Exception {
- return new Ikev2VpnProfile.Builder(SERVER_ADDR_STRING, IDENTITY_STRING)
- .setBypassable(true)
- .setMaxMtu(1300)
- .setMetered(true)
- .setAuthPsk(PSK_BYTES)
- .build();
- }
-
- @Test
- public void testVpnTypesEqual() throws Exception {
- SparseArray<String> vmVpnTypes = MessageUtils.findMessageNames(
- new Class[] { VpnManager.class }, new String[]{ "TYPE_VPN_" });
- SparseArray<String> nativeVpnType = MessageUtils.findMessageNames(
- new Class[] { NativeVpnType.class }, new String[]{ "" });
-
- // TYPE_VPN_NONE = -1 is only defined in VpnManager.
- assertEquals(vmVpnTypes.size() - 1, nativeVpnType.size());
- for (int i = VpnManager.TYPE_VPN_SERVICE; i < vmVpnTypes.size(); i++) {
- assertEquals(vmVpnTypes.get(i), "TYPE_VPN_" + nativeVpnType.get(i));
- }
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/VpnTransportInfoTest.java b/packages/Connectivity/tests/unit/java/android/net/VpnTransportInfoTest.java
deleted file mode 100644
index ccaa5cf..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/VpnTransportInfoTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
-import static android.net.NetworkCapabilities.REDACT_NONE;
-
-import static com.android.testutils.ParcelUtils.assertParcelSane;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class VpnTransportInfoTest {
-
- @Test
- public void testParceling() {
- VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345");
- assertParcelSane(v, 2 /* fieldCount */);
- }
-
- @Test
- public void testEqualsAndHashCode() {
- String session1 = "12345";
- String session2 = "6789";
- VpnTransportInfo v11 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1);
- VpnTransportInfo v12 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE, session1);
- VpnTransportInfo v13 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1);
- VpnTransportInfo v14 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session1);
- VpnTransportInfo v15 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM, session1);
- VpnTransportInfo v21 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session2);
-
- VpnTransportInfo v31 = v11.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
- VpnTransportInfo v32 = v13.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
-
- assertNotEquals(v11, v12);
- assertNotEquals(v13, v14);
- assertNotEquals(v14, v15);
- assertNotEquals(v14, v21);
-
- assertEquals(v11, v13);
- assertEquals(v31, v32);
- assertEquals(v11.hashCode(), v13.hashCode());
- assertEquals(REDACT_FOR_NETWORK_SETTINGS, v32.getApplicableRedactions());
- assertEquals(session1, v15.makeCopy(REDACT_NONE).getSessionId());
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/ipmemorystore/ParcelableTests.java b/packages/Connectivity/tests/unit/java/android/net/ipmemorystore/ParcelableTests.java
deleted file mode 100644
index 603c875..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/ipmemorystore/ParcelableTests.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.ipmemorystore;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.net.networkstack.aidl.quirks.IPv6ProvisioningLossQuirk;
-import android.net.networkstack.aidl.quirks.IPv6ProvisioningLossQuirkParcelable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.lang.reflect.Modifier;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.util.Arrays;
-import java.util.Collections;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ParcelableTests {
- @Test
- public void testNetworkAttributesParceling() throws Exception {
- final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
- NetworkAttributes in = builder.build();
- assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
-
- builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
- // lease will expire in two hours
- builder.setAssignedV4AddressExpiry(System.currentTimeMillis() + 7_200_000);
- // cluster stays null this time around
- builder.setDnsAddresses(Collections.emptyList());
- builder.setMtu(18);
- in = builder.build();
- assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
-
- builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("6.7.8.9"));
- builder.setAssignedV4AddressExpiry(System.currentTimeMillis() + 3_600_000);
- builder.setCluster("groupHint");
- builder.setDnsAddresses(Arrays.asList(
- InetAddress.getByName("ACA1:652B:0911:DE8F:1200:115E:913B:AA2A"),
- InetAddress.getByName("6.7.8.9")));
- builder.setMtu(1_000_000);
- in = builder.build();
- assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
-
- builder.setMtu(null);
- in = builder.build();
- assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
-
- // Verify that this test does not miss any new field added later.
- // If any field is added to NetworkAttributes it must be tested here for parceling
- // roundtrip.
- assertEquals(6, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
- .filter(f -> !Modifier.isStatic(f.getModifiers())).count());
- }
-
- @Test
- public void testPrivateDataParceling() throws Exception {
- final Blob in = new Blob();
- in.data = new byte[] {89, 111, 108, 111};
- final Blob out = parcelingRoundTrip(in);
- // Object.equals on byte[] tests the references
- assertEquals(in.data.length, out.data.length);
- assertTrue(Arrays.equals(in.data, out.data));
- }
-
- @Test
- public void testSameL3NetworkResponseParceling() throws Exception {
- final SameL3NetworkResponseParcelable parcelable = new SameL3NetworkResponseParcelable();
- parcelable.l2Key1 = "key 1";
- parcelable.l2Key2 = "key 2";
- parcelable.confidence = 0.43f;
-
- final SameL3NetworkResponse in = new SameL3NetworkResponse(parcelable);
- assertEquals("key 1", in.l2Key1);
- assertEquals("key 2", in.l2Key2);
- assertEquals(0.43f, in.confidence, 0.01f /* delta */);
-
- final SameL3NetworkResponse out =
- new SameL3NetworkResponse(parcelingRoundTrip(in.toParcelable()));
-
- assertEquals(in, out);
- assertEquals(in.l2Key1, out.l2Key1);
- assertEquals(in.l2Key2, out.l2Key2);
- assertEquals(in.confidence, out.confidence, 0.01f /* delta */);
- }
-
- @Test
- public void testIPv6ProvisioningLossQuirkParceling() throws Exception {
- final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
- final IPv6ProvisioningLossQuirkParcelable parcelable =
- new IPv6ProvisioningLossQuirkParcelable();
- final long expiry = System.currentTimeMillis() + 7_200_000;
-
- parcelable.detectionCount = 3;
- parcelable.quirkExpiry = expiry; // quirk info will expire in two hours
- builder.setIpv6ProvLossQuirk(IPv6ProvisioningLossQuirk.fromStableParcelable(parcelable));
- final NetworkAttributes in = builder.build();
-
- final NetworkAttributes out = new NetworkAttributes(parcelingRoundTrip(in.toParcelable()));
- assertEquals(out.ipv6ProvisioningLossQuirk, in.ipv6ProvisioningLossQuirk);
- }
-
- private <T extends Parcelable> T parcelingRoundTrip(final T in) throws Exception {
- final Parcel p = Parcel.obtain();
- in.writeToParcel(p, /* flags */ 0);
- p.setDataPosition(0);
- final byte[] marshalledData = p.marshall();
- p.recycle();
-
- final Parcel q = Parcel.obtain();
- q.unmarshall(marshalledData, 0, marshalledData.length);
- q.setDataPosition(0);
-
- final Parcelable.Creator<T> creator = (Parcelable.Creator<T>)
- in.getClass().getField("CREATOR").get(null); // static object, so null receiver
- final T unmarshalled = (T) creator.createFromParcel(q);
- q.recycle();
- return unmarshalled;
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/nsd/NsdManagerTest.java b/packages/Connectivity/tests/unit/java/android/net/nsd/NsdManagerTest.java
deleted file mode 100644
index b0a9b8a..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/nsd/NsdManagerTest.java
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.nsd;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.AsyncChannel;
-import com.android.testutils.HandlerUtils;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NsdManagerTest {
-
- static final int PROTOCOL = NsdManager.PROTOCOL_DNS_SD;
-
- @Mock Context mContext;
- @Mock INsdManager mService;
- MockServiceHandler mServiceHandler;
-
- NsdManager mManager;
-
- long mTimeoutMs = 200; // non-final so that tests can adjust the value.
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- mServiceHandler = spy(MockServiceHandler.create(mContext));
- when(mService.getMessenger()).thenReturn(new Messenger(mServiceHandler));
-
- mManager = makeManager();
- }
-
- @After
- public void tearDown() throws Exception {
- HandlerUtils.waitForIdle(mServiceHandler, mTimeoutMs);
- mServiceHandler.chan.disconnect();
- mServiceHandler.stop();
- if (mManager != null) {
- mManager.disconnect();
- }
- }
-
- @Test
- public void testResolveService() {
- NsdManager manager = mManager;
-
- NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
- NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
- NsdManager.ResolveListener listener = mock(NsdManager.ResolveListener.class);
-
- manager.resolveService(request, listener);
- int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
- int err = 33;
- sendResponse(NsdManager.RESOLVE_SERVICE_FAILED, err, key1, null);
- verify(listener, timeout(mTimeoutMs).times(1)).onResolveFailed(request, err);
-
- manager.resolveService(request, listener);
- int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
- sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
- verify(listener, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
- }
-
- @Test
- public void testParallelResolveService() {
- NsdManager manager = mManager;
-
- NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
- NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
-
- NsdManager.ResolveListener listener1 = mock(NsdManager.ResolveListener.class);
- NsdManager.ResolveListener listener2 = mock(NsdManager.ResolveListener.class);
-
- manager.resolveService(request, listener1);
- int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
-
- manager.resolveService(request, listener2);
- int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
-
- sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
- sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key1, reply);
-
- verify(listener1, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
- verify(listener2, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
- }
-
- @Test
- public void testRegisterService() {
- NsdManager manager = mManager;
-
- NsdServiceInfo request1 = new NsdServiceInfo("a_name", "a_type");
- NsdServiceInfo request2 = new NsdServiceInfo("another_name", "another_type");
- request1.setPort(2201);
- request2.setPort(2202);
- NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
- NsdManager.RegistrationListener listener2 = mock(NsdManager.RegistrationListener.class);
-
- // Register two services
- manager.registerService(request1, PROTOCOL, listener1);
- int key1 = verifyRequest(NsdManager.REGISTER_SERVICE);
-
- manager.registerService(request2, PROTOCOL, listener2);
- int key2 = verifyRequest(NsdManager.REGISTER_SERVICE);
-
- // First reques fails, second request succeeds
- sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key2, request2);
- verify(listener2, timeout(mTimeoutMs).times(1)).onServiceRegistered(request2);
-
- int err = 1;
- sendResponse(NsdManager.REGISTER_SERVICE_FAILED, err, key1, request1);
- verify(listener1, timeout(mTimeoutMs).times(1)).onRegistrationFailed(request1, err);
-
- // Client retries first request, it succeeds
- manager.registerService(request1, PROTOCOL, listener1);
- int key3 = verifyRequest(NsdManager.REGISTER_SERVICE);
-
- sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key3, request1);
- verify(listener1, timeout(mTimeoutMs).times(1)).onServiceRegistered(request1);
-
- // First request is unregistered, it succeeds
- manager.unregisterService(listener1);
- int key3again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
- assertEquals(key3, key3again);
-
- sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key3again, null);
- verify(listener1, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request1);
-
- // Second request is unregistered, it fails
- manager.unregisterService(listener2);
- int key2again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
- assertEquals(key2, key2again);
-
- sendResponse(NsdManager.UNREGISTER_SERVICE_FAILED, err, key2again, null);
- verify(listener2, timeout(mTimeoutMs).times(1)).onUnregistrationFailed(request2, err);
-
- // TODO: do not unregister listener until service is unregistered
- // Client retries unregistration of second request, it succeeds
- //manager.unregisterService(listener2);
- //int key2yetAgain = verifyRequest(NsdManager.UNREGISTER_SERVICE);
- //assertEquals(key2, key2yetAgain);
-
- //sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key2yetAgain, null);
- //verify(listener2, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request2);
- }
-
- @Test
- public void testDiscoverService() {
- NsdManager manager = mManager;
-
- NsdServiceInfo reply1 = new NsdServiceInfo("a_name", "a_type");
- NsdServiceInfo reply2 = new NsdServiceInfo("another_name", "a_type");
- NsdServiceInfo reply3 = new NsdServiceInfo("a_third_name", "a_type");
-
- NsdManager.DiscoveryListener listener = mock(NsdManager.DiscoveryListener.class);
-
- // Client registers for discovery, request fails
- manager.discoverServices("a_type", PROTOCOL, listener);
- int key1 = verifyRequest(NsdManager.DISCOVER_SERVICES);
-
- int err = 1;
- sendResponse(NsdManager.DISCOVER_SERVICES_FAILED, err, key1, null);
- verify(listener, timeout(mTimeoutMs).times(1)).onStartDiscoveryFailed("a_type", err);
-
- // Client retries, request succeeds
- manager.discoverServices("a_type", PROTOCOL, listener);
- int key2 = verifyRequest(NsdManager.DISCOVER_SERVICES);
-
- sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key2, reply1);
- verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
-
-
- // mdns notifies about services
- sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply1);
- verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply1);
-
- sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply2);
- verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply2);
-
- sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply2);
- verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply2);
-
-
- // Client unregisters its listener
- manager.stopServiceDiscovery(listener);
- int key2again = verifyRequest(NsdManager.STOP_DISCOVERY);
- assertEquals(key2, key2again);
-
- // TODO: unregister listener immediately and stop notifying it about services
- // Notifications are still passed to the client's listener
- sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply1);
- verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply1);
-
- // Client is notified of complete unregistration
- sendResponse(NsdManager.STOP_DISCOVERY_SUCCEEDED, 0, key2again, "a_type");
- verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStopped("a_type");
-
- // Notifications are not passed to the client anymore
- sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply3);
- verify(listener, timeout(mTimeoutMs).times(0)).onServiceLost(reply3);
-
-
- // Client registers for service discovery
- reset(listener);
- manager.discoverServices("a_type", PROTOCOL, listener);
- int key3 = verifyRequest(NsdManager.DISCOVER_SERVICES);
-
- sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key3, reply1);
- verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
-
- // Client unregisters immediately, it fails
- manager.stopServiceDiscovery(listener);
- int key3again = verifyRequest(NsdManager.STOP_DISCOVERY);
- assertEquals(key3, key3again);
-
- err = 2;
- sendResponse(NsdManager.STOP_DISCOVERY_FAILED, err, key3again, "a_type");
- verify(listener, timeout(mTimeoutMs).times(1)).onStopDiscoveryFailed("a_type", err);
-
- // New notifications are not passed to the client anymore
- sendResponse(NsdManager.SERVICE_FOUND, 0, key3, reply1);
- verify(listener, timeout(mTimeoutMs).times(0)).onServiceFound(reply1);
- }
-
- @Test
- public void testInvalidCalls() {
- NsdManager manager = mManager;
-
- NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
- NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
- NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
-
- NsdServiceInfo invalidService = new NsdServiceInfo(null, null);
- NsdServiceInfo validService = new NsdServiceInfo("a_name", "a_type");
- validService.setPort(2222);
-
- // Service registration
- // - invalid arguments
- mustFail(() -> { manager.unregisterService(null); });
- mustFail(() -> { manager.registerService(null, -1, null); });
- mustFail(() -> { manager.registerService(null, PROTOCOL, listener1); });
- mustFail(() -> { manager.registerService(invalidService, PROTOCOL, listener1); });
- mustFail(() -> { manager.registerService(validService, -1, listener1); });
- mustFail(() -> { manager.registerService(validService, PROTOCOL, null); });
- manager.registerService(validService, PROTOCOL, listener1);
- // - listener already registered
- mustFail(() -> { manager.registerService(validService, PROTOCOL, listener1); });
- manager.unregisterService(listener1);
- // TODO: make listener immediately reusable
- //mustFail(() -> { manager.unregisterService(listener1); });
- //manager.registerService(validService, PROTOCOL, listener1);
-
- // Discover service
- // - invalid arguments
- mustFail(() -> { manager.stopServiceDiscovery(null); });
- mustFail(() -> { manager.discoverServices(null, -1, null); });
- mustFail(() -> { manager.discoverServices(null, PROTOCOL, listener2); });
- mustFail(() -> { manager.discoverServices("a_service", -1, listener2); });
- mustFail(() -> { manager.discoverServices("a_service", PROTOCOL, null); });
- manager.discoverServices("a_service", PROTOCOL, listener2);
- // - listener already registered
- mustFail(() -> { manager.discoverServices("another_service", PROTOCOL, listener2); });
- manager.stopServiceDiscovery(listener2);
- // TODO: make listener immediately reusable
- //mustFail(() -> { manager.stopServiceDiscovery(listener2); });
- //manager.discoverServices("another_service", PROTOCOL, listener2);
-
- // Resolver service
- // - invalid arguments
- mustFail(() -> { manager.resolveService(null, null); });
- mustFail(() -> { manager.resolveService(null, listener3); });
- mustFail(() -> { manager.resolveService(invalidService, listener3); });
- mustFail(() -> { manager.resolveService(validService, null); });
- manager.resolveService(validService, listener3);
- // - listener already registered:w
- mustFail(() -> { manager.resolveService(validService, listener3); });
- }
-
- public void mustFail(Runnable fn) {
- try {
- fn.run();
- fail();
- } catch (Exception expected) {
- }
- }
-
- NsdManager makeManager() {
- NsdManager manager = new NsdManager(mContext, mService);
- // Acknowledge first two messages connecting the AsyncChannel.
- verify(mServiceHandler, timeout(mTimeoutMs).times(2)).handleMessage(any());
- reset(mServiceHandler);
- assertNotNull(mServiceHandler.chan);
- return manager;
- }
-
- int verifyRequest(int expectedMessageType) {
- HandlerUtils.waitForIdle(mServiceHandler, mTimeoutMs);
- verify(mServiceHandler, timeout(mTimeoutMs)).handleMessage(any());
- reset(mServiceHandler);
- Message received = mServiceHandler.getLastMessage();
- assertEquals(NsdManager.nameOf(expectedMessageType), NsdManager.nameOf(received.what));
- return received.arg2;
- }
-
- void sendResponse(int replyType, int arg, int key, Object obj) {
- mServiceHandler.chan.sendMessage(replyType, arg, key, obj);
- }
-
- // Implements the server side of AsyncChannel connection protocol
- public static class MockServiceHandler extends Handler {
- public final Context context;
- public AsyncChannel chan;
- public Message lastMessage;
-
- MockServiceHandler(Looper l, Context c) {
- super(l);
- context = c;
- }
-
- synchronized Message getLastMessage() {
- return lastMessage;
- }
-
- synchronized void setLastMessage(Message msg) {
- lastMessage = obtainMessage();
- lastMessage.copyFrom(msg);
- }
-
- @Override
- public void handleMessage(Message msg) {
- setLastMessage(msg);
- if (msg.what == AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) {
- chan = new AsyncChannel();
- chan.connect(context, this, msg.replyTo);
- chan.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
- }
- }
-
- void stop() {
- getLooper().quitSafely();
- }
-
- static MockServiceHandler create(Context context) {
- HandlerThread t = new HandlerThread("mock-service-handler");
- t.start();
- return new MockServiceHandler(t.getLooper(), context);
- }
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/nsd/NsdServiceInfoTest.java b/packages/Connectivity/tests/unit/java/android/net/nsd/NsdServiceInfoTest.java
deleted file mode 100644
index 94dfc75..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/nsd/NsdServiceInfoTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.nsd;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.StrictMode;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.Map;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NsdServiceInfoTest {
-
- public final static InetAddress LOCALHOST;
- static {
- // Because test.
- StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
- StrictMode.setThreadPolicy(policy);
-
- InetAddress _host = null;
- try {
- _host = InetAddress.getLocalHost();
- } catch (UnknownHostException e) { }
- LOCALHOST = _host;
- }
-
- @Test
- public void testLimits() throws Exception {
- NsdServiceInfo info = new NsdServiceInfo();
-
- // Non-ASCII keys.
- boolean exceptionThrown = false;
- try {
- info.setAttribute("猫", "meow");
- } catch (IllegalArgumentException e) {
- exceptionThrown = true;
- }
- assertTrue(exceptionThrown);
- assertEmptyServiceInfo(info);
-
- // ASCII keys with '=' character.
- exceptionThrown = false;
- try {
- info.setAttribute("kitten=", "meow");
- } catch (IllegalArgumentException e) {
- exceptionThrown = true;
- }
- assertTrue(exceptionThrown);
- assertEmptyServiceInfo(info);
-
- // Single key + value length too long.
- exceptionThrown = false;
- try {
- String longValue = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
- "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
- "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
- "ooooooooooooooooooooooooooooong"; // 248 characters.
- info.setAttribute("longcat", longValue); // Key + value == 255 characters.
- } catch (IllegalArgumentException e) {
- exceptionThrown = true;
- }
- assertTrue(exceptionThrown);
- assertEmptyServiceInfo(info);
-
- // Total TXT record length too long.
- exceptionThrown = false;
- int recordsAdded = 0;
- try {
- for (int i = 100; i < 300; ++i) {
- // 6 char key + 5 char value + 2 bytes overhead = 13 byte record length.
- String key = String.format("key%d", i);
- info.setAttribute(key, "12345");
- recordsAdded++;
- }
- } catch (IllegalArgumentException e) {
- exceptionThrown = true;
- }
- assertTrue(exceptionThrown);
- assertTrue(100 == recordsAdded);
- assertTrue(info.getTxtRecord().length == 1300);
- }
-
- @Test
- public void testParcel() throws Exception {
- NsdServiceInfo emptyInfo = new NsdServiceInfo();
- checkParcelable(emptyInfo);
-
- NsdServiceInfo fullInfo = new NsdServiceInfo();
- fullInfo.setServiceName("kitten");
- fullInfo.setServiceType("_kitten._tcp");
- fullInfo.setPort(4242);
- fullInfo.setHost(LOCALHOST);
- checkParcelable(fullInfo);
-
- NsdServiceInfo noHostInfo = new NsdServiceInfo();
- noHostInfo.setServiceName("kitten");
- noHostInfo.setServiceType("_kitten._tcp");
- noHostInfo.setPort(4242);
- checkParcelable(noHostInfo);
-
- NsdServiceInfo attributedInfo = new NsdServiceInfo();
- attributedInfo.setServiceName("kitten");
- attributedInfo.setServiceType("_kitten._tcp");
- attributedInfo.setPort(4242);
- attributedInfo.setHost(LOCALHOST);
- attributedInfo.setAttribute("color", "pink");
- attributedInfo.setAttribute("sound", (new String("にゃあ")).getBytes("UTF-8"));
- attributedInfo.setAttribute("adorable", (String) null);
- attributedInfo.setAttribute("sticky", "yes");
- attributedInfo.setAttribute("siblings", new byte[] {});
- attributedInfo.setAttribute("edge cases", new byte[] {0, -1, 127, -128});
- attributedInfo.removeAttribute("sticky");
- checkParcelable(attributedInfo);
-
- // Sanity check that we actually wrote attributes to attributedInfo.
- assertTrue(attributedInfo.getAttributes().keySet().contains("adorable"));
- String sound = new String(attributedInfo.getAttributes().get("sound"), "UTF-8");
- assertTrue(sound.equals("にゃあ"));
- byte[] edgeCases = attributedInfo.getAttributes().get("edge cases");
- assertTrue(Arrays.equals(edgeCases, new byte[] {0, -1, 127, -128}));
- assertFalse(attributedInfo.getAttributes().keySet().contains("sticky"));
- }
-
- public void checkParcelable(NsdServiceInfo original) {
- // Write to parcel.
- Parcel p = Parcel.obtain();
- Bundle writer = new Bundle();
- writer.putParcelable("test_info", original);
- writer.writeToParcel(p, 0);
-
- // Extract from parcel.
- p.setDataPosition(0);
- Bundle reader = p.readBundle();
- reader.setClassLoader(NsdServiceInfo.class.getClassLoader());
- NsdServiceInfo result = reader.getParcelable("test_info");
-
- // Assert equality of base fields.
- assertEquals(original.getServiceName(), result.getServiceName());
- assertEquals(original.getServiceType(), result.getServiceType());
- assertEquals(original.getHost(), result.getHost());
- assertTrue(original.getPort() == result.getPort());
-
- // Assert equality of attribute map.
- Map<String, byte[]> originalMap = original.getAttributes();
- Map<String, byte[]> resultMap = result.getAttributes();
- assertEquals(originalMap.keySet(), resultMap.keySet());
- for (String key : originalMap.keySet()) {
- assertTrue(Arrays.equals(originalMap.get(key), resultMap.get(key)));
- }
- }
-
- public void assertEmptyServiceInfo(NsdServiceInfo shouldBeEmpty) {
- byte[] txtRecord = shouldBeEmpty.getTxtRecord();
- if (txtRecord == null || txtRecord.length == 0) {
- return;
- }
- fail("NsdServiceInfo.getTxtRecord did not return null but " + Arrays.toString(txtRecord));
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/util/DnsUtilsTest.java b/packages/Connectivity/tests/unit/java/android/net/util/DnsUtilsTest.java
deleted file mode 100644
index b626db8..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/util/DnsUtilsTest.java
+++ /dev/null
@@ -1,216 +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 android.net.util;
-
-import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_GLOBAL;
-import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_LINKLOCAL;
-import static android.net.util.DnsUtils.IPV6_ADDR_SCOPE_SITELOCAL;
-
-import static org.junit.Assert.assertEquals;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.InetAddresses;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.net.InetAddress;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DnsUtilsTest {
- private InetAddress stringToAddress(@NonNull String addr) {
- return InetAddresses.parseNumericAddress(addr);
- }
-
- private DnsUtils.SortableAddress makeSortableAddress(@NonNull String addr) {
- return makeSortableAddress(addr, null);
- }
-
- private DnsUtils.SortableAddress makeSortableAddress(@NonNull String addr,
- @Nullable String srcAddr) {
- return new DnsUtils.SortableAddress(stringToAddress(addr),
- srcAddr != null ? stringToAddress(srcAddr) : null);
- }
-
- @Test
- public void testRfc6724Comparator() {
- final List<DnsUtils.SortableAddress> test = Arrays.asList(
- // Ipv4
- makeSortableAddress("216.58.200.36", "192.168.1.1"),
- // global with different scope src
- makeSortableAddress("2404:6800:4008:801::2004", "fe80::1111:2222"),
- // global without src addr
- makeSortableAddress("2404:6800:cafe:801::1"),
- // loop back
- makeSortableAddress("::1", "::1"),
- // link local
- makeSortableAddress("fe80::c46f:1cff:fe04:39b4", "fe80::1"),
- // teredo tunneling
- makeSortableAddress("2001::47c1", "2001::2"),
- // 6bone without src addr
- makeSortableAddress("3ffe::1234:5678"),
- // IPv4-compatible
- makeSortableAddress("::216.58.200.36", "::216.58.200.9"),
- // 6bone
- makeSortableAddress("3ffe::1234:5678", "3ffe::1234:1"),
- // IPv4-mapped IPv6
- makeSortableAddress("::ffff:192.168.95.7", "::ffff:192.168.95.1"));
-
- final List<InetAddress> expected = Arrays.asList(
- stringToAddress("::1"), // loop back
- stringToAddress("fe80::c46f:1cff:fe04:39b4"), // link local
- stringToAddress("216.58.200.36"), // Ipv4
- stringToAddress("::ffff:192.168.95.7"), // IPv4-mapped IPv6
- stringToAddress("2001::47c1"), // teredo tunneling
- stringToAddress("::216.58.200.36"), // IPv4-compatible
- stringToAddress("3ffe::1234:5678"), // 6bone
- stringToAddress("2404:6800:4008:801::2004"), // global with different scope src
- stringToAddress("2404:6800:cafe:801::1"), // global without src addr
- stringToAddress("3ffe::1234:5678")); // 6bone without src addr
-
- Collections.sort(test, new DnsUtils.Rfc6724Comparator());
-
- for (int i = 0; i < test.size(); ++i) {
- assertEquals(test.get(i).address, expected.get(i));
- }
-
- // TODO: add more combinations
- }
-
- @Test
- public void testV4SortableAddress() {
- // Test V4 address
- DnsUtils.SortableAddress test = makeSortableAddress("216.58.200.36");
- assertEquals(test.hasSrcAddr, 0);
- assertEquals(test.prefixMatchLen, 0);
- assertEquals(test.address, stringToAddress("216.58.200.36"));
- assertEquals(test.labelMatch, 0);
- assertEquals(test.scopeMatch, 0);
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.label, 4);
- assertEquals(test.precedence, 35);
-
- // Test V4 loopback address with the same source address
- test = makeSortableAddress("127.1.2.3", "127.1.2.3");
- assertEquals(test.hasSrcAddr, 1);
- assertEquals(test.prefixMatchLen, 0);
- assertEquals(test.address, stringToAddress("127.1.2.3"));
- assertEquals(test.labelMatch, 1);
- assertEquals(test.scopeMatch, 1);
- assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
- assertEquals(test.label, 4);
- assertEquals(test.precedence, 35);
- }
-
- @Test
- public void testV6SortableAddress() {
- // Test global address
- DnsUtils.SortableAddress test = makeSortableAddress("2404:6800:4008:801::2004");
- assertEquals(test.address, stringToAddress("2404:6800:4008:801::2004"));
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.label, 1);
- assertEquals(test.precedence, 40);
-
- // Test global address with global source address
- test = makeSortableAddress("2404:6800:4008:801::2004",
- "2401:fa00:fc:fd00:6d6c:7199:b8e7:41d6");
- assertEquals(test.address, stringToAddress("2404:6800:4008:801::2004"));
- assertEquals(test.hasSrcAddr, 1);
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.labelMatch, 1);
- assertEquals(test.scopeMatch, 1);
- assertEquals(test.label, 1);
- assertEquals(test.precedence, 40);
- assertEquals(test.prefixMatchLen, 13);
-
- // Test global address with linklocal source address
- test = makeSortableAddress("2404:6800:4008:801::2004", "fe80::c46f:1cff:fe04:39b4");
- assertEquals(test.hasSrcAddr, 1);
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.labelMatch, 1);
- assertEquals(test.scopeMatch, 0);
- assertEquals(test.label, 1);
- assertEquals(test.precedence, 40);
- assertEquals(test.prefixMatchLen, 0);
-
- // Test loopback address with the same source address
- test = makeSortableAddress("::1", "::1");
- assertEquals(test.hasSrcAddr, 1);
- assertEquals(test.prefixMatchLen, 16 * 8);
- assertEquals(test.labelMatch, 1);
- assertEquals(test.scopeMatch, 1);
- assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
- assertEquals(test.label, 0);
- assertEquals(test.precedence, 50);
-
- // Test linklocal address
- test = makeSortableAddress("fe80::c46f:1cff:fe04:39b4");
- assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
- assertEquals(test.label, 1);
- assertEquals(test.precedence, 40);
-
- // Test linklocal address
- test = makeSortableAddress("fe80::");
- assertEquals(test.scope, IPV6_ADDR_SCOPE_LINKLOCAL);
- assertEquals(test.label, 1);
- assertEquals(test.precedence, 40);
-
- // Test 6to4 address
- test = makeSortableAddress("2002:c000:0204::");
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.label, 2);
- assertEquals(test.precedence, 30);
-
- // Test unique local address
- test = makeSortableAddress("fc00::c000:13ab");
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.label, 13);
- assertEquals(test.precedence, 3);
-
- // Test teredo tunneling address
- test = makeSortableAddress("2001::47c1");
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.label, 5);
- assertEquals(test.precedence, 5);
-
- // Test IPv4-compatible addresses
- test = makeSortableAddress("::216.58.200.36");
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.label, 3);
- assertEquals(test.precedence, 1);
-
- // Test site-local address
- test = makeSortableAddress("fec0::cafe:3ab2");
- assertEquals(test.scope, IPV6_ADDR_SCOPE_SITELOCAL);
- assertEquals(test.label, 11);
- assertEquals(test.precedence, 1);
-
- // Test 6bone address
- test = makeSortableAddress("3ffe::1234:5678");
- assertEquals(test.scope, IPV6_ADDR_SCOPE_GLOBAL);
- assertEquals(test.label, 12);
- assertEquals(test.precedence, 1);
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/util/KeepaliveUtilsTest.kt b/packages/Connectivity/tests/unit/java/android/net/util/KeepaliveUtilsTest.kt
deleted file mode 100644
index 5006d53..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/util/KeepaliveUtilsTest.kt
+++ /dev/null
@@ -1,145 +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 android.net.util
-
-import android.content.Context
-import android.content.res.Resources
-import android.net.ConnectivityResources
-import android.net.NetworkCapabilities
-import android.net.NetworkCapabilities.MAX_TRANSPORT
-import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
-import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
-import android.net.NetworkCapabilities.TRANSPORT_VPN
-import android.net.NetworkCapabilities.TRANSPORT_WIFI
-import androidx.test.filters.SmallTest
-import com.android.internal.R
-import org.junit.After
-import org.junit.Assert.assertArrayEquals
-import org.junit.Assert.assertEquals
-import org.junit.Assert.fail
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mockito.any
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.mock
-
-/**
- * Tests for [KeepaliveUtils].
- *
- * Build, install and run with:
- * atest android.net.util.KeepaliveUtilsTest
- */
-@RunWith(JUnit4::class)
-@SmallTest
-class KeepaliveUtilsTest {
-
- // Prepare mocked context with given resource strings.
- private fun getMockedContextWithStringArrayRes(
- id: Int,
- name: String,
- res: Array<out String?>?
- ): Context {
- val mockRes = mock(Resources::class.java)
- doReturn(res).`when`(mockRes).getStringArray(eq(id))
- doReturn(id).`when`(mockRes).getIdentifier(eq(name), any(), any())
-
- return mock(Context::class.java).apply {
- doReturn(mockRes).`when`(this).getResources()
- ConnectivityResources.setResourcesContextForTest(this)
- }
- }
-
- @After
- fun tearDown() {
- ConnectivityResources.setResourcesContextForTest(null)
- }
-
- @Test
- fun testGetSupportedKeepalives() {
- fun assertRunWithException(res: Array<out String?>?) {
- try {
- val mockContext = getMockedContextWithStringArrayRes(
- R.array.config_networkSupportedKeepaliveCount,
- "config_networkSupportedKeepaliveCount", res)
- KeepaliveUtils.getSupportedKeepalives(mockContext)
- fail("Expected KeepaliveDeviceConfigurationException")
- } catch (expected: KeepaliveUtils.KeepaliveDeviceConfigurationException) {
- }
- }
-
- // Check resource with various invalid format.
- assertRunWithException(null)
- assertRunWithException(arrayOf<String?>(null))
- assertRunWithException(arrayOfNulls<String?>(10))
- assertRunWithException(arrayOf(""))
- assertRunWithException(arrayOf("3,ABC"))
- assertRunWithException(arrayOf("6,3,3"))
- assertRunWithException(arrayOf("5"))
-
- // Check resource with invalid slots value.
- assertRunWithException(arrayOf("3,-1"))
-
- // Check resource with invalid transport type.
- assertRunWithException(arrayOf("-1,3"))
- assertRunWithException(arrayOf("10,3"))
-
- // Check valid customization generates expected array.
- val validRes = arrayOf("0,3", "1,0", "4,4")
- val expectedValidRes = intArrayOf(3, 0, 0, 0, 4, 0, 0, 0, 0)
-
- val mockContext = getMockedContextWithStringArrayRes(
- R.array.config_networkSupportedKeepaliveCount,
- "config_networkSupportedKeepaliveCount", validRes)
- val actual = KeepaliveUtils.getSupportedKeepalives(mockContext)
- assertArrayEquals(expectedValidRes, actual)
- }
-
- @Test
- fun testGetSupportedKeepalivesForNetworkCapabilities() {
- // Mock customized supported keepalives for each transport type, and assuming:
- // 3 for cellular,
- // 6 for wifi,
- // 0 for others.
- val cust = IntArray(MAX_TRANSPORT + 1).apply {
- this[TRANSPORT_CELLULAR] = 3
- this[TRANSPORT_WIFI] = 6
- }
-
- val nc = NetworkCapabilities()
- // Check supported keepalives with single transport type.
- nc.transportTypes = intArrayOf(TRANSPORT_CELLULAR)
- assertEquals(3, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
-
- // Check supported keepalives with multiple transport types.
- nc.transportTypes = intArrayOf(TRANSPORT_WIFI, TRANSPORT_VPN)
- assertEquals(0, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
-
- // Check supported keepalives with non-customized transport type.
- nc.transportTypes = intArrayOf(TRANSPORT_ETHERNET)
- assertEquals(0, KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc))
-
- // Check supported keepalives with undefined transport type.
- nc.transportTypes = intArrayOf(MAX_TRANSPORT + 1)
- try {
- KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(cust, nc)
- fail("Expected ArrayIndexOutOfBoundsException")
- } catch (expected: ArrayIndexOutOfBoundsException) {
- }
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/android/net/util/MultinetworkPolicyTrackerTest.kt b/packages/Connectivity/tests/unit/java/android/net/util/MultinetworkPolicyTrackerTest.kt
deleted file mode 100644
index 25aa626..0000000
--- a/packages/Connectivity/tests/unit/java/android/net/util/MultinetworkPolicyTrackerTest.kt
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.util
-
-import android.content.Context
-import android.content.res.Resources
-import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER
-import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE
-import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY
-import android.net.ConnectivityResources
-import android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI
-import android.net.ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE
-import android.net.util.MultinetworkPolicyTracker.ActiveDataSubscriptionIdListener
-import android.provider.Settings
-import android.telephony.SubscriptionInfo
-import android.telephony.SubscriptionManager
-import android.telephony.TelephonyManager
-import android.test.mock.MockContentResolver
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.connectivity.resources.R
-import com.android.internal.util.test.FakeSettingsProvider
-import org.junit.After
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.ArgumentMatchers.argThat
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mockito.any
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
-
-/**
- * Tests for [MultinetworkPolicyTracker].
- *
- * Build, install and run with:
- * atest android.net.util.MultinetworkPolicyTrackerTest
- */
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class MultinetworkPolicyTrackerTest {
- private val resources = mock(Resources::class.java).also {
- doReturn(R.integer.config_networkAvoidBadWifi).`when`(it).getIdentifier(
- eq("config_networkAvoidBadWifi"), eq("integer"), any())
- doReturn(0).`when`(it).getInteger(R.integer.config_networkAvoidBadWifi)
- }
- private val telephonyManager = mock(TelephonyManager::class.java)
- private val subscriptionManager = mock(SubscriptionManager::class.java).also {
- doReturn(null).`when`(it).getActiveSubscriptionInfo(anyInt())
- }
- private val resolver = MockContentResolver().apply {
- addProvider(Settings.AUTHORITY, FakeSettingsProvider()) }
- private val context = mock(Context::class.java).also {
- doReturn(Context.TELEPHONY_SERVICE).`when`(it)
- .getSystemServiceName(TelephonyManager::class.java)
- doReturn(telephonyManager).`when`(it).getSystemService(Context.TELEPHONY_SERVICE)
- doReturn(subscriptionManager).`when`(it)
- .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
- doReturn(resolver).`when`(it).contentResolver
- doReturn(resources).`when`(it).resources
- doReturn(it).`when`(it).createConfigurationContext(any())
- Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "1")
- ConnectivityResources.setResourcesContextForTest(it)
- }
- private val tracker = MultinetworkPolicyTracker(context, null /* handler */)
-
- private fun assertMultipathPreference(preference: Int) {
- Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
- preference.toString())
- tracker.updateMeteredMultipathPreference()
- assertEquals(preference, tracker.meteredMultipathPreference)
- }
-
- @After
- fun tearDown() {
- ConnectivityResources.setResourcesContextForTest(null)
- }
-
- @Test
- fun testUpdateMeteredMultipathPreference() {
- assertMultipathPreference(MULTIPATH_PREFERENCE_HANDOVER)
- assertMultipathPreference(MULTIPATH_PREFERENCE_RELIABILITY)
- assertMultipathPreference(MULTIPATH_PREFERENCE_PERFORMANCE)
- }
-
- @Test
- fun testUpdateAvoidBadWifi() {
- Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0")
- assertTrue(tracker.updateAvoidBadWifi())
- assertFalse(tracker.avoidBadWifi)
-
- doReturn(1).`when`(resources).getInteger(R.integer.config_networkAvoidBadWifi)
- assertTrue(tracker.updateAvoidBadWifi())
- assertTrue(tracker.avoidBadWifi)
- }
-
- @Test
- fun testOnActiveDataSubscriptionIdChanged() {
- val testSubId = 1000
- val subscriptionInfo = SubscriptionInfo(testSubId, ""/* iccId */, 1/* iccId */,
- "TMO"/* displayName */, "TMO"/* carrierName */, 1/* nameSource */, 1/* iconTint */,
- "123"/* number */, 1/* roaming */, null/* icon */, "310"/* mcc */, "210"/* mnc */,
- ""/* countryIso */, false/* isEmbedded */, null/* nativeAccessRules */,
- "1"/* cardString */)
- doReturn(subscriptionInfo).`when`(subscriptionManager).getActiveSubscriptionInfo(testSubId)
-
- // Modify avoidBadWifi and meteredMultipathPreference settings value and local variables in
- // MultinetworkPolicyTracker should be also updated after subId changed.
- Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0")
- Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE,
- MULTIPATH_PREFERENCE_PERFORMANCE.toString())
-
- val listenerCaptor = ArgumentCaptor.forClass(
- ActiveDataSubscriptionIdListener::class.java)
- verify(telephonyManager, times(1))
- .registerTelephonyCallback(any(), listenerCaptor.capture())
- val listener = listenerCaptor.value
- listener.onActiveDataSubscriptionIdChanged(testSubId)
-
- // Check it get resource value with test sub id.
- verify(subscriptionManager, times(1)).getActiveSubscriptionInfo(testSubId)
- verify(context).createConfigurationContext(argThat { it.mcc == 310 && it.mnc == 210 })
-
- // Check if avoidBadWifi and meteredMultipathPreference values have been updated.
- assertFalse(tracker.avoidBadWifi)
- assertEquals(MULTIPATH_PREFERENCE_PERFORMANCE, tracker.meteredMultipathPreference)
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/internal/net/NetworkUtilsInternalTest.java b/packages/Connectivity/tests/unit/java/com/android/internal/net/NetworkUtilsInternalTest.java
deleted file mode 100644
index 3cfecd5..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/internal/net/NetworkUtilsInternalTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2015 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.internal.net;
-
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.AF_UNIX;
-import static android.system.OsConstants.EPERM;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOCK_STREAM;
-
-import static junit.framework.Assert.assertEquals;
-
-import static org.junit.Assert.fail;
-
-import android.system.ErrnoException;
-import android.system.Os;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import libcore.io.IoUtils;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@androidx.test.filters.SmallTest
-public class NetworkUtilsInternalTest {
-
- private static void expectSocketSuccess(String msg, int domain, int type) {
- try {
- IoUtils.closeQuietly(Os.socket(domain, type, 0));
- } catch (ErrnoException e) {
- fail(msg + e.getMessage());
- }
- }
-
- private static void expectSocketPemissionError(String msg, int domain, int type) {
- try {
- IoUtils.closeQuietly(Os.socket(domain, type, 0));
- fail(msg);
- } catch (ErrnoException e) {
- assertEquals(msg, e.errno, EPERM);
- }
- }
-
- private static void expectHasNetworking() {
- expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
- AF_UNIX, SOCK_STREAM);
- expectSocketSuccess("Creating a AF_INET socket shouldn't have thrown ErrnoException",
- AF_INET, SOCK_DGRAM);
- expectSocketSuccess("Creating a AF_INET6 socket shouldn't have thrown ErrnoException",
- AF_INET6, SOCK_DGRAM);
- }
-
- private static void expectNoNetworking() {
- expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
- AF_UNIX, SOCK_STREAM);
- expectSocketPemissionError(
- "Creating a AF_INET socket should have thrown ErrnoException(EPERM)",
- AF_INET, SOCK_DGRAM);
- expectSocketPemissionError(
- "Creating a AF_INET6 socket should have thrown ErrnoException(EPERM)",
- AF_INET6, SOCK_DGRAM);
- }
-
- @Test
- public void testSetAllowNetworkingForProcess() {
- expectHasNetworking();
- NetworkUtilsInternal.setAllowNetworkingForProcess(false);
- expectNoNetworking();
- NetworkUtilsInternal.setAllowNetworkingForProcess(true);
- expectHasNetworking();
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/internal/net/VpnProfileTest.java b/packages/Connectivity/tests/unit/java/com/android/internal/net/VpnProfileTest.java
deleted file mode 100644
index 46597d1..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/internal/net/VpnProfileTest.java
+++ /dev/null
@@ -1,218 +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.internal.net;
-
-import static com.android.testutils.ParcelUtils.assertParcelSane;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.net.IpSecAlgorithm;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/** Unit tests for {@link VpnProfile}. */
-@SmallTest
-@RunWith(JUnit4.class)
-public class VpnProfileTest {
- private static final String DUMMY_PROFILE_KEY = "Test";
-
- private static final int ENCODED_INDEX_AUTH_PARAMS_INLINE = 23;
- private static final int ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS = 24;
-
- @Test
- public void testDefaults() throws Exception {
- final VpnProfile p = new VpnProfile(DUMMY_PROFILE_KEY);
-
- assertEquals(DUMMY_PROFILE_KEY, p.key);
- assertEquals("", p.name);
- assertEquals(VpnProfile.TYPE_PPTP, p.type);
- assertEquals("", p.server);
- assertEquals("", p.username);
- assertEquals("", p.password);
- assertEquals("", p.dnsServers);
- assertEquals("", p.searchDomains);
- assertEquals("", p.routes);
- assertTrue(p.mppe);
- assertEquals("", p.l2tpSecret);
- assertEquals("", p.ipsecIdentifier);
- assertEquals("", p.ipsecSecret);
- assertEquals("", p.ipsecUserCert);
- assertEquals("", p.ipsecCaCert);
- assertEquals("", p.ipsecServerCert);
- assertEquals(null, p.proxy);
- assertTrue(p.getAllowedAlgorithms() != null && p.getAllowedAlgorithms().isEmpty());
- assertFalse(p.isBypassable);
- assertFalse(p.isMetered);
- assertEquals(1360, p.maxMtu);
- assertFalse(p.areAuthParamsInline);
- assertFalse(p.isRestrictedToTestNetworks);
- }
-
- private VpnProfile getSampleIkev2Profile(String key) {
- final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */);
-
- p.name = "foo";
- p.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
- p.server = "bar";
- p.username = "baz";
- p.password = "qux";
- p.dnsServers = "8.8.8.8";
- p.searchDomains = "";
- p.routes = "0.0.0.0/0";
- p.mppe = false;
- p.l2tpSecret = "";
- p.ipsecIdentifier = "quux";
- p.ipsecSecret = "quuz";
- p.ipsecUserCert = "corge";
- p.ipsecCaCert = "grault";
- p.ipsecServerCert = "garply";
- p.proxy = null;
- p.setAllowedAlgorithms(
- Arrays.asList(
- IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
- IpSecAlgorithm.AUTH_HMAC_SHA512,
- IpSecAlgorithm.CRYPT_AES_CBC));
- p.isBypassable = true;
- p.isMetered = true;
- p.maxMtu = 1350;
- p.areAuthParamsInline = true;
-
- // Not saved, but also not compared.
- p.saveLogin = true;
-
- return p;
- }
-
- @Test
- public void testEquals() {
- assertEquals(
- getSampleIkev2Profile(DUMMY_PROFILE_KEY), getSampleIkev2Profile(DUMMY_PROFILE_KEY));
-
- final VpnProfile modified = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
- modified.maxMtu--;
- assertNotEquals(getSampleIkev2Profile(DUMMY_PROFILE_KEY), modified);
- }
-
- @Test
- public void testParcelUnparcel() {
- assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 23);
- }
-
- @Test
- public void testSetInvalidAlgorithmValueDelimiter() {
- final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
-
- try {
- profile.setAllowedAlgorithms(
- Arrays.asList("test" + VpnProfile.VALUE_DELIMITER + "test"));
- fail("Expected failure due to value separator in algorithm name");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testSetInvalidAlgorithmListDelimiter() {
- final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
-
- try {
- profile.setAllowedAlgorithms(
- Arrays.asList("test" + VpnProfile.LIST_DELIMITER + "test"));
- fail("Expected failure due to value separator in algorithm name");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testEncodeDecode() {
- final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
- final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, profile.encode());
- assertEquals(profile, decoded);
- }
-
- @Test
- public void testEncodeDecodeTooManyValues() {
- final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
- final byte[] tooManyValues =
- (new String(profile.encode()) + VpnProfile.VALUE_DELIMITER + "invalid").getBytes();
-
- assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooManyValues));
- }
-
- private String getEncodedDecodedIkev2ProfileMissingValues(int... missingIndices) {
- // Sort to ensure when we remove, we can do it from greatest first.
- Arrays.sort(missingIndices);
-
- final String encoded = new String(getSampleIkev2Profile(DUMMY_PROFILE_KEY).encode());
- final List<String> parts =
- new ArrayList<>(Arrays.asList(encoded.split(VpnProfile.VALUE_DELIMITER)));
-
- // Remove from back first to ensure indexing is consistent.
- for (int i = missingIndices.length - 1; i >= 0; i--) {
- parts.remove(missingIndices[i]);
- }
-
- return String.join(VpnProfile.VALUE_DELIMITER, parts.toArray(new String[0]));
- }
-
- @Test
- public void testEncodeDecodeInvalidNumberOfValues() {
- final String tooFewValues =
- getEncodedDecodedIkev2ProfileMissingValues(
- ENCODED_INDEX_AUTH_PARAMS_INLINE,
- ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */);
-
- assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()));
- }
-
- @Test
- public void testEncodeDecodeMissingIsRestrictedToTestNetworks() {
- final String tooFewValues =
- getEncodedDecodedIkev2ProfileMissingValues(
- ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */);
-
- // Verify decoding without isRestrictedToTestNetworks defaults to false
- final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
- assertFalse(decoded.isRestrictedToTestNetworks);
- }
-
- @Test
- public void testEncodeDecodeLoginsNotSaved() {
- final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
- profile.saveLogin = false;
-
- final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, profile.encode());
- assertNotEquals(profile, decoded);
-
- // Add the username/password back, everything else must be equal.
- decoded.username = profile.username;
- decoded.password = profile.password;
- assertEquals(profile, decoded);
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/internal/util/BitUtilsTest.java b/packages/Connectivity/tests/unit/java/com/android/internal/util/BitUtilsTest.java
deleted file mode 100644
index d2fbdce..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/internal/util/BitUtilsTest.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2017 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.internal.util;
-
-import static com.android.internal.util.BitUtils.bytesToBEInt;
-import static com.android.internal.util.BitUtils.bytesToLEInt;
-import static com.android.internal.util.BitUtils.getUint16;
-import static com.android.internal.util.BitUtils.getUint32;
-import static com.android.internal.util.BitUtils.getUint8;
-import static com.android.internal.util.BitUtils.packBits;
-import static com.android.internal.util.BitUtils.uint16;
-import static com.android.internal.util.BitUtils.uint32;
-import static com.android.internal.util.BitUtils.uint8;
-import static com.android.internal.util.BitUtils.unpackBits;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.Random;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class BitUtilsTest {
-
- @Test
- public void testUnsignedByteWideningConversions() {
- byte b0 = 0;
- byte b1 = 1;
- byte bm1 = -1;
- assertEquals(0, uint8(b0));
- assertEquals(1, uint8(b1));
- assertEquals(127, uint8(Byte.MAX_VALUE));
- assertEquals(128, uint8(Byte.MIN_VALUE));
- assertEquals(255, uint8(bm1));
- assertEquals(255, uint8((byte)255));
- }
-
- @Test
- public void testUnsignedShortWideningConversions() {
- short s0 = 0;
- short s1 = 1;
- short sm1 = -1;
- assertEquals(0, uint16(s0));
- assertEquals(1, uint16(s1));
- assertEquals(32767, uint16(Short.MAX_VALUE));
- assertEquals(32768, uint16(Short.MIN_VALUE));
- assertEquals(65535, uint16(sm1));
- assertEquals(65535, uint16((short)65535));
- }
-
- @Test
- public void testUnsignedShortComposition() {
- byte b0 = 0;
- byte b1 = 1;
- byte b2 = 2;
- byte b10 = 10;
- byte b16 = 16;
- byte b128 = -128;
- byte b224 = -32;
- byte b255 = -1;
- assertEquals(0x0000, uint16(b0, b0));
- assertEquals(0xffff, uint16(b255, b255));
- assertEquals(0x0a01, uint16(b10, b1));
- assertEquals(0x8002, uint16(b128, b2));
- assertEquals(0x01ff, uint16(b1, b255));
- assertEquals(0x80ff, uint16(b128, b255));
- assertEquals(0xe010, uint16(b224, b16));
- }
-
- @Test
- public void testUnsignedIntWideningConversions() {
- assertEquals(0, uint32(0));
- assertEquals(1, uint32(1));
- assertEquals(2147483647L, uint32(Integer.MAX_VALUE));
- assertEquals(2147483648L, uint32(Integer.MIN_VALUE));
- assertEquals(4294967295L, uint32(-1));
- assertEquals(4294967295L, uint32((int)4294967295L));
- }
-
- @Test
- public void testBytesToInt() {
- assertEquals(0x00000000, bytesToBEInt(bytes(0, 0, 0, 0)));
- assertEquals(0xffffffff, bytesToBEInt(bytes(255, 255, 255, 255)));
- assertEquals(0x0a000001, bytesToBEInt(bytes(10, 0, 0, 1)));
- assertEquals(0x0a000002, bytesToBEInt(bytes(10, 0, 0, 2)));
- assertEquals(0x0a001fff, bytesToBEInt(bytes(10, 0, 31, 255)));
- assertEquals(0xe0000001, bytesToBEInt(bytes(224, 0, 0, 1)));
-
- assertEquals(0x00000000, bytesToLEInt(bytes(0, 0, 0, 0)));
- assertEquals(0x01020304, bytesToLEInt(bytes(4, 3, 2, 1)));
- assertEquals(0xffff0000, bytesToLEInt(bytes(0, 0, 255, 255)));
- }
-
- @Test
- public void testUnsignedGetters() {
- ByteBuffer b = ByteBuffer.allocate(4);
- b.putInt(0xffff);
-
- assertEquals(0x0, getUint8(b, 0));
- assertEquals(0x0, getUint8(b, 1));
- assertEquals(0xff, getUint8(b, 2));
- assertEquals(0xff, getUint8(b, 3));
-
- assertEquals(0x0, getUint16(b, 0));
- assertEquals(0xffff, getUint16(b, 2));
-
- b.rewind();
- b.putInt(0xffffffff);
- assertEquals(0xffffffffL, getUint32(b, 0));
- }
-
- @Test
- public void testBitsPacking() {
- BitPackingTestCase[] testCases = {
- new BitPackingTestCase(0, ints()),
- new BitPackingTestCase(1, ints(0)),
- new BitPackingTestCase(2, ints(1)),
- new BitPackingTestCase(3, ints(0, 1)),
- new BitPackingTestCase(4, ints(2)),
- new BitPackingTestCase(6, ints(1, 2)),
- new BitPackingTestCase(9, ints(0, 3)),
- new BitPackingTestCase(~Long.MAX_VALUE, ints(63)),
- new BitPackingTestCase(~Long.MAX_VALUE + 1, ints(0, 63)),
- new BitPackingTestCase(~Long.MAX_VALUE + 2, ints(1, 63)),
- };
- for (BitPackingTestCase tc : testCases) {
- int[] got = unpackBits(tc.packedBits);
- assertTrue(
- "unpackBits("
- + tc.packedBits
- + "): expected "
- + Arrays.toString(tc.bits)
- + " but got "
- + Arrays.toString(got),
- Arrays.equals(tc.bits, got));
- }
- for (BitPackingTestCase tc : testCases) {
- long got = packBits(tc.bits);
- assertEquals(
- "packBits("
- + Arrays.toString(tc.bits)
- + "): expected "
- + tc.packedBits
- + " but got "
- + got,
- tc.packedBits,
- got);
- }
-
- long[] moreTestCases = {
- 0, 1, -1, 23895, -908235, Long.MAX_VALUE, Long.MIN_VALUE, new Random().nextLong(),
- };
- for (long l : moreTestCases) {
- assertEquals(l, packBits(unpackBits(l)));
- }
- }
-
- static byte[] bytes(int b1, int b2, int b3, int b4) {
- return new byte[] {b(b1), b(b2), b(b3), b(b4)};
- }
-
- static byte b(int i) {
- return (byte) i;
- }
-
- static int[] ints(int... array) {
- return array;
- }
-
- static class BitPackingTestCase {
- final int[] bits;
- final long packedBits;
-
- BitPackingTestCase(long packedBits, int[] bits) {
- this.bits = bits;
- this.packedBits = packedBits;
- }
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/internal/util/RingBufferTest.java b/packages/Connectivity/tests/unit/java/com/android/internal/util/RingBufferTest.java
deleted file mode 100644
index d06095a..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/internal/util/RingBufferTest.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2017 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.internal.util;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class RingBufferTest {
-
- @Test
- public void testEmptyRingBuffer() {
- RingBuffer<String> buffer = new RingBuffer<>(String.class, 100);
-
- assertArrayEquals(new String[0], buffer.toArray());
- }
-
- @Test
- public void testIncorrectConstructorArguments() {
- try {
- RingBuffer<String> buffer = new RingBuffer<>(String.class, -10);
- fail("Should not be able to create a negative capacity RingBuffer");
- } catch (IllegalArgumentException expected) {
- }
-
- try {
- RingBuffer<String> buffer = new RingBuffer<>(String.class, 0);
- fail("Should not be able to create a 0 capacity RingBuffer");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testRingBufferWithNoWrapping() {
- RingBuffer<String> buffer = new RingBuffer<>(String.class, 100);
-
- buffer.append("a");
- buffer.append("b");
- buffer.append("c");
- buffer.append("d");
- buffer.append("e");
-
- String[] expected = {"a", "b", "c", "d", "e"};
- assertArrayEquals(expected, buffer.toArray());
- }
-
- @Test
- public void testRingBufferWithCapacity1() {
- RingBuffer<String> buffer = new RingBuffer<>(String.class, 1);
-
- buffer.append("a");
- assertArrayEquals(new String[]{"a"}, buffer.toArray());
-
- buffer.append("b");
- assertArrayEquals(new String[]{"b"}, buffer.toArray());
-
- buffer.append("c");
- assertArrayEquals(new String[]{"c"}, buffer.toArray());
-
- buffer.append("d");
- assertArrayEquals(new String[]{"d"}, buffer.toArray());
-
- buffer.append("e");
- assertArrayEquals(new String[]{"e"}, buffer.toArray());
- }
-
- @Test
- public void testRingBufferWithWrapping() {
- int capacity = 100;
- RingBuffer<String> buffer = new RingBuffer<>(String.class, capacity);
-
- buffer.append("a");
- buffer.append("b");
- buffer.append("c");
- buffer.append("d");
- buffer.append("e");
-
- String[] expected1 = {"a", "b", "c", "d", "e"};
- assertArrayEquals(expected1, buffer.toArray());
-
- String[] expected2 = new String[capacity];
- int firstIndex = 0;
- int lastIndex = capacity - 1;
-
- expected2[firstIndex] = "e";
- for (int i = 1; i < capacity; i++) {
- buffer.append("x");
- expected2[i] = "x";
- }
- assertArrayEquals(expected2, buffer.toArray());
-
- buffer.append("x");
- expected2[firstIndex] = "x";
- assertArrayEquals(expected2, buffer.toArray());
-
- for (int i = 0; i < 10; i++) {
- for (String s : expected2) {
- buffer.append(s);
- }
- }
- assertArrayEquals(expected2, buffer.toArray());
-
- buffer.append("a");
- expected2[lastIndex] = "a";
- assertArrayEquals(expected2, buffer.toArray());
- }
-
- @Test
- public void testGetNextSlot() {
- int capacity = 100;
- RingBuffer<DummyClass1> buffer = new RingBuffer<>(DummyClass1.class, capacity);
-
- final DummyClass1[] actual = new DummyClass1[capacity];
- final DummyClass1[] expected = new DummyClass1[capacity];
- for (int i = 0; i < capacity; ++i) {
- final DummyClass1 obj = buffer.getNextSlot();
- obj.x = capacity * i;
- actual[i] = obj;
- expected[i] = new DummyClass1();
- expected[i].x = capacity * i;
- }
- assertArrayEquals(expected, buffer.toArray());
-
- for (int i = 0; i < capacity; ++i) {
- if (actual[i] != buffer.getNextSlot()) {
- fail("getNextSlot() should re-use objects if available");
- }
- }
-
- RingBuffer<DummyClass2> buffer2 = new RingBuffer<>(DummyClass2.class, capacity);
- assertNull("getNextSlot() should return null if the object can't be initiated "
- + "(No nullary constructor)", buffer2.getNextSlot());
-
- RingBuffer<DummyClass3> buffer3 = new RingBuffer<>(DummyClass3.class, capacity);
- assertNull("getNextSlot() should return null if the object can't be initiated "
- + "(Inaccessible class)", buffer3.getNextSlot());
- }
-
- public static final class DummyClass1 {
- int x;
-
- public boolean equals(Object o) {
- if (o instanceof DummyClass1) {
- final DummyClass1 other = (DummyClass1) o;
- return other.x == this.x;
- }
- return false;
- }
- }
-
- public static final class DummyClass2 {
- public DummyClass2(int x) {}
- }
-
- private static final class DummyClass3 {}
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/packages/Connectivity/tests/unit/java/com/android/server/ConnectivityServiceTest.java
deleted file mode 100644
index 29a411e..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ /dev/null
@@ -1,12897 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static android.Manifest.permission.CHANGE_NETWORK_STATE;
-import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
-import static android.Manifest.permission.DUMP;
-import static android.Manifest.permission.LOCAL_MAC_ADDRESS;
-import static android.Manifest.permission.NETWORK_FACTORY;
-import static android.Manifest.permission.NETWORK_SETTINGS;
-import static android.app.PendingIntent.FLAG_IMMUTABLE;
-import static android.content.Intent.ACTION_PACKAGE_ADDED;
-import static android.content.Intent.ACTION_PACKAGE_REMOVED;
-import static android.content.Intent.ACTION_PACKAGE_REPLACED;
-import static android.content.Intent.ACTION_USER_ADDED;
-import static android.content.Intent.ACTION_USER_REMOVED;
-import static android.content.Intent.ACTION_USER_UNLOCKED;
-import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
-import static android.content.pm.PackageManager.FEATURE_WIFI;
-import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT;
-import static android.content.pm.PackageManager.GET_PERMISSIONS;
-import static android.content.pm.PackageManager.MATCH_ANY_USER;
-import static android.content.pm.PackageManager.PERMISSION_DENIED;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
-import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
-import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
-import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
-import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
-import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
-import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
-import static android.net.ConnectivityManager.EXTRA_NETWORK_TYPE;
-import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
-import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
-import static android.net.ConnectivityManager.TYPE_ETHERNET;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
-import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
-import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
-import static android.net.ConnectivityManager.TYPE_PROXY;
-import static android.net.ConnectivityManager.TYPE_VPN;
-import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
-import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_BIP;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_IA;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_VSIM;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
-import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
-import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
-import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
-import static android.net.NetworkCapabilities.REDACT_NONE;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
-import static android.net.NetworkScore.KEEP_CONNECTED_FOR_HANDOVER;
-import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
-import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
-import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
-import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
-import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED;
-import static android.net.RouteInfo.RTN_UNREACHABLE;
-import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED;
-import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_REMOVED;
-import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
-import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
-import static android.os.Process.INVALID_UID;
-import static android.system.OsConstants.IPPROTO_TCP;
-
-import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType;
-import static com.android.testutils.ConcurrentUtils.await;
-import static com.android.testutils.ConcurrentUtils.durationOf;
-import static com.android.testutils.ExceptionUtils.ignoreExceptions;
-import static com.android.testutils.HandlerUtils.waitForIdleSerialExecutor;
-import static com.android.testutils.MiscAsserts.assertContainsAll;
-import static com.android.testutils.MiscAsserts.assertContainsExactly;
-import static com.android.testutils.MiscAsserts.assertEmpty;
-import static com.android.testutils.MiscAsserts.assertLength;
-import static com.android.testutils.MiscAsserts.assertRunsInAtMost;
-import static com.android.testutils.MiscAsserts.assertSameElements;
-import static com.android.testutils.MiscAsserts.assertThrows;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.AdditionalMatchers.aryEq;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.ArgumentMatchers.startsWith;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.AlarmManager;
-import android.app.AppOpsManager;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.usage.NetworkStatsManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentProvider;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.location.LocationManager;
-import android.net.CaptivePortalData;
-import android.net.ConnectionInfo;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.ConnectivityManager.PacketKeepalive;
-import android.net.ConnectivityManager.PacketKeepaliveCallback;
-import android.net.ConnectivityManager.TooManyRequestsException;
-import android.net.ConnectivityResources;
-import android.net.ConnectivitySettingsManager;
-import android.net.ConnectivityThread;
-import android.net.DataStallReportParcelable;
-import android.net.EthernetManager;
-import android.net.IConnectivityDiagnosticsCallback;
-import android.net.IDnsResolver;
-import android.net.INetd;
-import android.net.INetworkMonitor;
-import android.net.INetworkMonitorCallbacks;
-import android.net.IOnCompleteListener;
-import android.net.IQosCallback;
-import android.net.InetAddresses;
-import android.net.InterfaceConfigurationParcel;
-import android.net.IpPrefix;
-import android.net.IpSecManager;
-import android.net.IpSecManager.UdpEncapsulationSocket;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.MatchAllNetworkSpecifier;
-import android.net.NativeNetworkConfig;
-import android.net.NativeNetworkType;
-import android.net.Network;
-import android.net.NetworkAgent;
-import android.net.NetworkAgentConfig;
-import android.net.NetworkCapabilities;
-import android.net.NetworkFactory;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkPolicyManager;
-import android.net.NetworkPolicyManager.NetworkPolicyCallback;
-import android.net.NetworkRequest;
-import android.net.NetworkScore;
-import android.net.NetworkSpecifier;
-import android.net.NetworkStack;
-import android.net.NetworkStateSnapshot;
-import android.net.NetworkTestResultParcelable;
-import android.net.OemNetworkPreferences;
-import android.net.ProxyInfo;
-import android.net.QosCallbackException;
-import android.net.QosFilter;
-import android.net.QosSession;
-import android.net.ResolverParamsParcel;
-import android.net.RouteInfo;
-import android.net.RouteInfoParcel;
-import android.net.SocketKeepalive;
-import android.net.TransportInfo;
-import android.net.UidRange;
-import android.net.UidRangeParcel;
-import android.net.UnderlyingNetworkInfo;
-import android.net.Uri;
-import android.net.VpnManager;
-import android.net.VpnTransportInfo;
-import android.net.metrics.IpConnectivityLog;
-import android.net.networkstack.NetworkStackClientBase;
-import android.net.resolv.aidl.Nat64PrefixEventParcel;
-import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
-import android.net.shared.NetworkMonitorUtils;
-import android.net.shared.PrivateDnsConfig;
-import android.net.util.MultinetworkPolicyTracker;
-import android.os.BadParcelableException;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.INetworkManagementService;
-import android.os.Looper;
-import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.os.SystemClock;
-import android.os.SystemConfigManager;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.security.Credentials;
-import android.system.Os;
-import android.telephony.TelephonyManager;
-import android.telephony.data.EpsBearerQosSessionAttributes;
-import android.telephony.data.NrQosSessionAttributes;
-import android.test.mock.MockContentResolver;
-import android.text.TextUtils;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.Pair;
-import android.util.Range;
-import android.util.SparseArray;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.connectivity.resources.R;
-import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnProfile;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.WakeupMessage;
-import com.android.internal.util.test.BroadcastInterceptingContext;
-import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.net.module.util.ArrayTrackRecord;
-import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
-import com.android.server.connectivity.MockableSystemProperties;
-import com.android.server.connectivity.Nat464Xlat;
-import com.android.server.connectivity.NetworkAgentInfo;
-import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
-import com.android.server.connectivity.ProxyTracker;
-import com.android.server.connectivity.QosCallbackTracker;
-import com.android.server.connectivity.Vpn;
-import com.android.server.connectivity.VpnProfileStore;
-import com.android.server.net.NetworkPinner;
-import com.android.testutils.ExceptionUtils;
-import com.android.testutils.HandlerUtils;
-import com.android.testutils.RecorderCallback.CallbackEntry;
-import com.android.testutils.TestableNetworkCallback;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.AdditionalAnswers;
-import org.mockito.ArgumentCaptor;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
-import org.mockito.stubbing.Answer;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.net.DatagramSocket;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-import kotlin.reflect.KClass;
-
-/**
- * Tests for {@link ConnectivityService}.
- *
- * Build, install and run with:
- * runtest frameworks-net -c com.android.server.ConnectivityServiceTest
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ConnectivityServiceTest {
- private static final String TAG = "ConnectivityServiceTest";
-
- private static final int TIMEOUT_MS = 500;
- // Broadcasts can take a long time to be delivered. The test will not wait for that long unless
- // there is a failure, so use a long timeout.
- private static final int BROADCAST_TIMEOUT_MS = 30_000;
- private static final int TEST_LINGER_DELAY_MS = 400;
- private static final int TEST_NASCENT_DELAY_MS = 300;
- // Chosen to be less than the linger and nascent timeout. This ensures that we can distinguish
- // between a LOST callback that arrives immediately and a LOST callback that arrives after
- // the linger/nascent timeout. For this, our assertions should run fast enough to leave
- // less than (mService.mLingerDelayMs - TEST_CALLBACK_TIMEOUT_MS) between the time callbacks are
- // supposedly fired, and the time we call expectCallback.
- private static final int TEST_CALLBACK_TIMEOUT_MS = 250;
- // Chosen to be less than TEST_CALLBACK_TIMEOUT_MS. This ensures that requests have time to
- // complete before callbacks are verified.
- private static final int TEST_REQUEST_TIMEOUT_MS = 150;
-
- private static final int UNREASONABLY_LONG_ALARM_WAIT_MS = 1000;
-
- private static final long TIMESTAMP = 1234L;
-
- private static final int NET_ID = 110;
- private static final int OEM_PREF_ANY_NET_ID = -1;
- // Set a non-zero value to verify the flow to set tcp init rwnd value.
- private static final int TEST_TCP_INIT_RWND = 60;
-
- // Used for testing the per-work-profile default network.
- private static final int TEST_APP_ID = 103;
- private static final int TEST_WORK_PROFILE_USER_ID = 2;
- private static final int TEST_WORK_PROFILE_APP_UID =
- UserHandle.getUid(TEST_WORK_PROFILE_USER_ID, TEST_APP_ID);
- private static final String CLAT_PREFIX = "v4-";
- private static final String MOBILE_IFNAME = "test_rmnet_data0";
- private static final String WIFI_IFNAME = "test_wlan0";
- private static final String WIFI_WOL_IFNAME = "test_wlan_wol";
- private static final String VPN_IFNAME = "tun10042";
- private static final String TEST_PACKAGE_NAME = "com.android.test.package";
- private static final int TEST_PACKAGE_UID = 123;
- private static final String ALWAYS_ON_PACKAGE = "com.android.test.alwaysonvpn";
-
- private static final String INTERFACE_NAME = "interface";
-
- private static final String TEST_VENUE_URL_NA_PASSPOINT = "https://android.com/";
- private static final String TEST_VENUE_URL_NA_OTHER = "https://example.com/";
- private static final String TEST_TERMS_AND_CONDITIONS_URL_NA_PASSPOINT =
- "https://android.com/terms/";
- private static final String TEST_TERMS_AND_CONDITIONS_URL_NA_OTHER =
- "https://example.com/terms/";
- private static final String TEST_VENUE_URL_CAPPORT = "https://android.com/capport/";
- private static final String TEST_USER_PORTAL_API_URL_CAPPORT =
- "https://android.com/user/api/capport/";
- private static final String TEST_FRIENDLY_NAME = "Network friendly name";
- private static final String TEST_REDIRECT_URL = "http://example.com/firstPath";
-
- private MockContext mServiceContext;
- private HandlerThread mCsHandlerThread;
- private HandlerThread mVMSHandlerThread;
- private ConnectivityService.Dependencies mDeps;
- private ConnectivityService mService;
- private WrappedConnectivityManager mCm;
- private TestNetworkAgentWrapper mWiFiNetworkAgent;
- private TestNetworkAgentWrapper mCellNetworkAgent;
- private TestNetworkAgentWrapper mEthernetNetworkAgent;
- private MockVpn mMockVpn;
- private Context mContext;
- private NetworkPolicyCallback mPolicyCallback;
- private WrappedMultinetworkPolicyTracker mPolicyTracker;
- private HandlerThread mAlarmManagerThread;
- private TestNetIdManager mNetIdManager;
- private QosCallbackMockHelper mQosCallbackMockHelper;
- private QosCallbackTracker mQosCallbackTracker;
- private VpnManagerService mVpnManagerService;
- private TestNetworkCallback mDefaultNetworkCallback;
- private TestNetworkCallback mSystemDefaultNetworkCallback;
- private TestNetworkCallback mProfileDefaultNetworkCallback;
-
- // State variables required to emulate NetworkPolicyManagerService behaviour.
- private int mBlockedReasons = BLOCKED_REASON_NONE;
-
- @Mock DeviceIdleInternal mDeviceIdleInternal;
- @Mock INetworkManagementService mNetworkManagementService;
- @Mock NetworkStatsManager mStatsManager;
- @Mock IDnsResolver mMockDnsResolver;
- @Mock INetd mMockNetd;
- @Mock NetworkStackClientBase mNetworkStack;
- @Mock PackageManager mPackageManager;
- @Mock UserManager mUserManager;
- @Mock NotificationManager mNotificationManager;
- @Mock AlarmManager mAlarmManager;
- @Mock IConnectivityDiagnosticsCallback mConnectivityDiagnosticsCallback;
- @Mock IBinder mIBinder;
- @Mock LocationManager mLocationManager;
- @Mock AppOpsManager mAppOpsManager;
- @Mock TelephonyManager mTelephonyManager;
- @Mock MockableSystemProperties mSystemProperties;
- @Mock EthernetManager mEthernetManager;
- @Mock NetworkPolicyManager mNetworkPolicyManager;
- @Mock VpnProfileStore mVpnProfileStore;
- @Mock SystemConfigManager mSystemConfigManager;
- @Mock Resources mResources;
-
- private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
- ArgumentCaptor.forClass(ResolverParamsParcel.class);
-
- // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods
- // do not go through ConnectivityService but talk to netd directly, so they don't automatically
- // reflect the state of our test ConnectivityService.
- private class WrappedConnectivityManager extends ConnectivityManager {
- private Network mFakeBoundNetwork;
-
- public synchronized boolean bindProcessToNetwork(Network network) {
- mFakeBoundNetwork = network;
- return true;
- }
-
- public synchronized Network getBoundNetworkForProcess() {
- return mFakeBoundNetwork;
- }
-
- public WrappedConnectivityManager(Context context, ConnectivityService service) {
- super(context, service);
- }
- }
-
- private class MockContext extends BroadcastInterceptingContext {
- private final MockContentResolver mContentResolver;
-
- @Spy private Resources mInternalResources;
- private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
-
- // Map of permission name -> PermissionManager.Permission_{GRANTED|DENIED} constant
- private final HashMap<String, Integer> mMockedPermissions = new HashMap<>();
-
- MockContext(Context base, ContentProvider settingsProvider) {
- super(base);
-
- mInternalResources = spy(base.getResources());
- when(mInternalResources.getStringArray(com.android.internal.R.array.networkAttributes))
- .thenReturn(new String[] {
- "wifi,1,1,1,-1,true",
- "mobile,0,0,0,-1,true",
- "mobile_mms,2,0,2,60000,true",
- "mobile_supl,3,0,2,60000,true",
- });
-
- mContentResolver = new MockContentResolver();
- mContentResolver.addProvider(Settings.AUTHORITY, settingsProvider);
- }
-
- @Override
- public void startActivityAsUser(Intent intent, UserHandle handle) {
- mStartedActivities.offer(intent);
- }
-
- public Intent expectStartActivityIntent(int timeoutMs) {
- Intent intent = null;
- try {
- intent = mStartedActivities.poll(timeoutMs, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {}
- assertNotNull("Did not receive sign-in intent after " + timeoutMs + "ms", intent);
- return intent;
- }
-
- public void expectNoStartActivityIntent(int timeoutMs) {
- try {
- assertNull("Received unexpected Intent to start activity",
- mStartedActivities.poll(timeoutMs, TimeUnit.MILLISECONDS));
- } catch (InterruptedException e) {}
- }
-
- @Override
- public ComponentName startService(Intent service) {
- final String action = service.getAction();
- if (!VpnConfig.SERVICE_INTERFACE.equals(action)) {
- fail("Attempt to start unknown service, action=" + action);
- }
- return new ComponentName(service.getPackage(), "com.android.test.Service");
- }
-
- @Override
- public Object getSystemService(String name) {
- if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
- if (Context.NOTIFICATION_SERVICE.equals(name)) return mNotificationManager;
- if (Context.USER_SERVICE.equals(name)) return mUserManager;
- if (Context.ALARM_SERVICE.equals(name)) return mAlarmManager;
- if (Context.LOCATION_SERVICE.equals(name)) return mLocationManager;
- if (Context.APP_OPS_SERVICE.equals(name)) return mAppOpsManager;
- if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
- if (Context.ETHERNET_SERVICE.equals(name)) return mEthernetManager;
- if (Context.NETWORK_POLICY_SERVICE.equals(name)) return mNetworkPolicyManager;
- if (Context.SYSTEM_CONFIG_SERVICE.equals(name)) return mSystemConfigManager;
- if (Context.NETWORK_STATS_SERVICE.equals(name)) return mStatsManager;
- return super.getSystemService(name);
- }
-
- final HashMap<UserHandle, UserManager> mUserManagers = new HashMap<>();
- @Override
- public Context createContextAsUser(UserHandle user, int flags) {
- final Context asUser = mock(Context.class, AdditionalAnswers.delegatesTo(this));
- doReturn(user).when(asUser).getUser();
- doAnswer((inv) -> {
- final UserManager um = mUserManagers.computeIfAbsent(user,
- u -> mock(UserManager.class, AdditionalAnswers.delegatesTo(mUserManager)));
- return um;
- }).when(asUser).getSystemService(Context.USER_SERVICE);
- return asUser;
- }
-
- public void setWorkProfile(@NonNull final UserHandle userHandle, boolean value) {
- // This relies on all contexts for a given user returning the same UM mock
- final UserManager umMock = createContextAsUser(userHandle, 0 /* flags */)
- .getSystemService(UserManager.class);
- doReturn(value).when(umMock).isManagedProfile();
- doReturn(value).when(mUserManager).isManagedProfile(eq(userHandle.getIdentifier()));
- }
-
- @Override
- public ContentResolver getContentResolver() {
- return mContentResolver;
- }
-
- @Override
- public Resources getResources() {
- return mInternalResources;
- }
-
- @Override
- public PackageManager getPackageManager() {
- return mPackageManager;
- }
-
- private int checkMockedPermission(String permission, Supplier<Integer> ifAbsent) {
- final Integer granted = mMockedPermissions.get(permission);
- return granted != null ? granted : ifAbsent.get();
- }
-
- @Override
- public int checkPermission(String permission, int pid, int uid) {
- return checkMockedPermission(
- permission, () -> super.checkPermission(permission, pid, uid));
- }
-
- @Override
- public int checkCallingOrSelfPermission(String permission) {
- return checkMockedPermission(
- permission, () -> super.checkCallingOrSelfPermission(permission));
- }
-
- @Override
- public void enforceCallingOrSelfPermission(String permission, String message) {
- final Integer granted = mMockedPermissions.get(permission);
- if (granted == null) {
- super.enforceCallingOrSelfPermission(permission, message);
- return;
- }
-
- if (!granted.equals(PERMISSION_GRANTED)) {
- throw new SecurityException("[Test] permission denied: " + permission);
- }
- }
-
- /**
- * Mock checks for the specified permission, and have them behave as per {@code granted}.
- *
- * <p>Passing null reverts to default behavior, which does a real permission check on the
- * test package.
- * @param granted One of {@link PackageManager#PERMISSION_GRANTED} or
- * {@link PackageManager#PERMISSION_DENIED}.
- */
- public void setPermission(String permission, Integer granted) {
- mMockedPermissions.put(permission, granted);
- }
- }
-
- private void waitForIdle() {
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
- waitForIdle(mCellNetworkAgent, TIMEOUT_MS);
- waitForIdle(mWiFiNetworkAgent, TIMEOUT_MS);
- waitForIdle(mEthernetNetworkAgent, TIMEOUT_MS);
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
- HandlerUtils.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS);
- }
-
- private void waitForIdle(TestNetworkAgentWrapper agent, long timeoutMs) {
- if (agent == null) {
- return;
- }
- agent.waitForIdle(timeoutMs);
- }
-
- @Test
- public void testWaitForIdle() throws Exception {
- final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng.
-
- // Tests that waitForIdle returns immediately if the service is already idle.
- for (int i = 0; i < attempts; i++) {
- waitForIdle();
- }
-
- // Bring up a network that we can use to send messages to ConnectivityService.
- ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- Network n = mWiFiNetworkAgent.getNetwork();
- assertNotNull(n);
-
- // Tests that calling waitForIdle waits for messages to be processed.
- for (int i = 0; i < attempts; i++) {
- mWiFiNetworkAgent.setSignalStrength(i);
- waitForIdle();
- assertEquals(i, mCm.getNetworkCapabilities(n).getSignalStrength());
- }
- }
-
- // This test has an inherent race condition in it, and cannot be enabled for continuous testing
- // or presubmit tests. It is kept for manual runs and documentation purposes.
- @Ignore
- public void verifyThatNotWaitingForIdleCausesRaceConditions() throws Exception {
- // Bring up a network that we can use to send messages to ConnectivityService.
- ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- Network n = mWiFiNetworkAgent.getNetwork();
- assertNotNull(n);
-
- // Ensure that not calling waitForIdle causes a race condition.
- final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng.
- for (int i = 0; i < attempts; i++) {
- mWiFiNetworkAgent.setSignalStrength(i);
- if (i != mCm.getNetworkCapabilities(n).getSignalStrength()) {
- // We hit a race condition, as expected. Pass the test.
- return;
- }
- }
-
- // No race? There is a bug in this test.
- fail("expected race condition at least once in " + attempts + " attempts");
- }
-
- private class TestNetworkAgentWrapper extends NetworkAgentWrapper {
- private static final int VALIDATION_RESULT_INVALID = 0;
-
- private static final long DATA_STALL_TIMESTAMP = 10L;
- private static final int DATA_STALL_DETECTION_METHOD = 1;
-
- private INetworkMonitor mNetworkMonitor;
- private INetworkMonitorCallbacks mNmCallbacks;
- private int mNmValidationResult = VALIDATION_RESULT_INVALID;
- private int mProbesCompleted;
- private int mProbesSucceeded;
- private String mNmValidationRedirectUrl = null;
- private boolean mNmProvNotificationRequested = false;
- private Runnable mCreatedCallback;
- private Runnable mUnwantedCallback;
- private Runnable mDisconnectedCallback;
-
- private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
- // Contains the redirectUrl from networkStatus(). Before reading, wait for
- // mNetworkStatusReceived.
- private String mRedirectUrl;
-
- TestNetworkAgentWrapper(int transport) throws Exception {
- this(transport, new LinkProperties(), null);
- }
-
- TestNetworkAgentWrapper(int transport, LinkProperties linkProperties)
- throws Exception {
- this(transport, linkProperties, null);
- }
-
- private TestNetworkAgentWrapper(int transport, LinkProperties linkProperties,
- NetworkCapabilities ncTemplate) throws Exception {
- super(transport, linkProperties, ncTemplate, mServiceContext);
-
- // Waits for the NetworkAgent to be registered, which includes the creation of the
- // NetworkMonitor.
- waitForIdle(TIMEOUT_MS);
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
- HandlerUtils.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS);
- }
-
- @Override
- protected InstrumentedNetworkAgent makeNetworkAgent(LinkProperties linkProperties,
- NetworkAgentConfig nac) throws Exception {
- mNetworkMonitor = mock(INetworkMonitor.class);
-
- final Answer validateAnswer = inv -> {
- new Thread(ignoreExceptions(this::onValidationRequested)).start();
- return null;
- };
-
- doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected(any(), any());
- doAnswer(validateAnswer).when(mNetworkMonitor).forceReevaluation(anyInt());
-
- final ArgumentCaptor<Network> nmNetworkCaptor = ArgumentCaptor.forClass(Network.class);
- final ArgumentCaptor<INetworkMonitorCallbacks> nmCbCaptor =
- ArgumentCaptor.forClass(INetworkMonitorCallbacks.class);
- doNothing().when(mNetworkStack).makeNetworkMonitor(
- nmNetworkCaptor.capture(),
- any() /* name */,
- nmCbCaptor.capture());
-
- final InstrumentedNetworkAgent na =
- new InstrumentedNetworkAgent(this, linkProperties, nac) {
- @Override
- public void networkStatus(int status, String redirectUrl) {
- mRedirectUrl = redirectUrl;
- mNetworkStatusReceived.open();
- }
-
- @Override
- public void onNetworkCreated() {
- super.onNetworkCreated();
- if (mCreatedCallback != null) mCreatedCallback.run();
- }
-
- @Override
- public void onNetworkUnwanted() {
- super.onNetworkUnwanted();
- if (mUnwantedCallback != null) mUnwantedCallback.run();
- }
-
- @Override
- public void onNetworkDestroyed() {
- super.onNetworkDestroyed();
- if (mDisconnectedCallback != null) mDisconnectedCallback.run();
- }
- };
-
- assertEquals(na.getNetwork().netId, nmNetworkCaptor.getValue().netId);
- mNmCallbacks = nmCbCaptor.getValue();
-
- mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor);
-
- return na;
- }
-
- private void onValidationRequested() throws Exception {
- if (mNmProvNotificationRequested
- && ((mNmValidationResult & NETWORK_VALIDATION_RESULT_VALID) != 0)) {
- mNmCallbacks.hideProvisioningNotification();
- mNmProvNotificationRequested = false;
- }
-
- mNmCallbacks.notifyProbeStatusChanged(mProbesCompleted, mProbesSucceeded);
- final NetworkTestResultParcelable p = new NetworkTestResultParcelable();
- p.result = mNmValidationResult;
- p.probesAttempted = mProbesCompleted;
- p.probesSucceeded = mProbesSucceeded;
- p.redirectUrl = mNmValidationRedirectUrl;
- p.timestampMillis = TIMESTAMP;
- mNmCallbacks.notifyNetworkTestedWithExtras(p);
-
- if (mNmValidationRedirectUrl != null) {
- mNmCallbacks.showProvisioningNotification(
- "test_provisioning_notif_action", TEST_PACKAGE_NAME);
- mNmProvNotificationRequested = true;
- }
- }
-
- /**
- * Connect without adding any internet capability.
- */
- public void connectWithoutInternet() {
- super.connect();
- }
-
- /**
- * Transition this NetworkAgent to CONNECTED state with NET_CAPABILITY_INTERNET.
- * @param validated Indicate if network should pretend to be validated.
- */
- public void connect(boolean validated) {
- connect(validated, true, false /* isStrictMode */);
- }
-
- /**
- * Transition this NetworkAgent to CONNECTED state.
- * @param validated Indicate if network should pretend to be validated.
- * @param hasInternet Indicate if network should pretend to have NET_CAPABILITY_INTERNET.
- */
- public void connect(boolean validated, boolean hasInternet, boolean isStrictMode) {
- assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_INTERNET));
-
- ConnectivityManager.NetworkCallback callback = null;
- final ConditionVariable validatedCv = new ConditionVariable();
- if (validated) {
- setNetworkValid(isStrictMode);
- NetworkRequest request = new NetworkRequest.Builder()
- .addTransportType(getNetworkCapabilities().getTransportTypes()[0])
- .clearCapabilities()
- .build();
- callback = new ConnectivityManager.NetworkCallback() {
- public void onCapabilitiesChanged(Network network,
- NetworkCapabilities networkCapabilities) {
- if (network.equals(getNetwork()) &&
- networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
- validatedCv.open();
- }
- }
- };
- mCm.registerNetworkCallback(request, callback);
- }
- if (hasInternet) {
- addCapability(NET_CAPABILITY_INTERNET);
- }
-
- connectWithoutInternet();
-
- if (validated) {
- // Wait for network to validate.
- waitFor(validatedCv);
- setNetworkInvalid(isStrictMode);
- }
-
- if (callback != null) mCm.unregisterNetworkCallback(callback);
- }
-
- public void connectWithCaptivePortal(String redirectUrl, boolean isStrictMode) {
- setNetworkPortal(redirectUrl, isStrictMode);
- connect(false, true /* hasInternet */, isStrictMode);
- }
-
- public void connectWithPartialConnectivity() {
- setNetworkPartial();
- connect(false);
- }
-
- public void connectWithPartialValidConnectivity(boolean isStrictMode) {
- setNetworkPartialValid(isStrictMode);
- connect(false, true /* hasInternet */, isStrictMode);
- }
-
- void setNetworkValid(boolean isStrictMode) {
- mNmValidationResult = NETWORK_VALIDATION_RESULT_VALID;
- mNmValidationRedirectUrl = null;
- int probesSucceeded = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS;
- if (isStrictMode) {
- probesSucceeded |= NETWORK_VALIDATION_PROBE_PRIVDNS;
- }
- // The probesCompleted equals to probesSucceeded for the case of valid network, so put
- // the same value into two different parameter of the method.
- setProbesStatus(probesSucceeded, probesSucceeded);
- }
-
- void setNetworkInvalid(boolean isStrictMode) {
- mNmValidationResult = VALIDATION_RESULT_INVALID;
- mNmValidationRedirectUrl = null;
- int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS
- | NETWORK_VALIDATION_PROBE_HTTP;
- int probesSucceeded = 0;
- // If the isStrictMode is true, it means the network is invalid when NetworkMonitor
- // tried to validate the private DNS but failed.
- if (isStrictMode) {
- probesCompleted &= ~NETWORK_VALIDATION_PROBE_HTTP;
- probesSucceeded = probesCompleted;
- probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS;
- }
- setProbesStatus(probesCompleted, probesSucceeded);
- }
-
- void setNetworkPortal(String redirectUrl, boolean isStrictMode) {
- setNetworkInvalid(isStrictMode);
- mNmValidationRedirectUrl = redirectUrl;
- // Suppose the portal is found when NetworkMonitor probes NETWORK_VALIDATION_PROBE_HTTP
- // in the beginning, so the NETWORK_VALIDATION_PROBE_HTTPS hasn't probed yet.
- int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTP;
- int probesSucceeded = VALIDATION_RESULT_INVALID;
- if (isStrictMode) {
- probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS;
- }
- setProbesStatus(probesCompleted, probesSucceeded);
- }
-
- void setNetworkPartial() {
- mNmValidationResult = NETWORK_VALIDATION_RESULT_PARTIAL;
- mNmValidationRedirectUrl = null;
- int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS
- | NETWORK_VALIDATION_PROBE_FALLBACK;
- int probesSucceeded = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_FALLBACK;
- setProbesStatus(probesCompleted, probesSucceeded);
- }
-
- void setNetworkPartialValid(boolean isStrictMode) {
- setNetworkPartial();
- mNmValidationResult |= NETWORK_VALIDATION_RESULT_VALID;
- int probesCompleted = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTPS
- | NETWORK_VALIDATION_PROBE_HTTP;
- int probesSucceeded = NETWORK_VALIDATION_PROBE_DNS | NETWORK_VALIDATION_PROBE_HTTP;
- // Suppose the partial network cannot pass the private DNS validation as well, so only
- // add NETWORK_VALIDATION_PROBE_DNS in probesCompleted but not probesSucceeded.
- if (isStrictMode) {
- probesCompleted |= NETWORK_VALIDATION_PROBE_PRIVDNS;
- }
- setProbesStatus(probesCompleted, probesSucceeded);
- }
-
- void setProbesStatus(int probesCompleted, int probesSucceeded) {
- mProbesCompleted = probesCompleted;
- mProbesSucceeded = probesSucceeded;
- }
-
- void notifyCapportApiDataChanged(CaptivePortalData data) {
- try {
- mNmCallbacks.notifyCaptivePortalDataChanged(data);
- } catch (RemoteException e) {
- throw new AssertionError("This cannot happen", e);
- }
- }
-
- public String waitForRedirectUrl() {
- assertTrue(mNetworkStatusReceived.block(TIMEOUT_MS));
- return mRedirectUrl;
- }
-
- public void expectDisconnected() {
- expectDisconnected(TIMEOUT_MS);
- }
-
- public void expectPreventReconnectReceived() {
- expectPreventReconnectReceived(TIMEOUT_MS);
- }
-
- void notifyDataStallSuspected() throws Exception {
- final DataStallReportParcelable p = new DataStallReportParcelable();
- p.detectionMethod = DATA_STALL_DETECTION_METHOD;
- p.timestampMillis = DATA_STALL_TIMESTAMP;
- mNmCallbacks.notifyDataStallSuspected(p);
- }
-
- public void setCreatedCallback(Runnable r) {
- mCreatedCallback = r;
- }
-
- public void setUnwantedCallback(Runnable r) {
- mUnwantedCallback = r;
- }
-
- public void setDisconnectedCallback(Runnable r) {
- mDisconnectedCallback = r;
- }
- }
-
- /**
- * A NetworkFactory that allows to wait until any in-flight NetworkRequest add or remove
- * operations have been processed and test for them.
- */
- private static class MockNetworkFactory extends NetworkFactory {
- private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
-
- static class RequestEntry {
- @NonNull
- public final NetworkRequest request;
-
- RequestEntry(@NonNull final NetworkRequest request) {
- this.request = request;
- }
-
- static final class Add extends RequestEntry {
- Add(@NonNull final NetworkRequest request) {
- super(request);
- }
- }
-
- static final class Remove extends RequestEntry {
- Remove(@NonNull final NetworkRequest request) {
- super(request);
- }
- }
-
- @Override
- public String toString() {
- return "RequestEntry [ " + getClass().getName() + " : " + request + " ]";
- }
- }
-
- // History of received requests adds and removes.
- private final ArrayTrackRecord<RequestEntry>.ReadHead mRequestHistory =
- new ArrayTrackRecord<RequestEntry>().newReadHead();
-
- private static <T> T failIfNull(@Nullable final T obj, @Nullable final String message) {
- if (null == obj) fail(null != message ? message : "Must not be null");
- return obj;
- }
-
- public RequestEntry.Add expectRequestAdd() {
- return failIfNull((RequestEntry.Add) mRequestHistory.poll(TIMEOUT_MS,
- it -> it instanceof RequestEntry.Add), "Expected request add");
- }
-
- public void expectRequestAdds(final int count) {
- for (int i = count; i > 0; --i) {
- expectRequestAdd();
- }
- }
-
- public RequestEntry.Remove expectRequestRemove() {
- return failIfNull((RequestEntry.Remove) mRequestHistory.poll(TIMEOUT_MS,
- it -> it instanceof RequestEntry.Remove), "Expected request remove");
- }
-
- public void expectRequestRemoves(final int count) {
- for (int i = count; i > 0; --i) {
- expectRequestRemove();
- }
- }
-
- // Used to collect the networks requests managed by this factory. This is a duplicate of
- // the internal information stored in the NetworkFactory (which is private).
- private SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
- private final HandlerThread mHandlerSendingRequests;
-
- public MockNetworkFactory(Looper looper, Context context, String logTag,
- NetworkCapabilities filter, HandlerThread threadSendingRequests) {
- super(looper, context, logTag, filter);
- mHandlerSendingRequests = threadSendingRequests;
- }
-
- public int getMyRequestCount() {
- return getRequestCount();
- }
-
- protected void startNetwork() {
- mNetworkStarted.set(true);
- }
-
- protected void stopNetwork() {
- mNetworkStarted.set(false);
- }
-
- public boolean getMyStartRequested() {
- return mNetworkStarted.get();
- }
-
-
- @Override
- protected void needNetworkFor(NetworkRequest request) {
- mNetworkRequests.put(request.requestId, request);
- super.needNetworkFor(request);
- mRequestHistory.add(new RequestEntry.Add(request));
- }
-
- @Override
- protected void releaseNetworkFor(NetworkRequest request) {
- mNetworkRequests.remove(request.requestId);
- super.releaseNetworkFor(request);
- mRequestHistory.add(new RequestEntry.Remove(request));
- }
-
- public void assertRequestCountEquals(final int count) {
- assertEquals(count, getMyRequestCount());
- }
-
- @Override
- public void terminate() {
- super.terminate();
- // Make sure there are no remaining requests unaccounted for.
- HandlerUtils.waitForIdle(mHandlerSendingRequests, TIMEOUT_MS);
- assertNull(mRequestHistory.poll(0, r -> true));
- }
-
- // Trigger releasing the request as unfulfillable
- public void triggerUnfulfillable(NetworkRequest r) {
- super.releaseRequestAsUnfulfillableByAnyFactory(r);
- }
-
- public void assertNoRequestChanged() {
- assertNull(mRequestHistory.poll(0, r -> true));
- }
- }
-
- private Set<UidRange> uidRangesForUids(int... uids) {
- final ArraySet<UidRange> ranges = new ArraySet<>();
- for (final int uid : uids) {
- ranges.add(new UidRange(uid, uid));
- }
- return ranges;
- }
-
- private static Looper startHandlerThreadAndReturnLooper() {
- final HandlerThread handlerThread = new HandlerThread("MockVpnThread");
- handlerThread.start();
- return handlerThread.getLooper();
- }
-
- private class MockVpn extends Vpn implements TestableNetworkCallback.HasNetwork {
- // Careful ! This is different from mNetworkAgent, because MockNetworkAgent does
- // not inherit from NetworkAgent.
- private TestNetworkAgentWrapper mMockNetworkAgent;
- private boolean mAgentRegistered = false;
-
- private int mVpnType = VpnManager.TYPE_VPN_SERVICE;
- private UnderlyingNetworkInfo mUnderlyingNetworkInfo;
-
- // These ConditionVariables allow tests to wait for LegacyVpnRunner to be stopped/started.
- // TODO: this scheme is ad-hoc and error-prone because it does not fail if, for example, the
- // test expects two starts in a row, or even if the production code calls start twice in a
- // row. find a better solution. Simply putting a method to create a LegacyVpnRunner into
- // Vpn.Dependencies doesn't work because LegacyVpnRunner is not a static class and has
- // extensive access into the internals of Vpn.
- private ConditionVariable mStartLegacyVpnCv = new ConditionVariable();
- private ConditionVariable mStopVpnRunnerCv = new ConditionVariable();
-
- public MockVpn(int userId) {
- super(startHandlerThreadAndReturnLooper(), mServiceContext,
- new Dependencies() {
- @Override
- public boolean isCallerSystem() {
- return true;
- }
-
- @Override
- public DeviceIdleInternal getDeviceIdleInternal() {
- return mDeviceIdleInternal;
- }
- },
- mNetworkManagementService, mMockNetd, userId, mVpnProfileStore);
- }
-
- public void setUids(Set<UidRange> uids) {
- mNetworkCapabilities.setUids(UidRange.toIntRanges(uids));
- if (mAgentRegistered) {
- mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities, true);
- }
- }
-
- public void setVpnType(int vpnType) {
- mVpnType = vpnType;
- }
-
- @Override
- public Network getNetwork() {
- return (mMockNetworkAgent == null) ? null : mMockNetworkAgent.getNetwork();
- }
-
- @Override
- public int getActiveVpnType() {
- return mVpnType;
- }
-
- private LinkProperties makeLinkProperties() {
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(VPN_IFNAME);
- return lp;
- }
-
- private void registerAgent(boolean isAlwaysMetered, Set<UidRange> uids, LinkProperties lp)
- throws Exception {
- if (mAgentRegistered) throw new IllegalStateException("already registered");
- updateState(NetworkInfo.DetailedState.CONNECTING, "registerAgent");
- mConfig = new VpnConfig();
- mConfig.session = "MySession12345";
- setUids(uids);
- if (!isAlwaysMetered) mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
- mInterface = VPN_IFNAME;
- mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType(),
- mConfig.session));
- mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
- mNetworkCapabilities);
- mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
-
- verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetwork().getNetId()),
- eq(toUidRangeStableParcels(uids)));
- verify(mMockNetd, never())
- .networkRemoveUidRanges(eq(mMockVpn.getNetwork().getNetId()), any());
- mAgentRegistered = true;
- verify(mMockNetd).networkCreate(nativeNetworkConfigVpn(getNetwork().netId,
- !mMockNetworkAgent.isBypassableVpn(), mVpnType));
- updateState(NetworkInfo.DetailedState.CONNECTED, "registerAgent");
- mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
- mNetworkAgent = mMockNetworkAgent.getNetworkAgent();
- }
-
- private void registerAgent(Set<UidRange> uids) throws Exception {
- registerAgent(false /* isAlwaysMetered */, uids, makeLinkProperties());
- }
-
- private void connect(boolean validated, boolean hasInternet, boolean isStrictMode) {
- mMockNetworkAgent.connect(validated, hasInternet, isStrictMode);
- }
-
- private void connect(boolean validated) {
- mMockNetworkAgent.connect(validated);
- }
-
- private TestNetworkAgentWrapper getAgent() {
- return mMockNetworkAgent;
- }
-
- public void establish(LinkProperties lp, int uid, Set<UidRange> ranges, boolean validated,
- boolean hasInternet, boolean isStrictMode) throws Exception {
- mNetworkCapabilities.setOwnerUid(uid);
- mNetworkCapabilities.setAdministratorUids(new int[]{uid});
- registerAgent(false, ranges, lp);
- connect(validated, hasInternet, isStrictMode);
- waitForIdle();
- }
-
- public void establish(LinkProperties lp, int uid, Set<UidRange> ranges) throws Exception {
- establish(lp, uid, ranges, true, true, false);
- }
-
- public void establishForMyUid(LinkProperties lp) throws Exception {
- final int uid = Process.myUid();
- establish(lp, uid, uidRangesForUids(uid), true, true, false);
- }
-
- public void establishForMyUid(boolean validated, boolean hasInternet, boolean isStrictMode)
- throws Exception {
- final int uid = Process.myUid();
- establish(makeLinkProperties(), uid, uidRangesForUids(uid), validated, hasInternet,
- isStrictMode);
- }
-
- public void establishForMyUid() throws Exception {
- establishForMyUid(makeLinkProperties());
- }
-
- public void sendLinkProperties(LinkProperties lp) {
- mMockNetworkAgent.sendLinkProperties(lp);
- }
-
- public void disconnect() {
- if (mMockNetworkAgent != null) {
- mMockNetworkAgent.disconnect();
- updateState(NetworkInfo.DetailedState.DISCONNECTED, "disconnect");
- }
- mAgentRegistered = false;
- setUids(null);
- // Remove NET_CAPABILITY_INTERNET or MockNetworkAgent will refuse to connect later on.
- mNetworkCapabilities.removeCapability(NET_CAPABILITY_INTERNET);
- mInterface = null;
- }
-
- @Override
- public void startLegacyVpnRunner() {
- mStartLegacyVpnCv.open();
- }
-
- public void expectStartLegacyVpnRunner() {
- assertTrue("startLegacyVpnRunner not called after " + TIMEOUT_MS + " ms",
- mStartLegacyVpnCv.block(TIMEOUT_MS));
-
- // startLegacyVpn calls stopVpnRunnerPrivileged, which will open mStopVpnRunnerCv, just
- // before calling startLegacyVpnRunner. Restore mStopVpnRunnerCv, so the test can expect
- // that the VpnRunner is stopped and immediately restarted by calling
- // expectStartLegacyVpnRunner() and expectStopVpnRunnerPrivileged() back-to-back.
- mStopVpnRunnerCv = new ConditionVariable();
- }
-
- @Override
- public void stopVpnRunnerPrivileged() {
- if (mVpnRunner != null) {
- super.stopVpnRunnerPrivileged();
- disconnect();
- mStartLegacyVpnCv = new ConditionVariable();
- }
- mVpnRunner = null;
- mStopVpnRunnerCv.open();
- }
-
- public void expectStopVpnRunnerPrivileged() {
- assertTrue("stopVpnRunnerPrivileged not called after " + TIMEOUT_MS + " ms",
- mStopVpnRunnerCv.block(TIMEOUT_MS));
- }
-
- @Override
- public synchronized UnderlyingNetworkInfo getUnderlyingNetworkInfo() {
- if (mUnderlyingNetworkInfo != null) return mUnderlyingNetworkInfo;
-
- return super.getUnderlyingNetworkInfo();
- }
-
- private synchronized void setUnderlyingNetworkInfo(
- UnderlyingNetworkInfo underlyingNetworkInfo) {
- mUnderlyingNetworkInfo = underlyingNetworkInfo;
- }
- }
-
- private UidRangeParcel[] toUidRangeStableParcels(final @NonNull Set<UidRange> ranges) {
- return ranges.stream().map(
- r -> new UidRangeParcel(r.start, r.stop)).toArray(UidRangeParcel[]::new);
- }
-
- private VpnManagerService makeVpnManagerService() {
- final VpnManagerService.Dependencies deps = new VpnManagerService.Dependencies() {
- public int getCallingUid() {
- return mDeps.getCallingUid();
- }
-
- public HandlerThread makeHandlerThread() {
- return mVMSHandlerThread;
- }
-
- @Override
- public VpnProfileStore getVpnProfileStore() {
- return mVpnProfileStore;
- }
-
- public INetd getNetd() {
- return mMockNetd;
- }
-
- public INetworkManagementService getINetworkManagementService() {
- return mNetworkManagementService;
- }
- };
- return new VpnManagerService(mServiceContext, deps);
- }
-
- private void assertVpnTransportInfo(NetworkCapabilities nc, int type) {
- assertNotNull(nc);
- final TransportInfo ti = nc.getTransportInfo();
- assertTrue("VPN TransportInfo is not a VpnTransportInfo: " + ti,
- ti instanceof VpnTransportInfo);
- assertEquals(type, ((VpnTransportInfo) ti).getType());
-
- }
-
- private void processBroadcast(Intent intent) {
- mServiceContext.sendBroadcast(intent);
- HandlerUtils.waitForIdle(mVMSHandlerThread, TIMEOUT_MS);
- waitForIdle();
- }
-
- private void mockVpn(int uid) {
- synchronized (mVpnManagerService.mVpns) {
- int userId = UserHandle.getUserId(uid);
- mMockVpn = new MockVpn(userId);
- // Every running user always has a Vpn in the mVpns array, even if no VPN is running.
- mVpnManagerService.mVpns.put(userId, mMockVpn);
- }
- }
-
- private void mockUidNetworkingBlocked() {
- doAnswer(i -> isUidBlocked(mBlockedReasons, i.getArgument(1))
- ).when(mNetworkPolicyManager).isUidNetworkingBlocked(anyInt(), anyBoolean());
- }
-
- private boolean isUidBlocked(int blockedReasons, boolean meteredNetwork) {
- final int blockedOnAllNetworksReason = (blockedReasons & ~BLOCKED_METERED_REASON_MASK);
- if (blockedOnAllNetworksReason != BLOCKED_REASON_NONE) {
- return true;
- }
- if (meteredNetwork) {
- return blockedReasons != BLOCKED_REASON_NONE;
- }
- return false;
- }
-
- private void setBlockedReasonChanged(int blockedReasons) {
- mBlockedReasons = blockedReasons;
- mPolicyCallback.onUidBlockedReasonChanged(Process.myUid(), blockedReasons);
- }
-
- private Nat464Xlat getNat464Xlat(NetworkAgentWrapper mna) {
- return mService.getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
- }
-
- private static class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
- volatile boolean mConfigRestrictsAvoidBadWifi;
- volatile int mConfigMeteredMultipathPreference;
-
- WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
- super(c, h, r);
- }
-
- @Override
- public boolean configRestrictsAvoidBadWifi() {
- return mConfigRestrictsAvoidBadWifi;
- }
-
- @Override
- public int configMeteredMultipathPreference() {
- return mConfigMeteredMultipathPreference;
- }
- }
-
- /**
- * Wait up to TIMEOUT_MS for {@code conditionVariable} to open.
- * Fails if TIMEOUT_MS goes by before {@code conditionVariable} opens.
- */
- static private void waitFor(ConditionVariable conditionVariable) {
- if (conditionVariable.block(TIMEOUT_MS)) {
- return;
- }
- fail("ConditionVariable was blocked for more than " + TIMEOUT_MS + "ms");
- }
-
- private <T> T doAsUid(final int uid, @NonNull final Supplier<T> what) {
- when(mDeps.getCallingUid()).thenReturn(uid);
- try {
- return what.get();
- } finally {
- returnRealCallingUid();
- }
- }
-
- private void doAsUid(final int uid, @NonNull final Runnable what) {
- doAsUid(uid, () -> {
- what.run(); return Void.TYPE;
- });
- }
-
- private void registerNetworkCallbackAsUid(NetworkRequest request, NetworkCallback callback,
- int uid) {
- doAsUid(uid, () -> {
- mCm.registerNetworkCallback(request, callback);
- });
- }
-
- private void registerDefaultNetworkCallbackAsUid(@NonNull final NetworkCallback callback,
- final int uid) {
- doAsUid(uid, () -> {
- mCm.registerDefaultNetworkCallback(callback);
- waitForIdle();
- });
- }
-
- private interface ExceptionalRunnable {
- void run() throws Exception;
- }
-
- private void withPermission(String permission, ExceptionalRunnable r) throws Exception {
- if (mServiceContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
- r.run();
- return;
- }
- try {
- mServiceContext.setPermission(permission, PERMISSION_GRANTED);
- r.run();
- } finally {
- mServiceContext.setPermission(permission, PERMISSION_DENIED);
- }
- }
-
- private static final int PRIMARY_USER = 0;
- private static final UidRange PRIMARY_UIDRANGE =
- UidRange.createForUser(UserHandle.of(PRIMARY_USER));
- private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100);
- private static final int APP2_UID = UserHandle.getUid(PRIMARY_USER, 10101);
- private static final int VPN_UID = UserHandle.getUid(PRIMARY_USER, 10043);
- private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER, "",
- UserInfo.FLAG_PRIMARY);
- private static final UserHandle PRIMARY_USER_HANDLE = new UserHandle(PRIMARY_USER);
-
- private static final int RESTRICTED_USER = 1;
- private static final UserInfo RESTRICTED_USER_INFO = new UserInfo(RESTRICTED_USER, "",
- UserInfo.FLAG_RESTRICTED);
- static {
- RESTRICTED_USER_INFO.restrictedProfileParentId = PRIMARY_USER;
- }
-
- @Before
- public void setUp() throws Exception {
- mNetIdManager = new TestNetIdManager();
-
- mContext = InstrumentationRegistry.getContext();
-
- MockitoAnnotations.initMocks(this);
-
- when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
- when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE));
- when(mUserManager.getUserInfo(PRIMARY_USER)).thenReturn(PRIMARY_USER_INFO);
- // canHaveRestrictedProfile does not take a userId. It applies to the userId of the context
- // it was started from, i.e., PRIMARY_USER.
- when(mUserManager.canHaveRestrictedProfile()).thenReturn(true);
- when(mUserManager.getUserInfo(RESTRICTED_USER)).thenReturn(RESTRICTED_USER_INFO);
-
- final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
- when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
- .thenReturn(applicationInfo);
- when(mPackageManager.getTargetSdkVersion(anyString()))
- .thenReturn(applicationInfo.targetSdkVersion);
- when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
-
- // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
- // http://b/25897652 .
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
- mockDefaultPackages();
- mockHasSystemFeature(FEATURE_WIFI, true);
- mockHasSystemFeature(FEATURE_WIFI_DIRECT, true);
- doReturn(true).when(mTelephonyManager).isDataCapable();
-
- FakeSettingsProvider.clearSettingsProvider();
- mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
- new FakeSettingsProvider());
- mServiceContext.setUseRegisteredHandlers(true);
-
- mAlarmManagerThread = new HandlerThread("TestAlarmManager");
- mAlarmManagerThread.start();
- initAlarmManager(mAlarmManager, mAlarmManagerThread.getThreadHandler());
-
- mCsHandlerThread = new HandlerThread("TestConnectivityService");
- mVMSHandlerThread = new HandlerThread("TestVpnManagerService");
- mDeps = makeDependencies();
- returnRealCallingUid();
- mService = new ConnectivityService(mServiceContext,
- mMockDnsResolver,
- mock(IpConnectivityLog.class),
- mMockNetd,
- mDeps);
- mService.mLingerDelayMs = TEST_LINGER_DELAY_MS;
- mService.mNascentDelayMs = TEST_NASCENT_DELAY_MS;
- verify(mDeps).makeMultinetworkPolicyTracker(any(), any(), any());
-
- final ArgumentCaptor<NetworkPolicyCallback> policyCallbackCaptor =
- ArgumentCaptor.forClass(NetworkPolicyCallback.class);
- verify(mNetworkPolicyManager).registerNetworkPolicyCallback(any(),
- policyCallbackCaptor.capture());
- mPolicyCallback = policyCallbackCaptor.getValue();
-
- // Create local CM before sending system ready so that we can answer
- // getSystemService() correctly.
- mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
- mService.systemReadyInternal();
- mVpnManagerService = makeVpnManagerService();
- mVpnManagerService.systemReady();
- mockVpn(Process.myUid());
- mCm.bindProcessToNetwork(null);
- mQosCallbackTracker = mock(QosCallbackTracker.class);
-
- // Ensure that the default setting for Captive Portals is used for most tests
- setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT);
- setAlwaysOnNetworks(false);
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
- }
-
- private void returnRealCallingUid() {
- doAnswer((invocationOnMock) -> Binder.getCallingUid()).when(mDeps).getCallingUid();
- }
-
- private ConnectivityService.Dependencies makeDependencies() {
- doReturn(false).when(mSystemProperties).getBoolean("ro.radio.noril", false);
- final ConnectivityService.Dependencies deps = mock(ConnectivityService.Dependencies.class);
- doReturn(mCsHandlerThread).when(deps).makeHandlerThread();
- doReturn(mNetIdManager).when(deps).makeNetIdManager();
- doReturn(mNetworkStack).when(deps).getNetworkStack();
- doReturn(mSystemProperties).when(deps).getSystemProperties();
- doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
- doReturn(true).when(deps).queryUserAccess(anyInt(), any(), any());
- doAnswer(inv -> {
- mPolicyTracker = new WrappedMultinetworkPolicyTracker(
- inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
- return mPolicyTracker;
- }).when(deps).makeMultinetworkPolicyTracker(any(), any(), any());
- doReturn(true).when(deps).getCellular464XlatEnabled();
-
- doReturn(60000).when(mResources).getInteger(R.integer.config_networkTransitionTimeout);
- doReturn("").when(mResources).getString(R.string.config_networkCaptivePortalServerUrl);
- doReturn(new String[]{ WIFI_WOL_IFNAME }).when(mResources).getStringArray(
- R.array.config_wakeonlan_supported_interfaces);
- doReturn(new String[] { "0,1", "1,3" }).when(mResources).getStringArray(
- R.array.config_networkSupportedKeepaliveCount);
- doReturn(new String[0]).when(mResources).getStringArray(
- R.array.config_networkNotifySwitches);
- doReturn(new int[]{10, 11, 12, 14, 15}).when(mResources).getIntArray(
- R.array.config_protectedNetworks);
- // We don't test the actual notification value strings, so just return an empty array.
- // It doesn't matter what the values are as long as it's not null.
- doReturn(new String[0]).when(mResources).getStringArray(R.array.network_switch_type_name);
-
- doReturn(R.array.config_networkSupportedKeepaliveCount).when(mResources)
- .getIdentifier(eq("config_networkSupportedKeepaliveCount"), eq("array"), any());
- doReturn(R.array.network_switch_type_name).when(mResources)
- .getIdentifier(eq("network_switch_type_name"), eq("array"), any());
-
-
- final ConnectivityResources connRes = mock(ConnectivityResources.class);
- doReturn(mResources).when(connRes).get();
- doReturn(connRes).when(deps).getResources(any());
-
- final Context mockResContext = mock(Context.class);
- doReturn(mResources).when(mockResContext).getResources();
- ConnectivityResources.setResourcesContextForTest(mockResContext);
-
- return deps;
- }
-
- private static void initAlarmManager(final AlarmManager am, final Handler alarmHandler) {
- doAnswer(inv -> {
- final long when = inv.getArgument(1);
- final WakeupMessage wakeupMsg = inv.getArgument(3);
- final Handler handler = inv.getArgument(4);
-
- long delayMs = when - SystemClock.elapsedRealtime();
- if (delayMs < 0) delayMs = 0;
- if (delayMs > UNREASONABLY_LONG_ALARM_WAIT_MS) {
- fail("Attempting to send msg more than " + UNREASONABLY_LONG_ALARM_WAIT_MS
- + "ms into the future: " + delayMs);
- }
- alarmHandler.postDelayed(() -> handler.post(wakeupMsg::onAlarm), wakeupMsg /* token */,
- delayMs);
-
- return null;
- }).when(am).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), anyLong(), anyString(),
- any(WakeupMessage.class), any());
-
- doAnswer(inv -> {
- final WakeupMessage wakeupMsg = inv.getArgument(0);
- alarmHandler.removeCallbacksAndMessages(wakeupMsg /* token */);
- return null;
- }).when(am).cancel(any(WakeupMessage.class));
- }
-
- @After
- public void tearDown() throws Exception {
- unregisterDefaultNetworkCallbacks();
- maybeTearDownEnterpriseNetwork();
- setAlwaysOnNetworks(false);
- if (mCellNetworkAgent != null) {
- mCellNetworkAgent.disconnect();
- mCellNetworkAgent = null;
- }
- if (mWiFiNetworkAgent != null) {
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent = null;
- }
- if (mEthernetNetworkAgent != null) {
- mEthernetNetworkAgent.disconnect();
- mEthernetNetworkAgent = null;
- }
-
- if (mQosCallbackMockHelper != null) {
- mQosCallbackMockHelper.tearDown();
- mQosCallbackMockHelper = null;
- }
- mMockVpn.disconnect();
- waitForIdle();
-
- FakeSettingsProvider.clearSettingsProvider();
- ConnectivityResources.setResourcesContextForTest(null);
-
- mCsHandlerThread.quitSafely();
- mAlarmManagerThread.quitSafely();
- }
-
- private void mockDefaultPackages() throws Exception {
- final String myPackageName = mContext.getPackageName();
- final PackageInfo myPackageInfo = mContext.getPackageManager().getPackageInfo(
- myPackageName, PackageManager.GET_PERMISSIONS);
- when(mPackageManager.getPackagesForUid(Binder.getCallingUid())).thenReturn(
- new String[] {myPackageName});
- when(mPackageManager.getPackageInfoAsUser(eq(myPackageName), anyInt(),
- eq(UserHandle.getCallingUserId()))).thenReturn(myPackageInfo);
-
- when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
- Arrays.asList(new PackageInfo[] {
- buildPackageInfo(/* SYSTEM */ false, APP1_UID),
- buildPackageInfo(/* SYSTEM */ false, APP2_UID),
- buildPackageInfo(/* SYSTEM */ false, VPN_UID)
- }));
-
- // Create a fake always-on VPN package.
- final int userId = UserHandle.getCallingUserId();
- final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.targetSdkVersion = Build.VERSION_CODES.R; // Always-on supported in N+.
- when(mPackageManager.getApplicationInfoAsUser(eq(ALWAYS_ON_PACKAGE), anyInt(),
- eq(userId))).thenReturn(applicationInfo);
-
- // Minimal mocking to keep Vpn#isAlwaysOnPackageSupported happy.
- ResolveInfo rInfo = new ResolveInfo();
- rInfo.serviceInfo = new ServiceInfo();
- rInfo.serviceInfo.metaData = new Bundle();
- final List<ResolveInfo> services = Arrays.asList(new ResolveInfo[]{rInfo});
- when(mPackageManager.queryIntentServicesAsUser(any(), eq(PackageManager.GET_META_DATA),
- eq(userId))).thenReturn(services);
- when(mPackageManager.getPackageUidAsUser(TEST_PACKAGE_NAME, userId))
- .thenReturn(Process.myUid());
- when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, userId))
- .thenReturn(VPN_UID);
- }
-
- private void verifyActiveNetwork(int transport) {
- // Test getActiveNetworkInfo()
- assertNotNull(mCm.getActiveNetworkInfo());
- assertEquals(transportToLegacyType(transport), mCm.getActiveNetworkInfo().getType());
- // Test getActiveNetwork()
- assertNotNull(mCm.getActiveNetwork());
- assertEquals(mCm.getActiveNetwork(), mCm.getActiveNetworkForUid(Process.myUid()));
- if (!NetworkCapabilities.isValidTransport(transport)) {
- throw new IllegalStateException("Unknown transport " + transport);
- }
- switch (transport) {
- case TRANSPORT_WIFI:
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- break;
- case TRANSPORT_CELLULAR:
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- break;
- case TRANSPORT_ETHERNET:
- assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- break;
- default:
- break;
- }
- // Test getNetworkInfo(Network)
- assertNotNull(mCm.getNetworkInfo(mCm.getActiveNetwork()));
- assertEquals(transportToLegacyType(transport),
- mCm.getNetworkInfo(mCm.getActiveNetwork()).getType());
- assertNotNull(mCm.getActiveNetworkInfoForUid(Process.myUid()));
- // Test getNetworkCapabilities(Network)
- assertNotNull(mCm.getNetworkCapabilities(mCm.getActiveNetwork()));
- assertTrue(mCm.getNetworkCapabilities(mCm.getActiveNetwork()).hasTransport(transport));
- }
-
- private void verifyNoNetwork() {
- waitForIdle();
- // Test getActiveNetworkInfo()
- assertNull(mCm.getActiveNetworkInfo());
- // Test getActiveNetwork()
- assertNull(mCm.getActiveNetwork());
- assertNull(mCm.getActiveNetworkForUid(Process.myUid()));
- // Test getAllNetworks()
- assertEmpty(mCm.getAllNetworks());
- assertEmpty(mCm.getAllNetworkStateSnapshots());
- }
-
- /**
- * Class to simplify expecting broadcasts using BroadcastInterceptingContext.
- * Ensures that the receiver is unregistered after the expected broadcast is received. This
- * cannot be done in the BroadcastReceiver itself because BroadcastInterceptingContext runs
- * the receivers' receive method while iterating over the list of receivers, and unregistering
- * the receiver during iteration throws ConcurrentModificationException.
- */
- private class ExpectedBroadcast extends CompletableFuture<Intent> {
- private final BroadcastReceiver mReceiver;
-
- ExpectedBroadcast(BroadcastReceiver receiver) {
- mReceiver = receiver;
- }
-
- public Intent expectBroadcast(int timeoutMs) throws Exception {
- try {
- return get(timeoutMs, TimeUnit.MILLISECONDS);
- } catch (TimeoutException e) {
- fail("Expected broadcast not received after " + timeoutMs + " ms");
- return null;
- } finally {
- mServiceContext.unregisterReceiver(mReceiver);
- }
- }
-
- public Intent expectBroadcast() throws Exception {
- return expectBroadcast(BROADCAST_TIMEOUT_MS);
- }
-
- public void expectNoBroadcast(int timeoutMs) throws Exception {
- waitForIdle();
- try {
- final Intent intent = get(timeoutMs, TimeUnit.MILLISECONDS);
- fail("Unexpected broadcast: " + intent.getAction() + " " + intent.getExtras());
- } catch (TimeoutException expected) {
- } finally {
- mServiceContext.unregisterReceiver(mReceiver);
- }
- }
- }
-
- /** Expects that {@code count} CONNECTIVITY_ACTION broadcasts are received. */
- private ExpectedBroadcast registerConnectivityBroadcast(final int count) {
- return registerConnectivityBroadcastThat(count, intent -> true);
- }
-
- private ExpectedBroadcast registerConnectivityBroadcastThat(final int count,
- @NonNull final Predicate<Intent> filter) {
- final IntentFilter intentFilter = new IntentFilter(CONNECTIVITY_ACTION);
- // AtomicReference allows receiver to access expected even though it is constructed later.
- final AtomicReference<ExpectedBroadcast> expectedRef = new AtomicReference<>();
- final BroadcastReceiver receiver = new BroadcastReceiver() {
- private int mRemaining = count;
- public void onReceive(Context context, Intent intent) {
- final int type = intent.getIntExtra(EXTRA_NETWORK_TYPE, -1);
- final NetworkInfo ni = intent.getParcelableExtra(EXTRA_NETWORK_INFO);
- Log.d(TAG, "Received CONNECTIVITY_ACTION type=" + type + " ni=" + ni);
- if (!filter.test(intent)) return;
- if (--mRemaining == 0) {
- expectedRef.get().complete(intent);
- }
- }
- };
- final ExpectedBroadcast expected = new ExpectedBroadcast(receiver);
- expectedRef.set(expected);
- mServiceContext.registerReceiver(receiver, intentFilter);
- return expected;
- }
-
- private boolean extraInfoInBroadcastHasExpectedNullness(NetworkInfo ni) {
- final DetailedState state = ni.getDetailedState();
- if (state == DetailedState.CONNECTED && ni.getExtraInfo() == null) return false;
- // Expect a null extraInfo if the network is CONNECTING, because a CONNECTIVITY_ACTION
- // broadcast with a state of CONNECTING only happens due to legacy VPN lockdown, which also
- // nulls out extraInfo.
- if (state == DetailedState.CONNECTING && ni.getExtraInfo() != null) return false;
- // Can't make any assertions about DISCONNECTED broadcasts. When a network actually
- // disconnects, disconnectAndDestroyNetwork sets its state to DISCONNECTED and its extraInfo
- // to null. But if the DISCONNECTED broadcast is just simulated by LegacyTypeTracker due to
- // a network switch, extraInfo will likely be populated.
- // This is likely a bug in CS, but likely not one we can fix without impacting apps.
- return true;
- }
-
- private ExpectedBroadcast expectConnectivityAction(int type, NetworkInfo.DetailedState state) {
- return registerConnectivityBroadcastThat(1, intent -> {
- final int actualType = intent.getIntExtra(EXTRA_NETWORK_TYPE, -1);
- final NetworkInfo ni = intent.getParcelableExtra(EXTRA_NETWORK_INFO);
- return type == actualType
- && state == ni.getDetailedState()
- && extraInfoInBroadcastHasExpectedNullness(ni);
- });
- }
-
- @Test
- public void testNetworkTypes() {
- // Ensure that our mocks for the networkAttributes config variable work as expected. If they
- // don't, then tests that depend on CONNECTIVITY_ACTION broadcasts for these network types
- // will fail. Failing here is much easier to debug.
- assertTrue(mCm.isNetworkSupported(TYPE_WIFI));
- assertTrue(mCm.isNetworkSupported(TYPE_MOBILE));
- assertTrue(mCm.isNetworkSupported(TYPE_MOBILE_MMS));
- assertTrue(mCm.isNetworkSupported(TYPE_MOBILE_FOTA));
- assertFalse(mCm.isNetworkSupported(TYPE_PROXY));
-
- // Check that TYPE_ETHERNET is supported. Unlike the asserts above, which only validate our
- // mocks, this assert exercises the ConnectivityService code path that ensures that
- // TYPE_ETHERNET is supported if the ethernet service is running.
- assertTrue(mCm.isNetworkSupported(TYPE_ETHERNET));
- }
-
- @Test
- public void testNetworkFeature() throws Exception {
- // Connect the cell agent and wait for the connected broadcast.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_SUPL);
- ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
-
- // Build legacy request for SUPL.
- final NetworkCapabilities legacyCaps = new NetworkCapabilities();
- legacyCaps.addTransportType(TRANSPORT_CELLULAR);
- legacyCaps.addCapability(NET_CAPABILITY_SUPL);
- final NetworkRequest legacyRequest = new NetworkRequest(legacyCaps, TYPE_MOBILE_SUPL,
- ConnectivityManager.REQUEST_ID_UNSET, NetworkRequest.Type.REQUEST);
-
- // File request, withdraw it and make sure no broadcast is sent
- b = registerConnectivityBroadcast(1);
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.requestNetwork(legacyRequest, callback);
- callback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
- mCm.unregisterNetworkCallback(callback);
- b.expectNoBroadcast(800); // 800ms long enough to at least flake if this is sent
-
- // Disconnect the network and expect mobile disconnected broadcast.
- b = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
- mCellNetworkAgent.disconnect();
- b.expectBroadcast();
- }
-
- @Test
- public void testLingering() throws Exception {
- verifyNoNetwork();
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- assertNull(mCm.getActiveNetworkInfo());
- assertNull(mCm.getActiveNetwork());
- // Test bringing up validated cellular.
- ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- assertLength(2, mCm.getAllNetworks());
- assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) ||
- mCm.getAllNetworks()[1].equals(mCm.getActiveNetwork()));
- assertTrue(mCm.getAllNetworks()[0].equals(mWiFiNetworkAgent.getNetwork()) ||
- mCm.getAllNetworks()[1].equals(mWiFiNetworkAgent.getNetwork()));
- // Test bringing up validated WiFi.
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- assertLength(2, mCm.getAllNetworks());
- assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) ||
- mCm.getAllNetworks()[1].equals(mCm.getActiveNetwork()));
- assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) ||
- mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork()));
- // Test cellular linger timeout.
- mCellNetworkAgent.expectDisconnected();
- waitForIdle();
- assertLength(1, mCm.getAllNetworks());
- verifyActiveNetwork(TRANSPORT_WIFI);
- assertLength(1, mCm.getAllNetworks());
- assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());
- // Test WiFi disconnect.
- b = registerConnectivityBroadcast(1);
- mWiFiNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyNoNetwork();
- }
-
- /**
- * Verify a newly created network will be inactive instead of torn down even if no one is
- * requesting.
- */
- @Test
- public void testNewNetworkInactive() throws Exception {
- // Create a callback that monitoring the testing network.
- final TestNetworkCallback listenCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(new NetworkRequest.Builder().build(), listenCallback);
-
- // 1. Create a network that is not requested by anyone, and does not satisfy any of the
- // default requests. Verify that the network will be inactive instead of torn down.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithoutInternet();
- listenCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- listenCallback.assertNoCallback();
-
- // Verify that the network will be torn down after nascent expiry. A small period of time
- // is added in case of flakiness.
- final int nascentTimeoutMs =
- mService.mNascentDelayMs + mService.mNascentDelayMs / 4;
- listenCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent, nascentTimeoutMs);
-
- // 2. Create a network that is satisfied by a request comes later.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithoutInternet();
- listenCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- final TestNetworkCallback wifiCallback = new TestNetworkCallback();
- mCm.requestNetwork(wifiRequest, wifiCallback);
- wifiCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- // Verify that the network will be kept since the request is still satisfied. And is able
- // to get disconnected as usual if the request is released after the nascent timer expires.
- listenCallback.assertNoCallback(nascentTimeoutMs);
- mCm.unregisterNetworkCallback(wifiCallback);
- listenCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // 3. Create a network that is satisfied by a request comes later.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithoutInternet();
- listenCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- mCm.requestNetwork(wifiRequest, wifiCallback);
- wifiCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- // Verify that the network will still be torn down after the request gets removed.
- mCm.unregisterNetworkCallback(wifiCallback);
- listenCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // There is no need to ensure that LOSING is never sent in the common case that the
- // network immediately satisfies a request that was already present, because it is already
- // verified anywhere whenever {@code TestNetworkCallback#expectAvailable*} is called.
-
- mCm.unregisterNetworkCallback(listenCallback);
- }
-
- /**
- * Verify a newly created network will be inactive and switch to background if only background
- * request is satisfied.
- */
- @Test
- public void testNewNetworkInactive_bgNetwork() throws Exception {
- // Create a callback that monitoring the wifi network.
- final TestNetworkCallback wifiListenCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build(), wifiListenCallback);
-
- // Create callbacks that can monitor background and foreground mobile networks.
- // This is done by granting using background networks permission before registration. Thus,
- // the service will not add {@code NET_CAPABILITY_FOREGROUND} by default.
- grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
- final TestNetworkCallback bgMobileListenCallback = new TestNetworkCallback();
- final TestNetworkCallback fgMobileListenCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build(), bgMobileListenCallback);
- mCm.registerNetworkCallback(new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_FOREGROUND).build(), fgMobileListenCallback);
-
- // Connect wifi, which satisfies default request.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- wifiListenCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
-
- // Connect a cellular network, verify that satisfies only the background callback.
- setAlwaysOnNetworks(true);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- bgMobileListenCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- fgMobileListenCallback.assertNoCallback();
- assertFalse(isForegroundNetwork(mCellNetworkAgent));
-
- mCellNetworkAgent.disconnect();
- bgMobileListenCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- fgMobileListenCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(wifiListenCallback);
- mCm.unregisterNetworkCallback(bgMobileListenCallback);
- mCm.unregisterNetworkCallback(fgMobileListenCallback);
- }
-
- @Test
- public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
- // Test bringing up unvalidated WiFi
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test bringing up unvalidated cellular
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false);
- waitForIdle();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test cellular disconnect.
- mCellNetworkAgent.disconnect();
- waitForIdle();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test bringing up validated cellular
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- b = registerConnectivityBroadcast(2);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test cellular disconnect.
- b = registerConnectivityBroadcast(2);
- mCellNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test WiFi disconnect.
- b = registerConnectivityBroadcast(1);
- mWiFiNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyNoNetwork();
- }
-
- @Test
- public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception {
- // Test bringing up unvalidated cellular.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mCellNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test bringing up unvalidated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test WiFi disconnect.
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test cellular disconnect.
- b = registerConnectivityBroadcast(1);
- mCellNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyNoNetwork();
- }
-
- @Test
- public void testUnlingeringDoesNotValidate() throws Exception {
- // Test bringing up unvalidated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- // Test bringing up validated cellular.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- b = registerConnectivityBroadcast(2);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- // Test cellular disconnect.
- b = registerConnectivityBroadcast(2);
- mCellNetworkAgent.disconnect();
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Unlingering a network should not cause it to be marked as validated.
- assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- }
-
- @Test
- public void testCellularOutscoresWeakWifi() throws Exception {
- // Test bringing up validated cellular.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test bringing up validated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test WiFi getting really weak.
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.adjustScore(-11);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test WiFi restoring signal strength.
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.adjustScore(11);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- }
-
- @Test
- public void testReapingNetwork() throws Exception {
- // Test bringing up WiFi without NET_CAPABILITY_INTERNET.
- // Expect it to be torn down immediately because it satisfies no requests.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithoutInternet();
- mWiFiNetworkAgent.expectDisconnected();
- // Test bringing up cellular without NET_CAPABILITY_INTERNET.
- // Expect it to be torn down immediately because it satisfies no requests.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mCellNetworkAgent.connectWithoutInternet();
- mCellNetworkAgent.expectDisconnected();
- // Test bringing up validated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test bringing up unvalidated cellular.
- // Expect it to be torn down because it could never be the highest scoring network
- // satisfying the default request even if it validated.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false);
- mCellNetworkAgent.expectDisconnected();
- verifyActiveNetwork(TRANSPORT_WIFI);
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- }
-
- @Test
- public void testCellularFallback() throws Exception {
- // Test bringing up validated cellular.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Test bringing up validated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Reevaluate WiFi (it'll instantly fail DNS).
- b = registerConnectivityBroadcast(2);
- assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- mCm.reportBadNetwork(mWiFiNetworkAgent.getNetwork());
- // Should quickly fall back to Cellular.
- b.expectBroadcast();
- assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Reevaluate cellular (it'll instantly fail DNS).
- b = registerConnectivityBroadcast(2);
- assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
- // Should quickly fall back to WiFi.
- b.expectBroadcast();
- assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- verifyActiveNetwork(TRANSPORT_WIFI);
- }
-
- @Test
- public void testWiFiFallback() throws Exception {
- // Test bringing up unvalidated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mWiFiNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- // Test bringing up validated cellular.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- b = registerConnectivityBroadcast(2);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- // Reevaluate cellular (it'll instantly fail DNS).
- b = registerConnectivityBroadcast(2);
- assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
- // Should quickly fall back to WiFi.
- b.expectBroadcast();
- assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
- NET_CAPABILITY_VALIDATED));
- verifyActiveNetwork(TRANSPORT_WIFI);
- }
-
- @Test
- public void testRequiresValidation() {
- assertTrue(NetworkMonitorUtils.isValidationRequired(
- mCm.getDefaultRequest().networkCapabilities));
- }
-
- /**
- * Utility NetworkCallback for testing. The caller must explicitly test for all the callbacks
- * this class receives, by calling expectCallback() exactly once each time a callback is
- * received. assertNoCallback may be called at any time.
- */
- private class TestNetworkCallback extends TestableNetworkCallback {
- TestNetworkCallback() {
- super(TEST_CALLBACK_TIMEOUT_MS);
- }
-
- @Override
- public void assertNoCallback() {
- // TODO: better support this use case in TestableNetworkCallback
- waitForIdle();
- assertNoCallback(0 /* timeout */);
- }
-
- @Override
- public <T extends CallbackEntry> T expectCallback(final KClass<T> type, final HasNetwork n,
- final long timeoutMs) {
- final T callback = super.expectCallback(type, n, timeoutMs);
- if (callback instanceof CallbackEntry.Losing) {
- // TODO : move this to the specific test(s) needing this rather than here.
- final CallbackEntry.Losing losing = (CallbackEntry.Losing) callback;
- final int maxMsToLive = losing.getMaxMsToLive();
- String msg = String.format(
- "Invalid linger time value %d, must be between %d and %d",
- maxMsToLive, 0, mService.mLingerDelayMs);
- assertTrue(msg, 0 <= maxMsToLive && maxMsToLive <= mService.mLingerDelayMs);
- }
- return callback;
- }
- }
-
- // Can't be part of TestNetworkCallback because "cannot be declared static; static methods can
- // only be declared in a static or top level type".
- static void assertNoCallbacks(TestNetworkCallback ... callbacks) {
- for (TestNetworkCallback c : callbacks) {
- c.assertNoCallback();
- }
- }
-
- static void expectOnLost(TestNetworkAgentWrapper network, TestNetworkCallback ... callbacks) {
- for (TestNetworkCallback c : callbacks) {
- c.expectCallback(CallbackEntry.LOST, network);
- }
- }
-
- static void expectAvailableCallbacksUnvalidatedWithSpecifier(TestNetworkAgentWrapper network,
- NetworkSpecifier specifier, TestNetworkCallback ... callbacks) {
- for (TestNetworkCallback c : callbacks) {
- c.expectCallback(CallbackEntry.AVAILABLE, network);
- c.expectCapabilitiesThat(network, (nc) ->
- !nc.hasCapability(NET_CAPABILITY_VALIDATED)
- && Objects.equals(specifier, nc.getNetworkSpecifier()));
- c.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, network);
- c.expectCallback(CallbackEntry.BLOCKED_STATUS, network);
- }
- }
-
- @Test
- public void testStateChangeNetworkCallbacks() throws Exception {
- final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest genericRequest = new NetworkRequest.Builder()
- .clearCapabilities().build();
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
- mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
- mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
-
- // Test unvalidated networks
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false);
- genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- cellNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- b.expectBroadcast();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- // This should not trigger spurious onAvailable() callbacks, b/21762680.
- mCellNetworkAgent.adjustScore(-1);
- waitForIdle();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- b.expectBroadcast();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- b = registerConnectivityBroadcast(2);
- mWiFiNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- b.expectBroadcast();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- b = registerConnectivityBroadcast(1);
- mCellNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- b.expectBroadcast();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- // Test validated networks
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- genericNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- // This should not trigger spurious onAvailable() callbacks, b/21762680.
- mCellNetworkAgent.adjustScore(-1);
- waitForIdle();
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- genericNetworkCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- wifiNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- mWiFiNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
-
- mCellNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
- }
-
- private void doNetworkCallbacksSanitizationTest(boolean sanitized) throws Exception {
- final TestNetworkCallback callback = new TestNetworkCallback();
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- mCm.registerNetworkCallback(wifiRequest, callback);
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- final LinkProperties newLp = new LinkProperties();
- final Uri capportUrl = Uri.parse("https://capport.example.com/api");
- final CaptivePortalData capportData = new CaptivePortalData.Builder()
- .setCaptive(true).build();
-
- final Uri expectedCapportUrl = sanitized ? null : capportUrl;
- newLp.setCaptivePortalApiUrl(capportUrl);
- mWiFiNetworkAgent.sendLinkProperties(newLp);
- callback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
- Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()));
- defaultCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
- Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()));
-
- final CaptivePortalData expectedCapportData = sanitized ? null : capportData;
- mWiFiNetworkAgent.notifyCapportApiDataChanged(capportData);
- callback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
- Objects.equals(expectedCapportData, lp.getCaptivePortalData()));
- defaultCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
- Objects.equals(expectedCapportData, lp.getCaptivePortalData()));
-
- final LinkProperties lp = mCm.getLinkProperties(mWiFiNetworkAgent.getNetwork());
- assertEquals(expectedCapportUrl, lp.getCaptivePortalApiUrl());
- assertEquals(expectedCapportData, lp.getCaptivePortalData());
- }
-
- @Test
- public void networkCallbacksSanitizationTest_Sanitize() throws Exception {
- mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- PERMISSION_DENIED);
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
- doNetworkCallbacksSanitizationTest(true /* sanitized */);
- }
-
- @Test
- public void networkCallbacksSanitizationTest_NoSanitize_NetworkStack() throws Exception {
- mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- PERMISSION_GRANTED);
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
- doNetworkCallbacksSanitizationTest(false /* sanitized */);
- }
-
- @Test
- public void networkCallbacksSanitizationTest_NoSanitize_Settings() throws Exception {
- mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- PERMISSION_DENIED);
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
- doNetworkCallbacksSanitizationTest(false /* sanitized */);
- }
-
- @Test
- public void testOwnerUidCannotChange() throws Exception {
- final NetworkCapabilities ncTemplate = new NetworkCapabilities();
- final int originalOwnerUid = Process.myUid();
- ncTemplate.setOwnerUid(originalOwnerUid);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(),
- ncTemplate);
- mWiFiNetworkAgent.connect(false);
- waitForIdle();
-
- // Send ConnectivityService an update to the mWiFiNetworkAgent's capabilities that changes
- // the owner UID and an unrelated capability.
- NetworkCapabilities agentCapabilities = mWiFiNetworkAgent.getNetworkCapabilities();
- assertEquals(originalOwnerUid, agentCapabilities.getOwnerUid());
- agentCapabilities.setOwnerUid(42);
- assertFalse(agentCapabilities.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- agentCapabilities.addCapability(NET_CAPABILITY_NOT_CONGESTED);
- mWiFiNetworkAgent.setNetworkCapabilities(agentCapabilities, true);
- waitForIdle();
-
- // Owner UIDs are not visible without location permission.
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- // Check that the capability change has been applied but the owner UID is not modified.
- NetworkCapabilities nc = mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork());
- assertEquals(originalOwnerUid, nc.getOwnerUid());
- assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- }
-
- @Test
- public void testMultipleLingering() throws Exception {
- // This test would be flaky with the default 120ms timer: that is short enough that
- // lingered networks are torn down before assertions can be run. We don't want to mock the
- // lingering timer to keep the WakeupMessage logic realistic: this has already proven useful
- // in detecting races.
- mService.mLingerDelayMs = 300;
-
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities().addCapability(NET_CAPABILITY_NOT_METERED)
- .build();
- TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
-
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
-
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mWiFiNetworkAgent.connect(true);
- // We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request.
- // We then get LOSING when wifi validates and cell is outscored.
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- // TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mEthernetNetworkAgent.connect(true);
- callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
- // TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackEntry.LOSING, mWiFiNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
- assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
- defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- for (int i = 0; i < 4; i++) {
- TestNetworkAgentWrapper oldNetwork, newNetwork;
- if (i % 2 == 0) {
- mWiFiNetworkAgent.adjustScore(-15);
- oldNetwork = mWiFiNetworkAgent;
- newNetwork = mCellNetworkAgent;
- } else {
- mWiFiNetworkAgent.adjustScore(15);
- oldNetwork = mCellNetworkAgent;
- newNetwork = mWiFiNetworkAgent;
-
- }
- callback.expectCallback(CallbackEntry.LOSING, oldNetwork);
- // TODO: should we send an AVAILABLE callback to newNetwork, to indicate that it is no
- // longer lingering?
- defaultCallback.expectAvailableCallbacksValidated(newNetwork);
- assertEquals(newNetwork.getNetwork(), mCm.getActiveNetwork());
- }
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Verify that if a network no longer satisfies a request, we send LOST and not LOSING, even
- // if the network is still up.
- mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- // We expect a notification about the capabilities change, and nothing else.
- defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
- defaultCallback.assertNoCallback();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Wifi no longer satisfies our listen, which is for an unmetered network.
- // But because its score is 55, it's still up (and the default network).
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Disconnect our test networks.
- mWiFiNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- waitForIdle();
- assertEquals(null, mCm.getActiveNetwork());
-
- mCm.unregisterNetworkCallback(callback);
- waitForIdle();
-
- // Check that a network is only lingered or torn down if it would not satisfy a request even
- // if it validated.
- request = new NetworkRequest.Builder().clearCapabilities().build();
- callback = new TestNetworkCallback();
-
- mCm.registerNetworkCallback(request, callback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false); // Score: 10
- callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring up wifi with a score of 20.
- // Cell stays up because it would satisfy the default request if it validated.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false); // Score: 20
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
- // it's arguably correct to linger it, since it was the default network before it validated.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- // TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- mCellNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- waitForIdle();
- assertEquals(null, mCm.getActiveNetwork());
-
- // If a network is lingering, and we add and remove a request from it, resume lingering.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- // TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- NetworkCallback noopCallback = new NetworkCallback();
- mCm.requestNetwork(cellRequest, noopCallback);
- // TODO: should this cause an AVAILABLE callback, to indicate that the network is no longer
- // lingering?
- mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
-
- // Similar to the above: lingering can start even after the lingered request is removed.
- // Disconnect wifi and switch to cell.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Cell is now the default network. Pin it with a cell-specific request.
- noopCallback = new NetworkCallback(); // Can't reuse NetworkCallbacks. http://b/20701525
- mCm.requestNetwork(cellRequest, noopCallback);
-
- // Now connect wifi, and expect it to become the default network.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- // The default request is lingering on cell, but nothing happens to cell, and we send no
- // callbacks for it, because it's kept up by cellRequest.
- callback.assertNoCallback();
- // Now unregister cellRequest and expect cell to start lingering.
- mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
-
- // Let linger run its course.
- callback.assertNoCallback();
- final int lingerTimeoutMs = mService.mLingerDelayMs + mService.mLingerDelayMs / 4;
- callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent, lingerTimeoutMs);
-
- // Register a TRACK_DEFAULT request and check that it does not affect lingering.
- TestNetworkCallback trackDefaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(trackDefaultCallback);
- trackDefaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
- mEthernetNetworkAgent.connect(true);
- callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mWiFiNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
- trackDefaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Let linger run its course.
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent, lingerTimeoutMs);
-
- // Clean up.
- mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
- trackDefaultCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
-
- mCm.unregisterNetworkCallback(callback);
- mCm.unregisterNetworkCallback(defaultCallback);
- mCm.unregisterNetworkCallback(trackDefaultCallback);
- }
-
- private void grantUsingBackgroundNetworksPermissionForUid(final int uid) throws Exception {
- grantUsingBackgroundNetworksPermissionForUid(uid, mContext.getPackageName());
- }
-
- private void grantUsingBackgroundNetworksPermissionForUid(
- final int uid, final String packageName) throws Exception {
- when(mPackageManager.getPackageInfo(
- eq(packageName), eq(GET_PERMISSIONS | MATCH_ANY_USER)))
- .thenReturn(buildPackageInfo(true /* hasSystemPermission */, uid));
- mService.mPermissionMonitor.onPackageAdded(packageName, uid);
- }
-
- @Test
- public void testNetworkGoesIntoBackgroundAfterLinger() throws Exception {
- setAlwaysOnNetworks(true);
- grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities()
- .build();
- TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-
- // Wifi comes up and cell lingers.
- mWiFiNetworkAgent.connect(true);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
-
- // File a request for cellular, then release it.
- NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- NetworkCallback noopCallback = new NetworkCallback();
- mCm.requestNetwork(cellRequest, noopCallback);
- mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
-
- // Let linger run its course.
- callback.assertNoCallback();
- final int lingerTimeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
- callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent,
- lingerTimeoutMs);
-
- // Clean up.
- mCm.unregisterNetworkCallback(defaultCallback);
- mCm.unregisterNetworkCallback(callback);
- }
-
- private NativeNetworkConfig nativeNetworkConfigPhysical(int netId, int permission) {
- return new NativeNetworkConfig(netId, NativeNetworkType.PHYSICAL, permission,
- /*secure=*/ false, VpnManager.TYPE_VPN_NONE);
- }
-
- private NativeNetworkConfig nativeNetworkConfigVpn(int netId, boolean secure, int vpnType) {
- return new NativeNetworkConfig(netId, NativeNetworkType.VIRTUAL, INetd.PERMISSION_NONE,
- secure, vpnType);
- }
-
- @Test
- public void testNetworkAgentCallbacks() throws Exception {
- // Keeps track of the order of events that happen in this test.
- final LinkedBlockingQueue<String> eventOrder = new LinkedBlockingQueue<>();
-
- final NetworkRequest request = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- final AtomicReference<Network> wifiNetwork = new AtomicReference<>();
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-
- // Expectations for state when various callbacks fire. These expectations run on the handler
- // thread and not on the test thread because they need to prevent the handler thread from
- // advancing while they examine state.
-
- // 1. When onCreated fires, netd has been told to create the network.
- mWiFiNetworkAgent.setCreatedCallback(() -> {
- eventOrder.offer("onNetworkCreated");
- wifiNetwork.set(mWiFiNetworkAgent.getNetwork());
- assertNotNull(wifiNetwork.get());
- try {
- verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- wifiNetwork.get().getNetId(), INetd.PERMISSION_NONE));
- } catch (RemoteException impossible) {
- fail();
- }
- });
-
- // 2. onNetworkUnwanted isn't precisely ordered with respect to any particular events. Just
- // check that it is fired at some point after disconnect.
- mWiFiNetworkAgent.setUnwantedCallback(() -> eventOrder.offer("onNetworkUnwanted"));
-
- // 3. While the teardown timer is running, connectivity APIs report the network is gone, but
- // netd has not yet been told to destroy it.
- final Runnable duringTeardown = () -> {
- eventOrder.offer("timePasses");
- assertNull(mCm.getLinkProperties(wifiNetwork.get()));
- try {
- verify(mMockNetd, never()).networkDestroy(wifiNetwork.get().getNetId());
- } catch (RemoteException impossible) {
- fail();
- }
- };
-
- // 4. After onNetworkDisconnected is called, connectivity APIs report the network is gone,
- // and netd has been told to destroy it.
- mWiFiNetworkAgent.setDisconnectedCallback(() -> {
- eventOrder.offer("onNetworkDisconnected");
- assertNull(mCm.getLinkProperties(wifiNetwork.get()));
- try {
- verify(mMockNetd).networkDestroy(wifiNetwork.get().getNetId());
- } catch (RemoteException impossible) {
- fail();
- }
- });
-
- // Connect a network, and file a request for it after it has come up, to ensure the nascent
- // timer is cleared and the test does not have to wait for it. Filing the request after the
- // network has come up is necessary because ConnectivityService does not appear to clear the
- // nascent timer if the first request satisfied by the network was filed before the network
- // connected.
- // TODO: fix this bug, file the request before connecting, and remove the waitForIdle.
- mWiFiNetworkAgent.connectWithoutInternet();
- waitForIdle();
- mCm.requestNetwork(request, callback);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- // Set teardown delay and make sure CS has processed it.
- mWiFiNetworkAgent.getNetworkAgent().setTeardownDelayMillis(300);
- waitForIdle();
-
- // Post the duringTeardown lambda to the handler so it fires while teardown is in progress.
- // The delay must be long enough it will run after the unregisterNetworkCallback has torn
- // down the network and started the teardown timer, and short enough that the lambda is
- // scheduled to run before the teardown timer.
- final Handler h = new Handler(mCsHandlerThread.getLooper());
- h.postDelayed(duringTeardown, 150);
-
- // Disconnect the network and check that events happened in the right order.
- mCm.unregisterNetworkCallback(callback);
- assertEquals("onNetworkCreated", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- assertEquals("onNetworkUnwanted", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- assertEquals("timePasses", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- assertEquals("onNetworkDisconnected", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
- mCm.unregisterNetworkCallback(callback);
- }
-
- @Test
- public void testExplicitlySelected() throws Exception {
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
- .build();
- TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- // Bring up validated cell.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-
- // Bring up unvalidated wifi with explicitlySelected=true.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(true, false);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- // Cell Remains the default.
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Lower wifi's score to below than cell, and check that it doesn't disconnect because
- // it's explicitly selected.
- mWiFiNetworkAgent.adjustScore(-40);
- mWiFiNetworkAgent.adjustScore(40);
- callback.assertNoCallback();
-
- // If the user chooses yes on the "No Internet access, stay connected?" dialog, we switch to
- // wifi even though it's unvalidated.
- mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), true, false);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Disconnect wifi, and then reconnect, again with explicitlySelected=true.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(true, false);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- // If the user chooses no on the "No Internet access, stay connected?" dialog, we ask the
- // network to disconnect.
- mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), false, false);
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Reconnect, again with explicitlySelected=true, but this time validate.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(true, false);
- mWiFiNetworkAgent.connect(true);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
- mEthernetNetworkAgent.connect(true);
- callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mWiFiNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
- assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- callback.assertNoCallback();
-
- // Disconnect wifi, and then reconnect as if the user had selected "yes, don't ask again"
- // (i.e., with explicitlySelected=true and acceptUnvalidated=true). Expect to switch to
- // wifi immediately.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(true, true);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mEthernetNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
-
- // Disconnect and reconnect with explicitlySelected=false and acceptUnvalidated=true.
- // Check that the network is not scored specially and that the device prefers cell data.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(false, true);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Clean up.
- mWiFiNetworkAgent.disconnect();
- mCellNetworkAgent.disconnect();
-
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- }
-
- private void tryNetworkFactoryRequests(int capability) throws Exception {
- // Verify NOT_RESTRICTED is set appropriately
- final NetworkCapabilities nc = new NetworkRequest.Builder().addCapability(capability)
- .build().networkCapabilities;
- if (capability == NET_CAPABILITY_CBS || capability == NET_CAPABILITY_DUN
- || capability == NET_CAPABILITY_EIMS || capability == NET_CAPABILITY_FOTA
- || capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS
- || capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP
- || capability == NET_CAPABILITY_VSIM || capability == NET_CAPABILITY_BIP
- || capability == NET_CAPABILITY_ENTERPRISE) {
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- } else {
- assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- }
-
- NetworkCapabilities filter = new NetworkCapabilities();
- filter.addTransportType(TRANSPORT_CELLULAR);
- filter.addCapability(capability);
- // Add NOT_VCN_MANAGED capability into filter unconditionally since some requests will add
- // NOT_VCN_MANAGED automatically but not for NetworkCapabilities,
- // see {@code NetworkCapabilities#deduceNotVcnManagedCapability} for more details.
- filter.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
- handlerThread.start();
- final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactory", filter, mCsHandlerThread);
- testFactory.setScoreFilter(45);
- testFactory.register();
-
- final NetworkCallback networkCallback;
- if (capability != NET_CAPABILITY_INTERNET) {
- // If the capability passed in argument is part of the default request, then the
- // factory will see the default request. Otherwise the filter will prevent the
- // factory from seeing it. In that case, add a request so it can be tested.
- assertFalse(testFactory.getMyStartRequested());
- NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build();
- networkCallback = new NetworkCallback();
- mCm.requestNetwork(request, networkCallback);
- } else {
- networkCallback = null;
- }
- testFactory.expectRequestAdd();
- testFactory.assertRequestCountEquals(1);
- assertTrue(testFactory.getMyStartRequested());
-
- // Now bring in a higher scored network.
- TestNetworkAgentWrapper testAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- // When testAgent connects, because of its score (50 legacy int / cell transport)
- // it will beat or equal the testFactory's offer, so the request will be removed.
- // Note the agent as validated only if the capability is INTERNET, as it's the only case
- // where it makes sense.
- testAgent.connect(NET_CAPABILITY_INTERNET == capability /* validated */);
- testAgent.addCapability(capability);
- testFactory.expectRequestRemove();
- testFactory.assertRequestCountEquals(0);
- assertFalse(testFactory.getMyStartRequested());
-
- // Add a request and make sure it's not sent to the factory, because the agent
- // is satisfying it better.
- final NetworkCallback cb = new ConnectivityManager.NetworkCallback();
- mCm.requestNetwork(new NetworkRequest.Builder().addCapability(capability).build(), cb);
- expectNoRequestChanged(testFactory);
- testFactory.assertRequestCountEquals(0);
- assertFalse(testFactory.getMyStartRequested());
-
- // If using legacy scores, make the test agent weak enough to have the exact same score as
- // the factory (50 for cell - 5 adjustment). Make sure the factory doesn't see the request.
- // If not using legacy score, this is a no-op and the "same score removes request" behavior
- // has already been tested above.
- testAgent.adjustScore(-5);
- expectNoRequestChanged(testFactory);
- assertFalse(testFactory.getMyStartRequested());
-
- // Make the test agent weak enough that the factory will see the two requests (the one that
- // was just sent, and either the default one or the one sent at the top of this test if
- // the default won't be seen).
- testAgent.setScore(new NetworkScore.Builder().setLegacyInt(2).setExiting(true).build());
- testFactory.expectRequestAdds(2);
- testFactory.assertRequestCountEquals(2);
- assertTrue(testFactory.getMyStartRequested());
-
- // Now unregister and make sure the request is removed.
- mCm.unregisterNetworkCallback(cb);
- testFactory.expectRequestRemove();
-
- // Bring in a bunch of requests.
- assertEquals(1, testFactory.getMyRequestCount());
- ConnectivityManager.NetworkCallback[] networkCallbacks =
- new ConnectivityManager.NetworkCallback[10];
- for (int i = 0; i< networkCallbacks.length; i++) {
- networkCallbacks[i] = new ConnectivityManager.NetworkCallback();
- NetworkRequest.Builder builder = new NetworkRequest.Builder();
- builder.addCapability(capability);
- mCm.requestNetwork(builder.build(), networkCallbacks[i]);
- }
- testFactory.expectRequestAdds(10);
- testFactory.assertRequestCountEquals(11); // +1 for the default/test specific request
- assertTrue(testFactory.getMyStartRequested());
-
- // Remove the requests.
- for (int i = 0; i < networkCallbacks.length; i++) {
- mCm.unregisterNetworkCallback(networkCallbacks[i]);
- }
- testFactory.expectRequestRemoves(10);
- testFactory.assertRequestCountEquals(1);
- assertTrue(testFactory.getMyStartRequested());
-
- // Adjust the agent score up again. Expect the request to be withdrawn.
- testAgent.setScore(new NetworkScore.Builder().setLegacyInt(50).build());
- testFactory.expectRequestRemove();
- testFactory.assertRequestCountEquals(0);
- assertFalse(testFactory.getMyStartRequested());
-
- // Drop the higher scored network.
- testAgent.disconnect();
- testFactory.expectRequestAdd();
- testFactory.assertRequestCountEquals(1);
- assertEquals(1, testFactory.getMyRequestCount());
- assertTrue(testFactory.getMyStartRequested());
-
- testFactory.terminate();
- if (networkCallback != null) mCm.unregisterNetworkCallback(networkCallback);
- handlerThread.quit();
- }
-
- @Test
- public void testNetworkFactoryRequests() throws Exception {
- tryNetworkFactoryRequests(NET_CAPABILITY_MMS);
- tryNetworkFactoryRequests(NET_CAPABILITY_SUPL);
- tryNetworkFactoryRequests(NET_CAPABILITY_DUN);
- tryNetworkFactoryRequests(NET_CAPABILITY_FOTA);
- tryNetworkFactoryRequests(NET_CAPABILITY_IMS);
- tryNetworkFactoryRequests(NET_CAPABILITY_CBS);
- tryNetworkFactoryRequests(NET_CAPABILITY_WIFI_P2P);
- tryNetworkFactoryRequests(NET_CAPABILITY_IA);
- tryNetworkFactoryRequests(NET_CAPABILITY_RCS);
- tryNetworkFactoryRequests(NET_CAPABILITY_XCAP);
- tryNetworkFactoryRequests(NET_CAPABILITY_ENTERPRISE);
- tryNetworkFactoryRequests(NET_CAPABILITY_EIMS);
- tryNetworkFactoryRequests(NET_CAPABILITY_NOT_METERED);
- tryNetworkFactoryRequests(NET_CAPABILITY_INTERNET);
- tryNetworkFactoryRequests(NET_CAPABILITY_TRUSTED);
- tryNetworkFactoryRequests(NET_CAPABILITY_NOT_VPN);
- tryNetworkFactoryRequests(NET_CAPABILITY_VSIM);
- tryNetworkFactoryRequests(NET_CAPABILITY_BIP);
- // Skipping VALIDATED and CAPTIVE_PORTAL as they're disallowed.
- }
-
- @Test
- public void testRegisterIgnoringScore() throws Exception {
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.setScore(new NetworkScore.Builder().setLegacyInt(90).build());
- mWiFiNetworkAgent.connect(true /* validated */);
-
- // Make sure the factory sees the default network
- final NetworkCapabilities filter = new NetworkCapabilities();
- filter.addTransportType(TRANSPORT_CELLULAR);
- filter.addCapability(NET_CAPABILITY_INTERNET);
- filter.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
- handlerThread.start();
- final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactory", filter, mCsHandlerThread);
- testFactory.register();
-
- final MockNetworkFactory testFactoryAll = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactoryAll", filter, mCsHandlerThread);
- testFactoryAll.registerIgnoringScore();
-
- // The regular test factory should not see the request, because WiFi is stronger than cell.
- expectNoRequestChanged(testFactory);
- // With ignoringScore though the request is seen.
- testFactoryAll.expectRequestAdd();
-
- // The legacy int will be ignored anyway, set the only other knob to true
- mWiFiNetworkAgent.setScore(new NetworkScore.Builder().setLegacyInt(110)
- .setTransportPrimary(true).build());
-
- expectNoRequestChanged(testFactory); // still not seeing the request
- expectNoRequestChanged(testFactoryAll); // still seeing the request
-
- mWiFiNetworkAgent.disconnect();
- }
-
- @Test
- public void testNetworkFactoryUnregister() throws Exception {
- // Make sure the factory sees the default network
- final NetworkCapabilities filter = new NetworkCapabilities();
- filter.addCapability(NET_CAPABILITY_INTERNET);
- filter.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
-
- final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
- handlerThread.start();
-
- // Checks that calling setScoreFilter on a NetworkFactory immediately before closing it
- // does not crash.
- for (int i = 0; i < 100; i++) {
- final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactory", filter, mCsHandlerThread);
- // Register the factory and don't be surprised when the default request arrives.
- testFactory.register();
- testFactory.expectRequestAdd();
-
- testFactory.setScoreFilter(42);
- testFactory.terminate();
-
- if (i % 2 == 0) {
- try {
- testFactory.register();
- fail("Re-registering terminated NetworkFactory should throw");
- } catch (IllegalStateException expected) {
- }
- }
- }
- handlerThread.quit();
- }
-
- @Test
- public void testNoMutableNetworkRequests() throws Exception {
- final PendingIntent pendingIntent = PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
- NetworkRequest request1 = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_VALIDATED)
- .build();
- NetworkRequest request2 = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL)
- .build();
-
- Class<IllegalArgumentException> expected = IllegalArgumentException.class;
- assertThrows(expected, () -> mCm.requestNetwork(request1, new NetworkCallback()));
- assertThrows(expected, () -> mCm.requestNetwork(request1, pendingIntent));
- assertThrows(expected, () -> mCm.requestNetwork(request2, new NetworkCallback()));
- assertThrows(expected, () -> mCm.requestNetwork(request2, pendingIntent));
- }
-
- @Test
- public void testMMSonWiFi() throws Exception {
- // Test bringing up cellular without MMS NetworkRequest gets reaped
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
- mCellNetworkAgent.connectWithoutInternet();
- mCellNetworkAgent.expectDisconnected();
- waitForIdle();
- assertEmpty(mCm.getAllNetworks());
- verifyNoNetwork();
-
- // Test bringing up validated WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
-
- // Register MMS NetworkRequest
- NetworkRequest.Builder builder = new NetworkRequest.Builder();
- builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(builder.build(), networkCallback);
-
- // Test bringing up unvalidated cellular with MMS
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
- mCellNetworkAgent.connectWithoutInternet();
- networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- verifyActiveNetwork(TRANSPORT_WIFI);
-
- // Test releasing NetworkRequest disconnects cellular with MMS
- mCm.unregisterNetworkCallback(networkCallback);
- mCellNetworkAgent.expectDisconnected();
- verifyActiveNetwork(TRANSPORT_WIFI);
- }
-
- @Test
- public void testMMSonCell() throws Exception {
- // Test bringing up cellular without MMS
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- ExpectedBroadcast b = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
- mCellNetworkAgent.connect(false);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
-
- // Register MMS NetworkRequest
- NetworkRequest.Builder builder = new NetworkRequest.Builder();
- builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(builder.build(), networkCallback);
-
- // Test bringing up MMS cellular network
- TestNetworkAgentWrapper
- mmsNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
- mmsNetworkAgent.connectWithoutInternet();
- networkCallback.expectAvailableCallbacksUnvalidated(mmsNetworkAgent);
- verifyActiveNetwork(TRANSPORT_CELLULAR);
-
- // Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
- mCm.unregisterNetworkCallback(networkCallback);
- mmsNetworkAgent.expectDisconnected();
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- }
-
- @Test
- public void testPartialConnectivity() throws Exception {
- // Register network callback.
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
- .build();
- TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- // Bring up validated mobile data.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-
- // Bring up wifi with partial connectivity.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithPartialConnectivity();
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
-
- // Mobile data should be the default network.
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- callback.assertNoCallback();
-
- // With HTTPS probe disabled, NetworkMonitor should pass the network validation with http
- // probe.
- mWiFiNetworkAgent.setNetworkPartialValid(false /* isStrictMode */);
- // If the user chooses yes to use this partial connectivity wifi, switch the default
- // network to wifi and check if wifi becomes valid or not.
- mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */,
- false /* always */);
- // If user accepts partial connectivity network,
- // NetworkMonitor#setAcceptPartialConnectivity() should be called too.
- waitForIdle();
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
-
- // Need a trigger point to let NetworkMonitor tell ConnectivityService that network is
- // validated.
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- NetworkCapabilities nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED,
- mWiFiNetworkAgent);
- assertTrue(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // Disconnect and reconnect wifi with partial connectivity again.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connectWithPartialConnectivity();
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
-
- // Mobile data should be the default network.
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
-
- // If the user chooses no, disconnect wifi immediately.
- mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), false/* accept */,
- false /* always */);
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // If user accepted partial connectivity before, and device reconnects to that network
- // again, but now the network has full connectivity. The network shouldn't contain
- // NET_CAPABILITY_PARTIAL_CONNECTIVITY.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- // acceptUnvalidated is also used as setting for accepting partial networks.
- mWiFiNetworkAgent.explicitlySelected(true /* explicitlySelected */,
- true /* acceptUnvalidated */);
- mWiFiNetworkAgent.connect(true);
-
- // If user accepted partial connectivity network before,
- // NetworkMonitor#setAcceptPartialConnectivity() will be called in
- // ConnectivityService#updateNetworkInfo().
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- assertFalse(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
-
- // Wifi should be the default network.
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // The user accepted partial connectivity and selected "don't ask again". Now the user
- // reconnects to the partial connectivity network. Switch to wifi as soon as partial
- // connectivity is detected.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(true /* explicitlySelected */,
- true /* acceptUnvalidated */);
- mWiFiNetworkAgent.connectWithPartialConnectivity();
- // If user accepted partial connectivity network before,
- // NetworkMonitor#setAcceptPartialConnectivity() will be called in
- // ConnectivityService#updateNetworkInfo().
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
- mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */);
-
- // Need a trigger point to let NetworkMonitor tell ConnectivityService that network is
- // validated.
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // If the user accepted partial connectivity, and the device auto-reconnects to the partial
- // connectivity network, it should contain both PARTIAL_CONNECTIVITY and VALIDATED.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.explicitlySelected(false /* explicitlySelected */,
- true /* acceptUnvalidated */);
-
- // NetworkMonitor will immediately (once the HTTPS probe fails...) report the network as
- // valid, because ConnectivityService calls setAcceptPartialConnectivity before it calls
- // notifyNetworkConnected.
- mWiFiNetworkAgent.connectWithPartialValidConnectivity(false /* isStrictMode */);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(
- NET_CAPABILITY_PARTIAL_CONNECTIVITY | NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- }
-
- @Test
- public void testCaptivePortalOnPartialConnectivity() throws Exception {
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- final TestNetworkCallback validatedCallback = new TestNetworkCallback();
- final NetworkRequest validatedRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_VALIDATED).build();
- mCm.registerNetworkCallback(validatedRequest, validatedCallback);
-
- // Bring up a network with a captive portal.
- // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- String redirectUrl = "http://android.com/path";
- mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl, false /* isStrictMode */);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), redirectUrl);
-
- // Check that startCaptivePortalApp sends the expected command to NetworkMonitor.
- mCm.startCaptivePortalApp(mWiFiNetworkAgent.getNetwork());
- verify(mWiFiNetworkAgent.mNetworkMonitor, timeout(TIMEOUT_MS).times(1))
- .launchCaptivePortalApp();
-
- // Report that the captive portal is dismissed with partial connectivity, and check that
- // callbacks are fired.
- mWiFiNetworkAgent.setNetworkPartial();
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- waitForIdle();
- captivePortalCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY,
- mWiFiNetworkAgent);
-
- // Report partial connectivity is accepted.
- mWiFiNetworkAgent.setNetworkPartialValid(false /* isStrictMode */);
- mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), true /* accept */,
- false /* always */);
- waitForIdle();
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- NetworkCapabilities nc =
- validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY,
- mWiFiNetworkAgent);
-
- mCm.unregisterNetworkCallback(captivePortalCallback);
- mCm.unregisterNetworkCallback(validatedCallback);
- }
-
- @Test
- public void testCaptivePortal() throws Exception {
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- final TestNetworkCallback validatedCallback = new TestNetworkCallback();
- final NetworkRequest validatedRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_VALIDATED).build();
- mCm.registerNetworkCallback(validatedRequest, validatedCallback);
-
- // Bring up a network with a captive portal.
- // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- String firstRedirectUrl = "http://example.com/firstPath";
- mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl, false /* isStrictMode */);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl);
-
- // Take down network.
- // Expect onLost callback.
- mWiFiNetworkAgent.disconnect();
- captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Bring up a network with a captive portal.
- // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- String secondRedirectUrl = "http://example.com/secondPath";
- mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl, false /* isStrictMode */);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl);
-
- // Make captive portal disappear then revalidate.
- // Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
- mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */);
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
- validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
-
- // Break network connectivity.
- // Expect NET_CAPABILITY_VALIDATED onLost callback.
- mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */);
- mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
- validatedCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- }
-
- @Test
- public void testCaptivePortalApp() throws Exception {
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- final TestNetworkCallback validatedCallback = new TestNetworkCallback();
- final NetworkRequest validatedRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_VALIDATED).build();
- mCm.registerNetworkCallback(validatedRequest, validatedCallback);
-
- // Bring up wifi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
-
- // Check that calling startCaptivePortalApp does nothing.
- final int fastTimeoutMs = 100;
- mCm.startCaptivePortalApp(wifiNetwork);
- waitForIdle();
- verify(mWiFiNetworkAgent.mNetworkMonitor, never()).launchCaptivePortalApp();
- mServiceContext.expectNoStartActivityIntent(fastTimeoutMs);
-
- // Turn into a captive portal.
- mWiFiNetworkAgent.setNetworkPortal("http://example.com", false /* isStrictMode */);
- mCm.reportNetworkConnectivity(wifiNetwork, false);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- validatedCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Check that startCaptivePortalApp sends the expected command to NetworkMonitor.
- mCm.startCaptivePortalApp(wifiNetwork);
- waitForIdle();
- verify(mWiFiNetworkAgent.mNetworkMonitor).launchCaptivePortalApp();
-
- // NetworkMonitor uses startCaptivePortal(Network, Bundle) (startCaptivePortalAppInternal)
- final Bundle testBundle = new Bundle();
- final String testKey = "testkey";
- final String testValue = "testvalue";
- testBundle.putString(testKey, testValue);
- mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- PERMISSION_GRANTED);
- mCm.startCaptivePortalApp(wifiNetwork, testBundle);
- final Intent signInIntent = mServiceContext.expectStartActivityIntent(TIMEOUT_MS);
- assertEquals(ACTION_CAPTIVE_PORTAL_SIGN_IN, signInIntent.getAction());
- assertEquals(testValue, signInIntent.getStringExtra(testKey));
-
- // Report that the captive portal is dismissed, and check that callbacks are fired
- mWiFiNetworkAgent.setNetworkValid(false /* isStrictMode */);
- mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- mCm.unregisterNetworkCallback(validatedCallback);
- mCm.unregisterNetworkCallback(captivePortalCallback);
- }
-
- @Test
- public void testAvoidOrIgnoreCaptivePortals() throws Exception {
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- final TestNetworkCallback validatedCallback = new TestNetworkCallback();
- final NetworkRequest validatedRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_VALIDATED).build();
- mCm.registerNetworkCallback(validatedRequest, validatedCallback);
-
- setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_AVOID);
- // Bring up a network with a captive portal.
- // Expect it to fail to connect and not result in any callbacks.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- String firstRedirectUrl = "http://example.com/firstPath";
-
- mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl, false /* isStrictMode */);
- mWiFiNetworkAgent.expectDisconnected();
- mWiFiNetworkAgent.expectPreventReconnectReceived();
-
- assertNoCallbacks(captivePortalCallback, validatedCallback);
- }
-
- @Test
- public void testCaptivePortalApi() throws Exception {
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final String redirectUrl = "http://example.com/firstPath";
-
- mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl, false /* isStrictMode */);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- final CaptivePortalData testData = new CaptivePortalData.Builder()
- .setUserPortalUrl(Uri.parse(redirectUrl))
- .setBytesRemaining(12345L)
- .build();
-
- mWiFiNetworkAgent.notifyCapportApiDataChanged(testData);
-
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> testData.equals(lp.getCaptivePortalData()));
-
- final LinkProperties newLps = new LinkProperties();
- newLps.setMtu(1234);
- mWiFiNetworkAgent.sendLinkProperties(newLps);
- // CaptivePortalData is not lost and unchanged when LPs are received from the NetworkAgent
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> testData.equals(lp.getCaptivePortalData()) && lp.getMtu() == 1234);
- }
-
- private TestNetworkCallback setupNetworkCallbackAndConnectToWifi() throws Exception {
- // Grant NETWORK_SETTINGS permission to be able to receive LinkProperties change callbacks
- // with sensitive (captive portal) data
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
- final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
- mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-
- mWiFiNetworkAgent.connectWithCaptivePortal(TEST_REDIRECT_URL, false /* isStrictMode */);
- captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- return captivePortalCallback;
- }
-
- private class CaptivePortalTestData {
- CaptivePortalTestData(CaptivePortalData naPasspointData, CaptivePortalData capportData,
- CaptivePortalData naOtherData, CaptivePortalData expectedMergedPasspointData,
- CaptivePortalData expectedMergedOtherData) {
- mNaPasspointData = naPasspointData;
- mCapportData = capportData;
- mNaOtherData = naOtherData;
- mExpectedMergedPasspointData = expectedMergedPasspointData;
- mExpectedMergedOtherData = expectedMergedOtherData;
- }
-
- public final CaptivePortalData mNaPasspointData;
- public final CaptivePortalData mCapportData;
- public final CaptivePortalData mNaOtherData;
- public final CaptivePortalData mExpectedMergedPasspointData;
- public final CaptivePortalData mExpectedMergedOtherData;
-
- }
-
- private CaptivePortalTestData setupCaptivePortalData() {
- final CaptivePortalData capportData = new CaptivePortalData.Builder()
- .setUserPortalUrl(Uri.parse(TEST_REDIRECT_URL))
- .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_CAPPORT))
- .setUserPortalUrl(Uri.parse(TEST_USER_PORTAL_API_URL_CAPPORT))
- .setExpiryTime(1000000L)
- .setBytesRemaining(12345L)
- .build();
-
- final CaptivePortalData naPasspointData = new CaptivePortalData.Builder()
- .setBytesRemaining(80802L)
- .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_NA_PASSPOINT),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
- .setUserPortalUrl(Uri.parse(TEST_TERMS_AND_CONDITIONS_URL_NA_PASSPOINT),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
- .setVenueFriendlyName(TEST_FRIENDLY_NAME).build();
-
- final CaptivePortalData naOtherData = new CaptivePortalData.Builder()
- .setBytesRemaining(80802L)
- .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_NA_OTHER),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER)
- .setUserPortalUrl(Uri.parse(TEST_TERMS_AND_CONDITIONS_URL_NA_OTHER),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER)
- .setVenueFriendlyName(TEST_FRIENDLY_NAME).build();
-
- final CaptivePortalData expectedMergedPasspointData = new CaptivePortalData.Builder()
- .setUserPortalUrl(Uri.parse(TEST_REDIRECT_URL))
- .setBytesRemaining(12345L)
- .setExpiryTime(1000000L)
- .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_NA_PASSPOINT),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
- .setUserPortalUrl(Uri.parse(TEST_TERMS_AND_CONDITIONS_URL_NA_PASSPOINT),
- CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
- .setVenueFriendlyName(TEST_FRIENDLY_NAME).build();
-
- final CaptivePortalData expectedMergedOtherData = new CaptivePortalData.Builder()
- .setUserPortalUrl(Uri.parse(TEST_REDIRECT_URL))
- .setBytesRemaining(12345L)
- .setExpiryTime(1000000L)
- .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_CAPPORT))
- .setUserPortalUrl(Uri.parse(TEST_USER_PORTAL_API_URL_CAPPORT))
- .setVenueFriendlyName(TEST_FRIENDLY_NAME).build();
- return new CaptivePortalTestData(naPasspointData, capportData, naOtherData,
- expectedMergedPasspointData, expectedMergedOtherData);
- }
-
- @Test
- public void testMergeCaptivePortalApiWithFriendlyNameAndVenueUrl() throws Exception {
- final TestNetworkCallback captivePortalCallback = setupNetworkCallbackAndConnectToWifi();
- final CaptivePortalTestData captivePortalTestData = setupCaptivePortalData();
-
- // Baseline capport data
- mWiFiNetworkAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData);
-
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mCapportData.equals(lp.getCaptivePortalData()));
-
- // Venue URL, T&C URL and friendly name from Network agent with Passpoint source, confirm
- // that API data gets precedence on the bytes remaining.
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setCaptivePortalData(captivePortalTestData.mNaPasspointData);
- mWiFiNetworkAgent.sendLinkProperties(linkProperties);
-
- // Make sure that the capport data is merged
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mExpectedMergedPasspointData
- .equals(lp.getCaptivePortalData()));
-
- // Now send this information from non-Passpoint source, confirm that Capport data takes
- // precedence
- linkProperties.setCaptivePortalData(captivePortalTestData.mNaOtherData);
- mWiFiNetworkAgent.sendLinkProperties(linkProperties);
-
- // Make sure that the capport data is merged
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mExpectedMergedOtherData
- .equals(lp.getCaptivePortalData()));
-
- // Create a new LP with no Network agent capport data
- final LinkProperties newLps = new LinkProperties();
- newLps.setMtu(1234);
- mWiFiNetworkAgent.sendLinkProperties(newLps);
- // CaptivePortalData is not lost and has the original values when LPs are received from the
- // NetworkAgent
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mCapportData.equals(lp.getCaptivePortalData())
- && lp.getMtu() == 1234);
-
- // Now send capport data only from the Network agent
- mWiFiNetworkAgent.notifyCapportApiDataChanged(null);
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> lp.getCaptivePortalData() == null);
-
- newLps.setCaptivePortalData(captivePortalTestData.mNaPasspointData);
- mWiFiNetworkAgent.sendLinkProperties(newLps);
-
- // Make sure that only the network agent capport data is available
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mNaPasspointData.equals(lp.getCaptivePortalData()));
- }
-
- @Test
- public void testMergeCaptivePortalDataFromNetworkAgentFirstThenCapport() throws Exception {
- final TestNetworkCallback captivePortalCallback = setupNetworkCallbackAndConnectToWifi();
- final CaptivePortalTestData captivePortalTestData = setupCaptivePortalData();
-
- // Venue URL and friendly name from Network agent, confirm that API data gets precedence
- // on the bytes remaining.
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setCaptivePortalData(captivePortalTestData.mNaPasspointData);
- mWiFiNetworkAgent.sendLinkProperties(linkProperties);
-
- // Make sure that the data is saved correctly
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mNaPasspointData.equals(lp.getCaptivePortalData()));
-
- // Expected merged data: Network agent data is preferred, and values that are not used by
- // it are merged from capport data
- mWiFiNetworkAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData);
-
- // Make sure that the Capport data is merged correctly
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mExpectedMergedPasspointData.equals(
- lp.getCaptivePortalData()));
-
- // Now set the naData to null
- linkProperties.setCaptivePortalData(null);
- mWiFiNetworkAgent.sendLinkProperties(linkProperties);
-
- // Make sure that the Capport data is retained correctly
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mCapportData.equals(lp.getCaptivePortalData()));
- }
-
- @Test
- public void testMergeCaptivePortalDataFromNetworkAgentOtherSourceFirstThenCapport()
- throws Exception {
- final TestNetworkCallback captivePortalCallback = setupNetworkCallbackAndConnectToWifi();
- final CaptivePortalTestData captivePortalTestData = setupCaptivePortalData();
-
- // Venue URL and friendly name from Network agent, confirm that API data gets precedence
- // on the bytes remaining.
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setCaptivePortalData(captivePortalTestData.mNaOtherData);
- mWiFiNetworkAgent.sendLinkProperties(linkProperties);
-
- // Make sure that the data is saved correctly
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mNaOtherData.equals(lp.getCaptivePortalData()));
-
- // Expected merged data: Network agent data is preferred, and values that are not used by
- // it are merged from capport data
- mWiFiNetworkAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData);
-
- // Make sure that the Capport data is merged correctly
- captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mExpectedMergedOtherData.equals(
- lp.getCaptivePortalData()));
- }
-
- private NetworkRequest.Builder newWifiRequestBuilder() {
- return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI);
- }
-
- /**
- * Verify request matching behavior with network specifiers.
- *
- * This test does not check updating the specifier on a live network because the specifier is
- * immutable and this triggers a WTF in
- * {@link ConnectivityService#mixInCapabilities(NetworkAgentInfo, NetworkCapabilities)}.
- */
- @Test
- public void testNetworkSpecifier() throws Exception {
- // A NetworkSpecifier subclass that matches all networks but must not be visible to apps.
- class ConfidentialMatchAllNetworkSpecifier extends NetworkSpecifier implements
- Parcelable {
- @Override
- public boolean canBeSatisfiedBy(NetworkSpecifier other) {
- return true;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {}
-
- @Override
- public NetworkSpecifier redact() {
- return null;
- }
- }
-
- // A network specifier that matches either another LocalNetworkSpecifier with the same
- // string or a ConfidentialMatchAllNetworkSpecifier, and can be passed to apps as is.
- class LocalStringNetworkSpecifier extends NetworkSpecifier implements Parcelable {
- private String mString;
-
- LocalStringNetworkSpecifier(String string) {
- mString = string;
- }
-
- @Override
- public boolean canBeSatisfiedBy(NetworkSpecifier other) {
- if (other instanceof LocalStringNetworkSpecifier) {
- return TextUtils.equals(mString,
- ((LocalStringNetworkSpecifier) other).mString);
- }
- if (other instanceof ConfidentialMatchAllNetworkSpecifier) return true;
- return false;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
- @Override
- public void writeToParcel(Parcel dest, int flags) {}
- }
-
-
- NetworkRequest rEmpty1 = newWifiRequestBuilder().build();
- NetworkRequest rEmpty2 = newWifiRequestBuilder().setNetworkSpecifier((String) null).build();
- NetworkRequest rEmpty3 = newWifiRequestBuilder().setNetworkSpecifier("").build();
- NetworkRequest rEmpty4 = newWifiRequestBuilder().setNetworkSpecifier(
- (NetworkSpecifier) null).build();
- NetworkRequest rFoo = newWifiRequestBuilder().setNetworkSpecifier(
- new LocalStringNetworkSpecifier("foo")).build();
- NetworkRequest rBar = newWifiRequestBuilder().setNetworkSpecifier(
- new LocalStringNetworkSpecifier("bar")).build();
-
- TestNetworkCallback cEmpty1 = new TestNetworkCallback();
- TestNetworkCallback cEmpty2 = new TestNetworkCallback();
- TestNetworkCallback cEmpty3 = new TestNetworkCallback();
- TestNetworkCallback cEmpty4 = new TestNetworkCallback();
- TestNetworkCallback cFoo = new TestNetworkCallback();
- TestNetworkCallback cBar = new TestNetworkCallback();
- TestNetworkCallback[] emptyCallbacks = new TestNetworkCallback[] {
- cEmpty1, cEmpty2, cEmpty3, cEmpty4 };
-
- mCm.registerNetworkCallback(rEmpty1, cEmpty1);
- mCm.registerNetworkCallback(rEmpty2, cEmpty2);
- mCm.registerNetworkCallback(rEmpty3, cEmpty3);
- mCm.registerNetworkCallback(rEmpty4, cEmpty4);
- mCm.registerNetworkCallback(rFoo, cFoo);
- mCm.registerNetworkCallback(rBar, cBar);
-
- LocalStringNetworkSpecifier nsFoo = new LocalStringNetworkSpecifier("foo");
- LocalStringNetworkSpecifier nsBar = new LocalStringNetworkSpecifier("bar");
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiNetworkAgent, null /* specifier */,
- cEmpty1, cEmpty2, cEmpty3, cEmpty4);
- assertNoCallbacks(cFoo, cBar);
-
- mWiFiNetworkAgent.disconnect();
- expectOnLost(mWiFiNetworkAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.setNetworkSpecifier(nsFoo);
- mWiFiNetworkAgent.connect(false);
- expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiNetworkAgent, nsFoo,
- cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo);
- cBar.assertNoCallback();
- assertEquals(nsFoo,
- mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
- assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo);
-
- mWiFiNetworkAgent.disconnect();
- expectOnLost(mWiFiNetworkAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.setNetworkSpecifier(nsBar);
- mWiFiNetworkAgent.connect(false);
- expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiNetworkAgent, nsBar,
- cEmpty1, cEmpty2, cEmpty3, cEmpty4, cBar);
- cFoo.assertNoCallback();
- assertEquals(nsBar,
- mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
-
- mWiFiNetworkAgent.disconnect();
- expectOnLost(mWiFiNetworkAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cBar);
- cFoo.assertNoCallback();
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.setNetworkSpecifier(new ConfidentialMatchAllNetworkSpecifier());
- mWiFiNetworkAgent.connect(false);
- expectAvailableCallbacksUnvalidatedWithSpecifier(mWiFiNetworkAgent, null /* specifier */,
- cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar);
- assertNull(
- mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
-
- mWiFiNetworkAgent.disconnect();
- expectOnLost(mWiFiNetworkAgent, cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar);
- }
-
- /**
- * @return the context's attribution tag
- */
- private String getAttributionTag() {
- return mContext.getAttributionTag();
- }
-
- @Test
- public void testInvalidNetworkSpecifier() {
- assertThrows(IllegalArgumentException.class, () -> {
- NetworkRequest.Builder builder = new NetworkRequest.Builder();
- builder.setNetworkSpecifier(new MatchAllNetworkSpecifier());
- });
-
- assertThrows(IllegalArgumentException.class, () -> {
- NetworkCapabilities networkCapabilities = new NetworkCapabilities();
- networkCapabilities.addTransportType(TRANSPORT_WIFI)
- .setNetworkSpecifier(new MatchAllNetworkSpecifier());
- mService.requestNetwork(Process.INVALID_UID, networkCapabilities,
- NetworkRequest.Type.REQUEST.ordinal(), null, 0, null,
- ConnectivityManager.TYPE_WIFI, NetworkCallback.FLAG_NONE,
- mContext.getPackageName(), getAttributionTag());
- });
-
- class NonParcelableSpecifier extends NetworkSpecifier {
- @Override
- public boolean canBeSatisfiedBy(NetworkSpecifier other) {
- return false;
- }
- };
- class ParcelableSpecifier extends NonParcelableSpecifier implements Parcelable {
- @Override public int describeContents() { return 0; }
- @Override public void writeToParcel(Parcel p, int flags) {}
- }
-
- final NetworkRequest.Builder builder =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET);
- assertThrows(ClassCastException.class, () -> {
- builder.setNetworkSpecifier(new NonParcelableSpecifier());
- Parcel parcelW = Parcel.obtain();
- builder.build().writeToParcel(parcelW, 0);
- });
-
- final NetworkRequest nr =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET)
- .setNetworkSpecifier(new ParcelableSpecifier())
- .build();
- assertNotNull(nr);
-
- assertThrows(BadParcelableException.class, () -> {
- Parcel parcelW = Parcel.obtain();
- nr.writeToParcel(parcelW, 0);
- byte[] bytes = parcelW.marshall();
- parcelW.recycle();
-
- Parcel parcelR = Parcel.obtain();
- parcelR.unmarshall(bytes, 0, bytes.length);
- parcelR.setDataPosition(0);
- NetworkRequest rereadNr = NetworkRequest.CREATOR.createFromParcel(parcelR);
- });
- }
-
- @Test
- public void testNetworkRequestUidSpoofSecurityException() throws Exception {
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- NetworkRequest networkRequest = newWifiRequestBuilder().build();
- TestNetworkCallback networkCallback = new TestNetworkCallback();
- doThrow(new SecurityException()).when(mAppOpsManager).checkPackage(anyInt(), anyString());
- assertThrows(SecurityException.class, () -> {
- mCm.requestNetwork(networkRequest, networkCallback);
- });
- }
-
- @Test
- public void testInvalidSignalStrength() {
- NetworkRequest r = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addTransportType(TRANSPORT_WIFI)
- .setSignalStrength(-75)
- .build();
- // Registering a NetworkCallback with signal strength but w/o NETWORK_SIGNAL_STRENGTH_WAKEUP
- // permission should get SecurityException.
- assertThrows(SecurityException.class, () ->
- mCm.registerNetworkCallback(r, new NetworkCallback()));
-
- assertThrows(SecurityException.class, () ->
- mCm.registerNetworkCallback(r, PendingIntent.getService(
- mServiceContext, 0 /* requestCode */, new Intent(), FLAG_IMMUTABLE)));
-
- // Requesting a Network with signal strength should get IllegalArgumentException.
- assertThrows(IllegalArgumentException.class, () ->
- mCm.requestNetwork(r, new NetworkCallback()));
-
- assertThrows(IllegalArgumentException.class, () ->
- mCm.requestNetwork(r, PendingIntent.getService(
- mServiceContext, 0 /* requestCode */, new Intent(), FLAG_IMMUTABLE)));
- }
-
- @Test
- public void testRegisterDefaultNetworkCallback() throws Exception {
- // NETWORK_SETTINGS is necessary to call registerSystemDefaultNetworkCallback.
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
- defaultNetworkCallback.assertNoCallback();
-
- final Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
- final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
- mCm.registerSystemDefaultNetworkCallback(systemDefaultCallback, handler);
- systemDefaultCallback.assertNoCallback();
-
- // Create a TRANSPORT_CELLULAR request to keep the mobile interface up
- // whenever Wi-Fi is up. Without this, the mobile network agent is
- // reaped before any other activity can take place.
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.requestNetwork(cellRequest, cellNetworkCallback);
- cellNetworkCallback.assertNoCallback();
-
- // Bring up cell and expect CALLBACK_AVAILABLE.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- systemDefaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring up wifi and expect CALLBACK_AVAILABLE.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- cellNetworkCallback.assertNoCallback();
- defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- systemDefaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring down cell. Expect no default network callback, since it wasn't the default.
- mCellNetworkAgent.disconnect();
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultNetworkCallback.assertNoCallback();
- systemDefaultCallback.assertNoCallback();
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring up cell. Expect no default network callback, since it won't be the default.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultNetworkCallback.assertNoCallback();
- systemDefaultCallback.assertNoCallback();
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- // Bring down wifi. Expect the default network callback to notified of LOST wifi
- // followed by AVAILABLE cell.
- mWiFiNetworkAgent.disconnect();
- cellNetworkCallback.assertNoCallback();
- defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- systemDefaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- systemDefaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- mCellNetworkAgent.disconnect();
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- systemDefaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- waitForIdle();
- assertEquals(null, mCm.getActiveNetwork());
-
- mMockVpn.establishForMyUid();
- assertUidRangesUpdatedForMyUid(true);
- defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- systemDefaultCallback.assertNoCallback();
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- assertEquals(null, systemDefaultCallback.getLastAvailableNetwork());
-
- mMockVpn.disconnect();
- defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- systemDefaultCallback.assertNoCallback();
- waitForIdle();
- assertEquals(null, mCm.getActiveNetwork());
- }
-
- @Test
- public void testAdditionalStateCallbacks() throws Exception {
- // File a network request for mobile.
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.requestNetwork(cellRequest, cellNetworkCallback);
-
- // Bring up the mobile network.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- // We should get onAvailable(), onCapabilitiesChanged(), and
- // onLinkPropertiesChanged() in rapid succession. Additionally, we
- // should get onCapabilitiesChanged() when the mobile network validates.
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
-
- // Update LinkProperties.
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("foonet_data0");
- mCellNetworkAgent.sendLinkProperties(lp);
- // We should get onLinkPropertiesChanged().
- cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
-
- // Suspend the network.
- mCellNetworkAgent.suspend();
- cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_SUSPENDED,
- mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.SUSPENDED, mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertEquals(NetworkInfo.State.SUSPENDED, mCm.getActiveNetworkInfo().getState());
-
- // Register a garden variety default network request.
- TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
- // We should get onAvailable(), onCapabilitiesChanged(), onLinkPropertiesChanged(),
- // as well as onNetworkSuspended() in rapid succession.
- dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent, true);
- dfltNetworkCallback.assertNoCallback();
- mCm.unregisterNetworkCallback(dfltNetworkCallback);
-
- mCellNetworkAgent.resume();
- cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_SUSPENDED,
- mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.RESUMED, mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertEquals(NetworkInfo.State.CONNECTED, mCm.getActiveNetworkInfo().getState());
-
- dfltNetworkCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
- // This time onNetworkSuspended should not be called.
- dfltNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- dfltNetworkCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(dfltNetworkCallback);
- mCm.unregisterNetworkCallback(cellNetworkCallback);
- }
-
- @Test
- public void testRegisterPrivilegedDefaultCallbacksRequireNetworkSettings() throws Exception {
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false /* validated */);
-
- final Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
- final TestNetworkCallback callback = new TestNetworkCallback();
- assertThrows(SecurityException.class,
- () -> mCm.registerSystemDefaultNetworkCallback(callback, handler));
- callback.assertNoCallback();
- assertThrows(SecurityException.class,
- () -> mCm.registerDefaultNetworkCallbackForUid(APP1_UID, callback, handler));
- callback.assertNoCallback();
-
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
- mCm.registerSystemDefaultNetworkCallback(callback, handler);
- callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- mCm.unregisterNetworkCallback(callback);
-
- mCm.registerDefaultNetworkCallbackForUid(APP1_UID, callback, handler);
- callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- mCm.unregisterNetworkCallback(callback);
- }
-
- @Test
- public void testNetworkCallbackWithNullUids() throws Exception {
- final NetworkRequest request = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- // Attempt to file a callback for networks applying to another UID. This does not actually
- // work, because this code does not currently have permission to do so. The callback behaves
- // exactly the same as the one registered just above.
- final int otherUid = UserHandle.getUid(RESTRICTED_USER, VPN_UID);
- final NetworkRequest otherUidRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .setUids(UidRange.toIntRanges(uidRangesForUids(otherUid)))
- .build();
- final TestNetworkCallback otherUidCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(otherUidRequest, otherUidCallback);
-
- final NetworkRequest includeOtherUidsRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .setIncludeOtherUidNetworks(true)
- .build();
- final TestNetworkCallback includeOtherUidsCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(includeOtherUidsRequest, includeOtherUidsCallback);
-
- // Both callbacks see a network with no specifier that applies to their UID.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false /* validated */);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- otherUidCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- includeOtherUidsCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- otherUidCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- includeOtherUidsCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Only the includeOtherUidsCallback sees a VPN that does not apply to its UID.
- final UidRange range = UidRange.createForUser(UserHandle.of(RESTRICTED_USER));
- final Set<UidRange> vpnRanges = Collections.singleton(range);
- mMockVpn.establish(new LinkProperties(), VPN_UID, vpnRanges);
- includeOtherUidsCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- callback.assertNoCallback();
- otherUidCallback.assertNoCallback();
-
- mMockVpn.disconnect();
- includeOtherUidsCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- callback.assertNoCallback();
- otherUidCallback.assertNoCallback();
- }
-
- private static class RedactableNetworkSpecifier extends NetworkSpecifier {
- public static final int ID_INVALID = -1;
-
- public final int networkId;
-
- RedactableNetworkSpecifier(int networkId) {
- this.networkId = networkId;
- }
-
- @Override
- public boolean canBeSatisfiedBy(NetworkSpecifier other) {
- return other instanceof RedactableNetworkSpecifier
- && this.networkId == ((RedactableNetworkSpecifier) other).networkId;
- }
-
- @Override
- public NetworkSpecifier redact() {
- return new RedactableNetworkSpecifier(ID_INVALID);
- }
- }
-
- @Test
- public void testNetworkCallbackWithNullUidsRedactsSpecifier() throws Exception {
- final RedactableNetworkSpecifier specifier = new RedactableNetworkSpecifier(42);
- final NetworkRequest request = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addTransportType(TRANSPORT_WIFI)
- .setNetworkSpecifier(specifier)
- .build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- // Attempt to file a callback for networks applying to another UID. This does not actually
- // work, because this code does not currently have permission to do so. The callback behaves
- // exactly the same as the one registered just above.
- final int otherUid = UserHandle.getUid(RESTRICTED_USER, VPN_UID);
- final NetworkRequest otherUidRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addTransportType(TRANSPORT_WIFI)
- .setNetworkSpecifier(specifier)
- .setUids(UidRange.toIntRanges(uidRangesForUids(otherUid)))
- .build();
- final TestNetworkCallback otherUidCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(otherUidRequest, otherUidCallback);
-
- final NetworkRequest includeOtherUidsRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addTransportType(TRANSPORT_WIFI)
- .setNetworkSpecifier(specifier)
- .setIncludeOtherUidNetworks(true)
- .build();
- final TestNetworkCallback includeOtherUidsCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(includeOtherUidsRequest, callback);
-
- // Only the regular callback sees the network, because callbacks filed with no UID have
- // their specifiers redacted.
- final LinkProperties emptyLp = new LinkProperties();
- final NetworkCapabilities ncTemplate = new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .setNetworkSpecifier(specifier);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, emptyLp, ncTemplate);
- mWiFiNetworkAgent.connect(false /* validated */);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- otherUidCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- includeOtherUidsCallback.assertNoCallback();
- }
-
- private void setCaptivePortalMode(int mode) {
- ContentResolver cr = mServiceContext.getContentResolver();
- Settings.Global.putInt(cr, ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE, mode);
- }
-
- private void setAlwaysOnNetworks(boolean enable) {
- ContentResolver cr = mServiceContext.getContentResolver();
- Settings.Global.putInt(cr, ConnectivitySettingsManager.MOBILE_DATA_ALWAYS_ON,
- enable ? 1 : 0);
- mService.updateAlwaysOnNetworks();
- waitForIdle();
- }
-
- private void setPrivateDnsSettings(int mode, String specifier) {
- ConnectivitySettingsManager.setPrivateDnsMode(mServiceContext, mode);
- ConnectivitySettingsManager.setPrivateDnsHostname(mServiceContext, specifier);
- mService.updatePrivateDnsSettings();
- waitForIdle();
- }
-
- private boolean isForegroundNetwork(TestNetworkAgentWrapper network) {
- NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
- assertNotNull(nc);
- return nc.hasCapability(NET_CAPABILITY_FOREGROUND);
- }
-
- @Test
- public void testBackgroundNetworks() throws Exception {
- // Create a cellular background request.
- grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
- final TestNetworkCallback cellBgCallback = new TestNetworkCallback();
- mCm.requestBackgroundNetwork(new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build(),
- cellBgCallback, mCsHandlerThread.getThreadHandler());
-
- // Make callbacks for monitoring.
- final NetworkRequest request = new NetworkRequest.Builder().build();
- final NetworkRequest fgRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_FOREGROUND).build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- final TestNetworkCallback fgCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
- mCm.registerNetworkCallback(fgRequest, fgCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- fgCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertTrue(isForegroundNetwork(mCellNetworkAgent));
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
-
- // When wifi connects, cell lingers.
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- fgCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- assertTrue(isForegroundNetwork(mCellNetworkAgent));
- assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
-
- // When lingering is complete, cell is still there but is now in the background.
- waitForIdle();
- int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
- fgCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent, timeoutMs);
- // Expect a network capabilities update sans FOREGROUND.
- callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
- assertFalse(isForegroundNetwork(mCellNetworkAgent));
- assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
-
- // File a cell request and check that cell comes into the foreground.
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- final TestNetworkCallback cellCallback = new TestNetworkCallback();
- mCm.requestNetwork(cellRequest, cellCallback);
- cellCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- // Expect a network capabilities update with FOREGROUND, because the most recent
- // request causes its state to change.
- cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
- callback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
- assertTrue(isForegroundNetwork(mCellNetworkAgent));
- assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
-
- // Release the request. The network immediately goes into the background, since it was not
- // lingering.
- mCm.unregisterNetworkCallback(cellCallback);
- fgCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- // Expect a network capabilities update sans FOREGROUND.
- callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
- assertFalse(isForegroundNetwork(mCellNetworkAgent));
- assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
-
- // Disconnect wifi and check that cell is foreground again.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertTrue(isForegroundNetwork(mCellNetworkAgent));
-
- mCm.unregisterNetworkCallback(callback);
- mCm.unregisterNetworkCallback(fgCallback);
- mCm.unregisterNetworkCallback(cellBgCallback);
- }
-
- @Ignore // This test has instrinsic chances of spurious failures: ignore for continuous testing.
- public void benchmarkRequestRegistrationAndCallbackDispatch() throws Exception {
- // TODO: turn this unit test into a real benchmarking test.
- // Benchmarks connecting and switching performance in the presence of a large number of
- // NetworkRequests.
- // 1. File NUM_REQUESTS requests.
- // 2. Have a network connect. Wait for NUM_REQUESTS onAvailable callbacks to fire.
- // 3. Have a new network connect and outscore the previous. Wait for NUM_REQUESTS onLosing
- // and NUM_REQUESTS onAvailable callbacks to fire.
- // See how long it took.
- final int NUM_REQUESTS = 90;
- final int REGISTER_TIME_LIMIT_MS = 200;
- final int CONNECT_TIME_LIMIT_MS = 60;
- final int SWITCH_TIME_LIMIT_MS = 60;
- final int UNREGISTER_TIME_LIMIT_MS = 20;
-
- final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
- final NetworkCallback[] callbacks = new NetworkCallback[NUM_REQUESTS];
- final CountDownLatch availableLatch = new CountDownLatch(NUM_REQUESTS);
- final CountDownLatch losingLatch = new CountDownLatch(NUM_REQUESTS);
-
- for (int i = 0; i < NUM_REQUESTS; i++) {
- callbacks[i] = new NetworkCallback() {
- @Override public void onAvailable(Network n) { availableLatch.countDown(); }
- @Override public void onLosing(Network n, int t) { losingLatch.countDown(); }
- };
- }
-
- assertRunsInAtMost("Registering callbacks", REGISTER_TIME_LIMIT_MS, () -> {
- for (NetworkCallback cb : callbacks) {
- mCm.registerNetworkCallback(request, cb);
- }
- });
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- // Don't request that the network validate, because otherwise connect() will block until
- // the network gets NET_CAPABILITY_VALIDATED, after all the callbacks below have fired,
- // and we won't actually measure anything.
- mCellNetworkAgent.connect(false);
-
- long onAvailableDispatchingDuration = durationOf(() -> {
- await(availableLatch, 10 * CONNECT_TIME_LIMIT_MS);
- });
- Log.d(TAG, String.format("Dispatched %d of %d onAvailable callbacks in %dms",
- NUM_REQUESTS - availableLatch.getCount(), NUM_REQUESTS,
- onAvailableDispatchingDuration));
- assertTrue(String.format("Dispatching %d onAvailable callbacks in %dms, expected %dms",
- NUM_REQUESTS, onAvailableDispatchingDuration, CONNECT_TIME_LIMIT_MS),
- onAvailableDispatchingDuration <= CONNECT_TIME_LIMIT_MS);
-
- // Give wifi a high enough score that we'll linger cell when wifi comes up.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.adjustScore(40);
- mWiFiNetworkAgent.connect(false);
-
- long onLostDispatchingDuration = durationOf(() -> {
- await(losingLatch, 10 * SWITCH_TIME_LIMIT_MS);
- });
- Log.d(TAG, String.format("Dispatched %d of %d onLosing callbacks in %dms",
- NUM_REQUESTS - losingLatch.getCount(), NUM_REQUESTS, onLostDispatchingDuration));
- assertTrue(String.format("Dispatching %d onLosing callbacks in %dms, expected %dms",
- NUM_REQUESTS, onLostDispatchingDuration, SWITCH_TIME_LIMIT_MS),
- onLostDispatchingDuration <= SWITCH_TIME_LIMIT_MS);
-
- assertRunsInAtMost("Unregistering callbacks", UNREGISTER_TIME_LIMIT_MS, () -> {
- for (NetworkCallback cb : callbacks) {
- mCm.unregisterNetworkCallback(cb);
- }
- });
- }
-
- @Test
- public void testMobileDataAlwaysOn() throws Exception {
- grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
-
- final HandlerThread handlerThread = new HandlerThread("MobileDataAlwaysOnFactory");
- handlerThread.start();
- NetworkCapabilities filter = new NetworkCapabilities()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
- .addCapability(NET_CAPABILITY_INTERNET);
- final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactory", filter, mCsHandlerThread);
- testFactory.setScoreFilter(40);
-
- // Register the factory and expect it to start looking for a network.
- testFactory.register();
-
- try {
- // Expect the factory to receive the default network request.
- testFactory.expectRequestAdd();
- testFactory.assertRequestCountEquals(1);
- assertTrue(testFactory.getMyStartRequested());
-
- // Bring up wifi. The factory stops looking for a network.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- // Score 60 - 40 penalty for not validated yet, then 60 when it validates
- mWiFiNetworkAgent.connect(true);
- // The network connects with a low score, so the offer can still beat it and
- // nothing happens. Then the network validates, and the offer with its filter score
- // of 40 can no longer beat it and the request is removed.
- testFactory.expectRequestRemove();
- testFactory.assertRequestCountEquals(0);
-
- assertFalse(testFactory.getMyStartRequested());
-
- // Turn on mobile data always on. This request will not match the wifi request, so
- // it will be sent to the test factory whose filters allow to see it.
- setAlwaysOnNetworks(true);
- testFactory.expectRequestAdd();
- testFactory.assertRequestCountEquals(1);
-
- assertTrue(testFactory.getMyStartRequested());
-
- // Bring up cell data and check that the factory stops looking.
- assertLength(1, mCm.getAllNetworks());
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false);
- cellNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent, false, false, false,
- TEST_CALLBACK_TIMEOUT_MS);
- // When cell connects, it will satisfy the "mobile always on request" right away
- // by virtue of being the only network that can satisfy the request. However, its
- // score is low (50 - 40 = 10) so the test factory can still hope to beat it.
- expectNoRequestChanged(testFactory);
-
- // Next, cell validates. This gives it a score of 50 and the test factory can't
- // hope to beat that according to its filters. It will see the message that its
- // offer is now unnecessary.
- mCellNetworkAgent.setNetworkValid(true);
- // Need a trigger point to let NetworkMonitor tell ConnectivityService that network is
- // validated – see testPartialConnectivity.
- mCm.reportNetworkConnectivity(mCellNetworkAgent.getNetwork(), true);
- cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mCellNetworkAgent);
- testFactory.expectRequestRemove();
- testFactory.assertRequestCountEquals(0);
- // Accordingly, the factory shouldn't be started.
- assertFalse(testFactory.getMyStartRequested());
-
- // Check that cell data stays up.
- waitForIdle();
- verifyActiveNetwork(TRANSPORT_WIFI);
- assertLength(2, mCm.getAllNetworks());
-
- // Cell disconnects. There is still the "mobile data always on" request outstanding,
- // and the test factory should see it now that it isn't hopelessly outscored.
- mCellNetworkAgent.disconnect();
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- assertLength(1, mCm.getAllNetworks());
- testFactory.expectRequestAdd();
- testFactory.assertRequestCountEquals(1);
-
- // Reconnect cell validated, see the request disappear again. Then withdraw the
- // mobile always on request. This will tear down cell, and there shouldn't be a
- // blip where the test factory briefly sees the request or anything.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertLength(2, mCm.getAllNetworks());
- testFactory.expectRequestRemove();
- testFactory.assertRequestCountEquals(0);
- setAlwaysOnNetworks(false);
- expectNoRequestChanged(testFactory);
- testFactory.assertRequestCountEquals(0);
- assertFalse(testFactory.getMyStartRequested());
- // ... and cell data to be torn down immediately since it is no longer nascent.
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- waitForIdle();
- assertLength(1, mCm.getAllNetworks());
- } finally {
- testFactory.terminate();
- mCm.unregisterNetworkCallback(cellNetworkCallback);
- handlerThread.quit();
- }
- }
-
- @Test
- public void testAvoidBadWifiSetting() throws Exception {
- final ContentResolver cr = mServiceContext.getContentResolver();
- final String settingName = ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI;
-
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
- String[] values = new String[] {null, "0", "1"};
- for (int i = 0; i < values.length; i++) {
- Settings.Global.putInt(cr, settingName, 1);
- mPolicyTracker.reevaluate();
- waitForIdle();
- String msg = String.format("config=false, setting=%s", values[i]);
- assertTrue(mService.avoidBadWifi());
- assertFalse(msg, mPolicyTracker.shouldNotifyWifiUnvalidated());
- }
-
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
-
- Settings.Global.putInt(cr, settingName, 0);
- mPolicyTracker.reevaluate();
- waitForIdle();
- assertFalse(mService.avoidBadWifi());
- assertFalse(mPolicyTracker.shouldNotifyWifiUnvalidated());
-
- Settings.Global.putInt(cr, settingName, 1);
- mPolicyTracker.reevaluate();
- waitForIdle();
- assertTrue(mService.avoidBadWifi());
- assertFalse(mPolicyTracker.shouldNotifyWifiUnvalidated());
-
- Settings.Global.putString(cr, settingName, null);
- mPolicyTracker.reevaluate();
- waitForIdle();
- assertFalse(mService.avoidBadWifi());
- assertTrue(mPolicyTracker.shouldNotifyWifiUnvalidated());
- }
-
- @Ignore("Refactoring in progress b/178071397")
- @Test
- public void testAvoidBadWifi() throws Exception {
- final ContentResolver cr = mServiceContext.getContentResolver();
-
- // Pretend we're on a carrier that restricts switching away from bad wifi.
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
-
- // File a request for cell to ensure it doesn't go down.
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.requestNetwork(cellRequest, cellNetworkCallback);
-
- TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- NetworkRequest validatedWifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI)
- .addCapability(NET_CAPABILITY_VALIDATED)
- .build();
- TestNetworkCallback validatedWifiCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);
-
- Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 0);
- mPolicyTracker.reevaluate();
-
- // Bring up validated cell.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- Network cellNetwork = mCellNetworkAgent.getNetwork();
-
- // Bring up validated wifi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
-
- // Fail validation on wifi.
- mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */);
- mCm.reportNetworkConnectivity(wifiNetwork, false);
- defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Because avoid bad wifi is off, we don't switch to cellular.
- defaultCallback.assertNoCallback();
- assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertEquals(mCm.getActiveNetwork(), wifiNetwork);
-
- // Simulate switching to a carrier that does not restrict avoiding bad wifi, and expect
- // that we switch back to cell.
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = false;
- mPolicyTracker.reevaluate();
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertEquals(mCm.getActiveNetwork(), cellNetwork);
-
- // Switch back to a restrictive carrier.
- mPolicyTracker.mConfigRestrictsAvoidBadWifi = true;
- mPolicyTracker.reevaluate();
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mCm.getActiveNetwork(), wifiNetwork);
-
- // Simulate the user selecting "switch" on the dialog, and check that we switch to cell.
- mCm.setAvoidUnvalidated(wifiNetwork);
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertEquals(mCm.getActiveNetwork(), cellNetwork);
-
- // Disconnect and reconnect wifi to clear the one-time switch above.
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- wifiNetwork = mWiFiNetworkAgent.getNetwork();
-
- // Fail validation on wifi and expect the dialog to appear.
- mWiFiNetworkAgent.setNetworkInvalid(false /* isStrictMode */);
- mCm.reportNetworkConnectivity(wifiNetwork, false);
- defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Simulate the user selecting "switch" and checking the don't ask again checkbox.
- Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 1);
- mPolicyTracker.reevaluate();
-
- // We now switch to cell.
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
- NET_CAPABILITY_VALIDATED));
- assertEquals(mCm.getActiveNetwork(), cellNetwork);
-
- // Simulate the user turning the cellular fallback setting off and then on.
- // We switch to wifi and then to cell.
- Settings.Global.putString(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, null);
- mPolicyTracker.reevaluate();
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mCm.getActiveNetwork(), wifiNetwork);
- Settings.Global.putInt(cr, ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI, 1);
- mPolicyTracker.reevaluate();
- defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertEquals(mCm.getActiveNetwork(), cellNetwork);
-
- // If cell goes down, we switch to wifi.
- mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- validatedWifiCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(cellNetworkCallback);
- mCm.unregisterNetworkCallback(validatedWifiCallback);
- mCm.unregisterNetworkCallback(defaultCallback);
- }
-
- @Test
- public void testMeteredMultipathPreferenceSetting() throws Exception {
- final ContentResolver cr = mServiceContext.getContentResolver();
- final String settingName = ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE;
-
- for (int config : Arrays.asList(0, 3, 2)) {
- for (String setting: Arrays.asList(null, "0", "2", "1")) {
- mPolicyTracker.mConfigMeteredMultipathPreference = config;
- Settings.Global.putString(cr, settingName, setting);
- mPolicyTracker.reevaluate();
- waitForIdle();
-
- final int expected = (setting != null) ? Integer.parseInt(setting) : config;
- String msg = String.format("config=%d, setting=%s", config, setting);
- assertEquals(msg, expected, mCm.getMultipathPreference(null));
- }
- }
- }
-
- /**
- * Validate that a satisfied network request does not trigger onUnavailable() once the
- * time-out period expires.
- */
- @Test
- public void testSatisfiedNetworkRequestDoesNotTriggerOnUnavailable() throws Exception {
- NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
- NetworkCapabilities.TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false,
- TEST_CALLBACK_TIMEOUT_MS);
-
- // pass timeout and validate that UNAVAILABLE is not called
- networkCallback.assertNoCallback();
- }
-
- /**
- * Validate that a satisfied network request followed by a disconnected (lost) network does
- * not trigger onUnavailable() once the time-out period expires.
- */
- @Test
- public void testSatisfiedThenLostNetworkRequestDoesNotTriggerOnUnavailable() throws Exception {
- NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
- NetworkCapabilities.TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false,
- TEST_CALLBACK_TIMEOUT_MS);
- mWiFiNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- // Validate that UNAVAILABLE is not called
- networkCallback.assertNoCallback();
- }
-
- /**
- * Validate that when a time-out is specified for a network request the onUnavailable()
- * callback is called when time-out expires. Then validate that if network request is
- * (somehow) satisfied - the callback isn't called later.
- */
- @Test
- public void testTimedoutNetworkRequest() throws Exception {
- NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
- NetworkCapabilities.TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- final int timeoutMs = 10;
- mCm.requestNetwork(nr, networkCallback, timeoutMs);
-
- // pass timeout and validate that UNAVAILABLE is called
- networkCallback.expectCallback(CallbackEntry.UNAVAILABLE, (Network) null);
-
- // create a network satisfying request - validate that request not triggered
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- networkCallback.assertNoCallback();
- }
-
- /**
- * Validate that when a network request is unregistered (cancelled), no posterior event can
- * trigger the callback.
- */
- @Test
- public void testNoCallbackAfterUnregisteredNetworkRequest() throws Exception {
- NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
- NetworkCapabilities.TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- final int timeoutMs = 10;
-
- mCm.requestNetwork(nr, networkCallback, timeoutMs);
- mCm.unregisterNetworkCallback(networkCallback);
- // Regardless of the timeout, unregistering the callback in ConnectivityManager ensures
- // that this callback will not be called.
- networkCallback.assertNoCallback();
-
- // create a network satisfying request - validate that request not triggered
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- networkCallback.assertNoCallback();
- }
-
- @Test
- public void testUnfulfillableNetworkRequest() throws Exception {
- runUnfulfillableNetworkRequest(false);
- }
-
- @Test
- public void testUnfulfillableNetworkRequestAfterUnregister() throws Exception {
- runUnfulfillableNetworkRequest(true);
- }
-
- /**
- * Validate the callback flow for a factory releasing a request as unfulfillable.
- */
- private void runUnfulfillableNetworkRequest(boolean preUnregister) throws Exception {
- NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
- NetworkCapabilities.TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
-
- final HandlerThread handlerThread = new HandlerThread("testUnfulfillableNetworkRequest");
- handlerThread.start();
- NetworkCapabilities filter = new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactory", filter, mCsHandlerThread);
- testFactory.setScoreFilter(40);
-
- // Register the factory and expect it to receive the default request.
- testFactory.register();
- testFactory.expectRequestAdd();
-
- try {
- // Now file the test request and expect it.
- mCm.requestNetwork(nr, networkCallback);
- final NetworkRequest newRequest = testFactory.expectRequestAdd().request;
-
- if (preUnregister) {
- mCm.unregisterNetworkCallback(networkCallback);
-
- // The request has been released : the factory should see it removed
- // immediately.
- testFactory.expectRequestRemove();
-
- // Simulate the factory releasing the request as unfulfillable: no-op since
- // the callback has already been unregistered (but a test that no exceptions are
- // thrown).
- testFactory.triggerUnfulfillable(newRequest);
- } else {
- // Simulate the factory releasing the request as unfulfillable and expect
- // onUnavailable!
- testFactory.triggerUnfulfillable(newRequest);
-
- networkCallback.expectCallback(CallbackEntry.UNAVAILABLE, (Network) null);
-
- // Declaring a request unfulfillable releases it automatically.
- testFactory.expectRequestRemove();
-
- // unregister network callback - a no-op (since already freed by the
- // on-unavailable), but should not fail or throw exceptions.
- mCm.unregisterNetworkCallback(networkCallback);
-
- // The factory should not see any further removal, as this request has
- // already been removed.
- }
- } finally {
- testFactory.terminate();
- handlerThread.quit();
- }
- }
-
- private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
-
- public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR }
-
- private class CallbackValue {
- public CallbackType callbackType;
- public int error;
-
- public CallbackValue(CallbackType type) {
- this.callbackType = type;
- this.error = PacketKeepalive.SUCCESS;
- assertTrue("onError callback must have error", type != CallbackType.ON_ERROR);
- }
-
- public CallbackValue(CallbackType type, int error) {
- this.callbackType = type;
- this.error = error;
- assertEquals("error can only be set for onError", type, CallbackType.ON_ERROR);
- }
-
- @Override
- public boolean equals(Object o) {
- return o instanceof CallbackValue &&
- this.callbackType == ((CallbackValue) o).callbackType &&
- this.error == ((CallbackValue) o).error;
- }
-
- @Override
- public String toString() {
- return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType, error);
- }
- }
-
- private final LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
-
- @Override
- public void onStarted() {
- mCallbacks.add(new CallbackValue(CallbackType.ON_STARTED));
- }
-
- @Override
- public void onStopped() {
- mCallbacks.add(new CallbackValue(CallbackType.ON_STOPPED));
- }
-
- @Override
- public void onError(int error) {
- mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, error));
- }
-
- private void expectCallback(CallbackValue callbackValue) throws InterruptedException {
- assertEquals(callbackValue, mCallbacks.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- }
-
- public void expectStarted() throws Exception {
- expectCallback(new CallbackValue(CallbackType.ON_STARTED));
- }
-
- public void expectStopped() throws Exception {
- expectCallback(new CallbackValue(CallbackType.ON_STOPPED));
- }
-
- public void expectError(int error) throws Exception {
- expectCallback(new CallbackValue(CallbackType.ON_ERROR, error));
- }
- }
-
- private static class TestSocketKeepaliveCallback extends SocketKeepalive.Callback {
-
- public enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
-
- private class CallbackValue {
- public CallbackType callbackType;
- public int error;
-
- CallbackValue(CallbackType type) {
- this.callbackType = type;
- this.error = SocketKeepalive.SUCCESS;
- assertTrue("onError callback must have error", type != CallbackType.ON_ERROR);
- }
-
- CallbackValue(CallbackType type, int error) {
- this.callbackType = type;
- this.error = error;
- assertEquals("error can only be set for onError", type, CallbackType.ON_ERROR);
- }
-
- @Override
- public boolean equals(Object o) {
- return o instanceof CallbackValue
- && this.callbackType == ((CallbackValue) o).callbackType
- && this.error == ((CallbackValue) o).error;
- }
-
- @Override
- public String toString() {
- return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType,
- error);
- }
- }
-
- private LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
- private final Executor mExecutor;
-
- TestSocketKeepaliveCallback(@NonNull Executor executor) {
- mExecutor = executor;
- }
-
- @Override
- public void onStarted() {
- mCallbacks.add(new CallbackValue(CallbackType.ON_STARTED));
- }
-
- @Override
- public void onStopped() {
- mCallbacks.add(new CallbackValue(CallbackType.ON_STOPPED));
- }
-
- @Override
- public void onError(int error) {
- mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, error));
- }
-
- private void expectCallback(CallbackValue callbackValue) throws InterruptedException {
- assertEquals(callbackValue, mCallbacks.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
- }
-
- public void expectStarted() throws InterruptedException {
- expectCallback(new CallbackValue(CallbackType.ON_STARTED));
- }
-
- public void expectStopped() throws InterruptedException {
- expectCallback(new CallbackValue(CallbackType.ON_STOPPED));
- }
-
- public void expectError(int error) throws InterruptedException {
- expectCallback(new CallbackValue(CallbackType.ON_ERROR, error));
- }
-
- public void assertNoCallback() {
- waitForIdleSerialExecutor(mExecutor, TIMEOUT_MS);
- CallbackValue cv = mCallbacks.peek();
- assertNull("Unexpected callback: " + cv, cv);
- }
- }
-
- private Network connectKeepaliveNetwork(LinkProperties lp) throws Exception {
- // Ensure the network is disconnected before anything else occurs
- if (mWiFiNetworkAgent != null) {
- assertNull(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()));
- }
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- mWiFiNetworkAgent.connect(true);
- b.expectBroadcast();
- verifyActiveNetwork(TRANSPORT_WIFI);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- waitForIdle();
- return mWiFiNetworkAgent.getNetwork();
- }
-
- @Test
- public void testPacketKeepalives() throws Exception {
- InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
- InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
- InetAddress myIPv6 = InetAddress.getByName("2001:db8::1");
- InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
- InetAddress dstIPv6 = InetAddress.getByName("2001:4860:4860::8888");
-
- final int validKaInterval = 15;
- final int invalidKaInterval = 9;
-
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("wlan12");
- lp.addLinkAddress(new LinkAddress(myIPv6, 64));
- lp.addLinkAddress(new LinkAddress(myIPv4, 25));
- lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
- lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
-
- Network notMyNet = new Network(61234);
- Network myNet = connectKeepaliveNetwork(lp);
-
- TestKeepaliveCallback callback = new TestKeepaliveCallback();
- PacketKeepalive ka;
-
- // Attempt to start keepalives with invalid parameters and check for errors.
- ka = mCm.startNattKeepalive(notMyNet, validKaInterval, callback, myIPv4, 1234, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
-
- ka = mCm.startNattKeepalive(myNet, invalidKaInterval, callback, myIPv4, 1234, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_INVALID_INTERVAL);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 1234, dstIPv6);
- callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv6, 1234, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
-
- // NAT-T is only supported for IPv4.
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv6, 1234, dstIPv6);
- callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 123456, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_INVALID_PORT);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 123456, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_INVALID_PORT);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
-
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
-
- // Check that a started keepalive can be stopped.
- mWiFiNetworkAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS);
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectStarted();
- mWiFiNetworkAgent.setStopKeepaliveEvent(PacketKeepalive.SUCCESS);
- ka.stop();
- callback.expectStopped();
-
- // Check that deleting the IP address stops the keepalive.
- LinkProperties bogusLp = new LinkProperties(lp);
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectStarted();
- bogusLp.removeLinkAddress(new LinkAddress(myIPv4, 25));
- bogusLp.addLinkAddress(new LinkAddress(notMyIPv4, 25));
- mWiFiNetworkAgent.sendLinkProperties(bogusLp);
- callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
- mWiFiNetworkAgent.sendLinkProperties(lp);
-
- // Check that a started keepalive is stopped correctly when the network disconnects.
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectStarted();
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
-
- // ... and that stopping it after that has no adverse effects.
- waitForIdle();
- final Network myNetAlias = myNet;
- assertNull(mCm.getNetworkCapabilities(myNetAlias));
- ka.stop();
-
- // Reconnect.
- myNet = connectKeepaliveNetwork(lp);
- mWiFiNetworkAgent.setStartKeepaliveEvent(PacketKeepalive.SUCCESS);
-
- // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
- mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
- ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
- callback.expectStarted();
-
- // The second one gets slot 2.
- mWiFiNetworkAgent.setExpectedKeepaliveSlot(2);
- TestKeepaliveCallback callback2 = new TestKeepaliveCallback();
- PacketKeepalive ka2 = mCm.startNattKeepalive(
- myNet, validKaInterval, callback2, myIPv4, 6789, dstIPv4);
- callback2.expectStarted();
-
- // Now stop the first one and create a third. This also gets slot 1.
- ka.stop();
- callback.expectStopped();
-
- mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
- TestKeepaliveCallback callback3 = new TestKeepaliveCallback();
- PacketKeepalive ka3 = mCm.startNattKeepalive(
- myNet, validKaInterval, callback3, myIPv4, 9876, dstIPv4);
- callback3.expectStarted();
-
- ka2.stop();
- callback2.expectStopped();
-
- ka3.stop();
- callback3.expectStopped();
- }
-
- // Helper method to prepare the executor and run test
- private void runTestWithSerialExecutors(ExceptionUtils.ThrowingConsumer<Executor> functor)
- throws Exception {
- final ExecutorService executorSingleThread = Executors.newSingleThreadExecutor();
- final Executor executorInline = (Runnable r) -> r.run();
- functor.accept(executorSingleThread);
- executorSingleThread.shutdown();
- functor.accept(executorInline);
- }
-
- @Test
- public void testNattSocketKeepalives() throws Exception {
- runTestWithSerialExecutors(executor -> doTestNattSocketKeepalivesWithExecutor(executor));
- runTestWithSerialExecutors(executor -> doTestNattSocketKeepalivesFdWithExecutor(executor));
- }
-
- private void doTestNattSocketKeepalivesWithExecutor(Executor executor) throws Exception {
- // TODO: 1. Move this outside of ConnectivityServiceTest.
- // 2. Make test to verify that Nat-T keepalive socket is created by IpSecService.
- // 3. Mock ipsec service.
- final InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
- final InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
- final InetAddress myIPv6 = InetAddress.getByName("2001:db8::1");
- final InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
- final InetAddress dstIPv6 = InetAddress.getByName("2001:4860:4860::8888");
-
- final int validKaInterval = 15;
- final int invalidKaInterval = 9;
-
- final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
- final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket();
- final int srcPort = testSocket.getPort();
-
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("wlan12");
- lp.addLinkAddress(new LinkAddress(myIPv6, 64));
- lp.addLinkAddress(new LinkAddress(myIPv4, 25));
- lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
- lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
-
- Network notMyNet = new Network(61234);
- Network myNet = connectKeepaliveNetwork(lp);
-
- TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor);
-
- // Attempt to start keepalives with invalid parameters and check for errors.
- // Invalid network.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- notMyNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK);
- }
-
- // Invalid interval.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(invalidKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_INTERVAL);
- }
-
- // Invalid destination.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv6, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
- }
-
- // Invalid source;
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv6, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
- }
-
- // NAT-T is only supported for IPv4.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv6, dstIPv6, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
- }
-
- // Basic check before testing started keepalive.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_UNSUPPORTED);
- }
-
- // Check that a started keepalive can be stopped.
- mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
- mWiFiNetworkAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS);
- ka.stop();
- callback.expectStopped();
-
- // Check that keepalive could be restarted.
- ka.start(validKaInterval);
- callback.expectStarted();
- ka.stop();
- callback.expectStopped();
-
- // Check that keepalive can be restarted without waiting for callback.
- ka.start(validKaInterval);
- callback.expectStarted();
- ka.stop();
- ka.start(validKaInterval);
- callback.expectStopped();
- callback.expectStarted();
- ka.stop();
- callback.expectStopped();
- }
-
- // Check that deleting the IP address stops the keepalive.
- LinkProperties bogusLp = new LinkProperties(lp);
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
- bogusLp.removeLinkAddress(new LinkAddress(myIPv4, 25));
- bogusLp.addLinkAddress(new LinkAddress(notMyIPv4, 25));
- mWiFiNetworkAgent.sendLinkProperties(bogusLp);
- callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- }
-
- // Check that a started keepalive is stopped correctly when the network disconnects.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK);
-
- // ... and that stopping it after that has no adverse effects.
- waitForIdle();
- final Network myNetAlias = myNet;
- assertNull(mCm.getNetworkCapabilities(myNetAlias));
- ka.stop();
- callback.assertNoCallback();
- }
-
- // Reconnect.
- myNet = connectKeepaliveNetwork(lp);
- mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
-
- // Check that a stop followed by network disconnects does not result in crash.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
- // Delay the response of keepalive events in networkAgent long enough to make sure
- // the follow-up network disconnection will be processed first.
- mWiFiNetworkAgent.setKeepaliveResponseDelay(3 * TIMEOUT_MS);
- ka.stop();
-
- // Make sure the stop has been processed. Wait for executor idle is needed to prevent
- // flaky since the actual stop call to the service is delegated to executor thread.
- waitForIdleSerialExecutor(executor, TIMEOUT_MS);
- waitForIdle();
-
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- callback.expectStopped();
- callback.assertNoCallback();
- }
-
- // Reconnect.
- waitForIdle();
- myNet = connectKeepaliveNetwork(lp);
- mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
-
- // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
- mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
- int srcPort2 = 0;
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
-
- // The second one gets slot 2.
- mWiFiNetworkAgent.setExpectedKeepaliveSlot(2);
- final UdpEncapsulationSocket testSocket2 = mIpSec.openUdpEncapsulationSocket();
- srcPort2 = testSocket2.getPort();
- TestSocketKeepaliveCallback callback2 = new TestSocketKeepaliveCallback(executor);
- try (SocketKeepalive ka2 = mCm.createSocketKeepalive(
- myNet, testSocket2, myIPv4, dstIPv4, executor, callback2)) {
- ka2.start(validKaInterval);
- callback2.expectStarted();
-
- ka.stop();
- callback.expectStopped();
-
- ka2.stop();
- callback2.expectStopped();
-
- testSocket.close();
- testSocket2.close();
- }
- }
-
- // Check that there is no port leaked after all keepalives and sockets are closed.
- // TODO: enable this check after ensuring a valid free port. See b/129512753#comment7.
- // assertFalse(isUdpPortInUse(srcPort));
- // assertFalse(isUdpPortInUse(srcPort2));
-
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- mWiFiNetworkAgent = null;
- }
-
- @Test
- public void testTcpSocketKeepalives() throws Exception {
- runTestWithSerialExecutors(executor -> doTestTcpSocketKeepalivesWithExecutor(executor));
- }
-
- private void doTestTcpSocketKeepalivesWithExecutor(Executor executor) throws Exception {
- final int srcPortV4 = 12345;
- final int srcPortV6 = 23456;
- final InetAddress myIPv4 = InetAddress.getByName("127.0.0.1");
- final InetAddress myIPv6 = InetAddress.getByName("::1");
-
- final int validKaInterval = 15;
-
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("wlan12");
- lp.addLinkAddress(new LinkAddress(myIPv6, 64));
- lp.addLinkAddress(new LinkAddress(myIPv4, 25));
- lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
- lp.addRoute(new RouteInfo(InetAddress.getByName("127.0.0.254")));
-
- final Network notMyNet = new Network(61234);
- final Network myNet = connectKeepaliveNetwork(lp);
-
- final Socket testSocketV4 = new Socket();
- final Socket testSocketV6 = new Socket();
-
- TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor);
-
- // Attempt to start Tcp keepalives with invalid parameters and check for errors.
- // Invalid network.
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- notMyNet, testSocketV4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK);
- }
-
- // Invalid Socket (socket is not bound with IPv4 address).
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocketV4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
- }
-
- // Invalid Socket (socket is not bound with IPv6 address).
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocketV6, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
- }
-
- // Bind the socket address
- testSocketV4.bind(new InetSocketAddress(myIPv4, srcPortV4));
- testSocketV6.bind(new InetSocketAddress(myIPv6, srcPortV6));
-
- // Invalid Socket (socket is bound with IPv4 address).
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocketV4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
- }
-
- // Invalid Socket (socket is bound with IPv6 address).
- try (SocketKeepalive ka = mCm.createSocketKeepalive(
- myNet, testSocketV6, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
- }
-
- testSocketV4.close();
- testSocketV6.close();
-
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- mWiFiNetworkAgent = null;
- }
-
- private void doTestNattSocketKeepalivesFdWithExecutor(Executor executor) throws Exception {
- final InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
- final InetAddress anyIPv4 = InetAddress.getByName("0.0.0.0");
- final InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
- final int validKaInterval = 15;
-
- // Prepare the target network.
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("wlan12");
- lp.addLinkAddress(new LinkAddress(myIPv4, 25));
- lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
- Network myNet = connectKeepaliveNetwork(lp);
- mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
- mWiFiNetworkAgent.setStopKeepaliveEvent(SocketKeepalive.SUCCESS);
-
- TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor);
-
- // Prepare the target file descriptor, keep only one instance.
- final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
- final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket();
- final int srcPort = testSocket.getPort();
- final ParcelFileDescriptor testPfd =
- ParcelFileDescriptor.dup(testSocket.getFileDescriptor());
- testSocket.close();
- assertTrue(isUdpPortInUse(srcPort));
-
- // Start keepalive and explicit make the variable goes out of scope with try-with-resources
- // block.
- try (SocketKeepalive ka = mCm.createNattKeepalive(
- myNet, testPfd, myIPv4, dstIPv4, executor, callback)) {
- ka.start(validKaInterval);
- callback.expectStarted();
- ka.stop();
- callback.expectStopped();
- }
-
- // Check that the ParcelFileDescriptor is still valid after keepalive stopped,
- // ErrnoException with EBADF will be thrown if the socket is closed when checking local
- // address.
- assertTrue(isUdpPortInUse(srcPort));
- final InetSocketAddress sa =
- (InetSocketAddress) Os.getsockname(testPfd.getFileDescriptor());
- assertEquals(anyIPv4, sa.getAddress());
-
- testPfd.close();
- // TODO: enable this check after ensuring a valid free port. See b/129512753#comment7.
- // assertFalse(isUdpPortInUse(srcPort));
-
- mWiFiNetworkAgent.disconnect();
- mWiFiNetworkAgent.expectDisconnected();
- mWiFiNetworkAgent = null;
- }
-
- private static boolean isUdpPortInUse(int port) {
- try (DatagramSocket ignored = new DatagramSocket(port)) {
- return false;
- } catch (IOException alreadyInUse) {
- return true;
- }
- }
-
- @Test
- public void testGetCaptivePortalServerUrl() throws Exception {
- String url = mCm.getCaptivePortalServerUrl();
- assertEquals("http://connectivitycheck.gstatic.com/generate_204", url);
- }
-
- private static class TestNetworkPinner extends NetworkPinner {
- public static boolean awaitPin(int timeoutMs) throws InterruptedException {
- synchronized(sLock) {
- if (sNetwork == null) {
- sLock.wait(timeoutMs);
- }
- return sNetwork != null;
- }
- }
-
- public static boolean awaitUnpin(int timeoutMs) throws InterruptedException {
- synchronized(sLock) {
- if (sNetwork != null) {
- sLock.wait(timeoutMs);
- }
- return sNetwork == null;
- }
- }
- }
-
- private void assertPinnedToWifiWithCellDefault() {
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- }
-
- private void assertPinnedToWifiWithWifiDefault() {
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- }
-
- private void assertNotPinnedToWifi() {
- assertNull(mCm.getBoundNetworkForProcess());
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- }
-
- @Test
- public void testNetworkPinner() throws Exception {
- NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI)
- .build();
- assertNull(mCm.getBoundNetworkForProcess());
-
- TestNetworkPinner.pin(mServiceContext, wifiRequest);
- assertNull(mCm.getBoundNetworkForProcess());
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
-
- // When wi-fi connects, expect to be pinned.
- assertTrue(TestNetworkPinner.awaitPin(100));
- assertPinnedToWifiWithCellDefault();
-
- // Disconnect and expect the pin to drop.
- mWiFiNetworkAgent.disconnect();
- assertTrue(TestNetworkPinner.awaitUnpin(100));
- assertNotPinnedToWifi();
-
- // Reconnecting does not cause the pin to come back.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- assertFalse(TestNetworkPinner.awaitPin(100));
- assertNotPinnedToWifi();
-
- // Pinning while connected causes the pin to take effect immediately.
- TestNetworkPinner.pin(mServiceContext, wifiRequest);
- assertTrue(TestNetworkPinner.awaitPin(100));
- assertPinnedToWifiWithCellDefault();
-
- // Explicitly unpin and expect to use the default network again.
- TestNetworkPinner.unpin();
- assertNotPinnedToWifi();
-
- // Disconnect cell and wifi.
- ExpectedBroadcast b = registerConnectivityBroadcast(3); // cell down, wifi up, wifi down.
- mCellNetworkAgent.disconnect();
- mWiFiNetworkAgent.disconnect();
- b.expectBroadcast();
-
- // Pinning takes effect even if the pinned network is the default when the pin is set...
- TestNetworkPinner.pin(mServiceContext, wifiRequest);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- assertTrue(TestNetworkPinner.awaitPin(100));
- assertPinnedToWifiWithWifiDefault();
-
- // ... and is maintained even when that network is no longer the default.
- b = registerConnectivityBroadcast(1);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mCellNetworkAgent.connect(true);
- b.expectBroadcast();
- assertPinnedToWifiWithCellDefault();
- }
-
- @Test
- public void testNetworkCallbackMaximum() throws Exception {
- final int MAX_REQUESTS = 100;
- final int CALLBACKS = 89;
- final int INTENTS = 11;
- final int SYSTEM_ONLY_MAX_REQUESTS = 250;
- assertEquals(MAX_REQUESTS, CALLBACKS + INTENTS);
-
- NetworkRequest networkRequest = new NetworkRequest.Builder().build();
- ArrayList<Object> registered = new ArrayList<>();
-
- int j = 0;
- while (j++ < CALLBACKS / 2) {
- NetworkCallback cb = new NetworkCallback();
- mCm.requestNetwork(networkRequest, cb);
- registered.add(cb);
- }
- while (j++ < CALLBACKS) {
- NetworkCallback cb = new NetworkCallback();
- mCm.registerNetworkCallback(networkRequest, cb);
- registered.add(cb);
- }
- j = 0;
- while (j++ < INTENTS / 2) {
- final PendingIntent pi = PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
- new Intent("a" + j), FLAG_IMMUTABLE);
- mCm.requestNetwork(networkRequest, pi);
- registered.add(pi);
- }
- while (j++ < INTENTS) {
- final PendingIntent pi = PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
- new Intent("b" + j), FLAG_IMMUTABLE);
- mCm.registerNetworkCallback(networkRequest, pi);
- registered.add(pi);
- }
-
- // Test that the limit is enforced when MAX_REQUESTS simultaneous requests are added.
- assertThrows(TooManyRequestsException.class, () ->
- mCm.requestNetwork(networkRequest, new NetworkCallback())
- );
- assertThrows(TooManyRequestsException.class, () ->
- mCm.registerNetworkCallback(networkRequest, new NetworkCallback())
- );
- assertThrows(TooManyRequestsException.class, () ->
- mCm.requestNetwork(networkRequest,
- PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
- new Intent("c"), FLAG_IMMUTABLE))
- );
- assertThrows(TooManyRequestsException.class, () ->
- mCm.registerNetworkCallback(networkRequest,
- PendingIntent.getBroadcast(mContext, 0 /* requestCode */,
- new Intent("d"), FLAG_IMMUTABLE))
- );
-
- // The system gets another SYSTEM_ONLY_MAX_REQUESTS slots.
- final Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
- withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () -> {
- ArrayList<NetworkCallback> systemRegistered = new ArrayList<>();
- for (int i = 0; i < SYSTEM_ONLY_MAX_REQUESTS - 1; i++) {
- NetworkCallback cb = new NetworkCallback();
- if (i % 2 == 0) {
- mCm.registerDefaultNetworkCallbackForUid(1000000 + i, cb, handler);
- } else {
- mCm.registerNetworkCallback(networkRequest, cb);
- }
- systemRegistered.add(cb);
- }
- waitForIdle();
-
- assertThrows(TooManyRequestsException.class, () ->
- mCm.registerDefaultNetworkCallbackForUid(1001042, new NetworkCallback(),
- handler));
- assertThrows(TooManyRequestsException.class, () ->
- mCm.registerNetworkCallback(networkRequest, new NetworkCallback()));
-
- for (NetworkCallback callback : systemRegistered) {
- mCm.unregisterNetworkCallback(callback);
- }
- waitForIdle(); // Wait for requests to be unregistered before giving up the permission.
- });
-
- for (Object o : registered) {
- if (o instanceof NetworkCallback) {
- mCm.unregisterNetworkCallback((NetworkCallback)o);
- }
- if (o instanceof PendingIntent) {
- mCm.unregisterNetworkCallback((PendingIntent)o);
- }
- }
- waitForIdle();
-
- // Test that the limit is not hit when MAX_REQUESTS requests are added and removed.
- for (int i = 0; i < MAX_REQUESTS; i++) {
- NetworkCallback networkCallback = new NetworkCallback();
- mCm.requestNetwork(networkRequest, networkCallback);
- mCm.unregisterNetworkCallback(networkCallback);
- }
- waitForIdle();
-
- for (int i = 0; i < MAX_REQUESTS; i++) {
- NetworkCallback networkCallback = new NetworkCallback();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
- mCm.unregisterNetworkCallback(networkCallback);
- }
- waitForIdle();
-
- for (int i = 0; i < MAX_REQUESTS; i++) {
- NetworkCallback networkCallback = new NetworkCallback();
- mCm.registerDefaultNetworkCallback(networkCallback);
- mCm.unregisterNetworkCallback(networkCallback);
- }
- waitForIdle();
-
- for (int i = 0; i < MAX_REQUESTS; i++) {
- NetworkCallback networkCallback = new NetworkCallback();
- mCm.registerDefaultNetworkCallback(networkCallback);
- mCm.unregisterNetworkCallback(networkCallback);
- }
- waitForIdle();
-
- withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () -> {
- for (int i = 0; i < MAX_REQUESTS; i++) {
- NetworkCallback networkCallback = new NetworkCallback();
- mCm.registerDefaultNetworkCallbackForUid(1000000 + i, networkCallback,
- new Handler(ConnectivityThread.getInstanceLooper()));
- mCm.unregisterNetworkCallback(networkCallback);
- }
- });
- waitForIdle();
-
- for (int i = 0; i < MAX_REQUESTS; i++) {
- final PendingIntent pendingIntent = PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, new Intent("e" + i), FLAG_IMMUTABLE);
- mCm.requestNetwork(networkRequest, pendingIntent);
- mCm.unregisterNetworkCallback(pendingIntent);
- }
- waitForIdle();
-
- for (int i = 0; i < MAX_REQUESTS; i++) {
- final PendingIntent pendingIntent = PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, new Intent("f" + i), FLAG_IMMUTABLE);
- mCm.registerNetworkCallback(networkRequest, pendingIntent);
- mCm.unregisterNetworkCallback(pendingIntent);
- }
- }
-
- @Test
- public void testNetworkInfoOfTypeNone() throws Exception {
- ExpectedBroadcast b = registerConnectivityBroadcast(1);
-
- verifyNoNetwork();
- TestNetworkAgentWrapper wifiAware = new TestNetworkAgentWrapper(TRANSPORT_WIFI_AWARE);
- assertNull(mCm.getActiveNetworkInfo());
-
- Network[] allNetworks = mCm.getAllNetworks();
- assertLength(1, allNetworks);
- Network network = allNetworks[0];
- NetworkCapabilities capabilities = mCm.getNetworkCapabilities(network);
- assertTrue(capabilities.hasTransport(TRANSPORT_WIFI_AWARE));
-
- final NetworkRequest request =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI_AWARE).build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- // Bring up wifi aware network.
- wifiAware.connect(false, false, false /* isStrictMode */);
- callback.expectAvailableCallbacksUnvalidated(wifiAware);
-
- assertNull(mCm.getActiveNetworkInfo());
- assertNull(mCm.getActiveNetwork());
- // TODO: getAllNetworkInfo is dirty and returns a non-empty array right from the start
- // of this test. Fix it and uncomment the assert below.
- //assertEmpty(mCm.getAllNetworkInfo());
-
- // Disconnect wifi aware network.
- wifiAware.disconnect();
- callback.expectCallbackThat(TIMEOUT_MS, (info) -> info instanceof CallbackEntry.Lost);
- mCm.unregisterNetworkCallback(callback);
-
- verifyNoNetwork();
- b.expectNoBroadcast(10);
- }
-
- @Test
- public void testDeprecatedAndUnsupportedOperations() throws Exception {
- final int TYPE_NONE = ConnectivityManager.TYPE_NONE;
- assertNull(mCm.getNetworkInfo(TYPE_NONE));
- assertNull(mCm.getNetworkForType(TYPE_NONE));
- assertNull(mCm.getLinkProperties(TYPE_NONE));
- assertFalse(mCm.isNetworkSupported(TYPE_NONE));
-
- assertThrows(IllegalArgumentException.class,
- () -> mCm.networkCapabilitiesForType(TYPE_NONE));
-
- Class<UnsupportedOperationException> unsupported = UnsupportedOperationException.class;
- assertThrows(unsupported, () -> mCm.startUsingNetworkFeature(TYPE_WIFI, ""));
- assertThrows(unsupported, () -> mCm.stopUsingNetworkFeature(TYPE_WIFI, ""));
- // TODO: let test context have configuration application target sdk version
- // and test that pre-M requesting for TYPE_NONE sends back APN_REQUEST_FAILED
- assertThrows(unsupported, () -> mCm.startUsingNetworkFeature(TYPE_NONE, ""));
- assertThrows(unsupported, () -> mCm.stopUsingNetworkFeature(TYPE_NONE, ""));
- assertThrows(unsupported, () -> mCm.requestRouteToHostAddress(TYPE_NONE, null));
- }
-
- @Test
- public void testLinkPropertiesEnsuresDirectlyConnectedRoutes() throws Exception {
- final NetworkRequest networkRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
-
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(WIFI_IFNAME);
- LinkAddress myIpv4Address = new LinkAddress("192.168.12.3/24");
- RouteInfo myIpv4DefaultRoute = new RouteInfo((IpPrefix) null,
- InetAddresses.parseNumericAddress("192.168.12.1"), lp.getInterfaceName());
- lp.addLinkAddress(myIpv4Address);
- lp.addRoute(myIpv4DefaultRoute);
-
- // Verify direct routes are added when network agent is first registered in
- // ConnectivityService.
- TestNetworkAgentWrapper networkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp);
- networkAgent.connect(true);
- networkCallback.expectCallback(CallbackEntry.AVAILABLE, networkAgent);
- networkCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, networkAgent);
- CallbackEntry.LinkPropertiesChanged cbi =
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- networkAgent);
- networkCallback.expectCallback(CallbackEntry.BLOCKED_STATUS, networkAgent);
- networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, networkAgent);
- networkCallback.assertNoCallback();
- checkDirectlyConnectedRoutes(cbi.getLp(), Arrays.asList(myIpv4Address),
- Arrays.asList(myIpv4DefaultRoute));
- checkDirectlyConnectedRoutes(mCm.getLinkProperties(networkAgent.getNetwork()),
- Arrays.asList(myIpv4Address), Arrays.asList(myIpv4DefaultRoute));
-
- // Verify direct routes are added during subsequent link properties updates.
- LinkProperties newLp = new LinkProperties(lp);
- LinkAddress myIpv6Address1 = new LinkAddress("fe80::cafe/64");
- LinkAddress myIpv6Address2 = new LinkAddress("2001:db8::2/64");
- newLp.addLinkAddress(myIpv6Address1);
- newLp.addLinkAddress(myIpv6Address2);
- networkAgent.sendLinkProperties(newLp);
- cbi = networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, networkAgent);
- networkCallback.assertNoCallback();
- checkDirectlyConnectedRoutes(cbi.getLp(),
- Arrays.asList(myIpv4Address, myIpv6Address1, myIpv6Address2),
- Arrays.asList(myIpv4DefaultRoute));
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- private void expectNotifyNetworkStatus(List<Network> networks, String defaultIface,
- Integer vpnUid, String vpnIfname, List<String> underlyingIfaces) throws Exception {
- ArgumentCaptor<List<Network>> networksCaptor = ArgumentCaptor.forClass(List.class);
- ArgumentCaptor<List<UnderlyingNetworkInfo>> vpnInfosCaptor =
- ArgumentCaptor.forClass(List.class);
-
- verify(mStatsManager, atLeastOnce()).notifyNetworkStatus(networksCaptor.capture(),
- any(List.class), eq(defaultIface), vpnInfosCaptor.capture());
-
- assertSameElements(networksCaptor.getValue(), networks);
-
- List<UnderlyingNetworkInfo> infos = vpnInfosCaptor.getValue();
- if (vpnUid != null) {
- assertEquals("Should have exactly one VPN:", 1, infos.size());
- UnderlyingNetworkInfo info = infos.get(0);
- assertEquals("Unexpected VPN owner:", (int) vpnUid, info.getOwnerUid());
- assertEquals("Unexpected VPN interface:", vpnIfname, info.getInterface());
- assertSameElements(underlyingIfaces, info.getUnderlyingInterfaces());
- } else {
- assertEquals(0, infos.size());
- return;
- }
- }
-
- private void expectNotifyNetworkStatus(
- List<Network> networks, String defaultIface) throws Exception {
- expectNotifyNetworkStatus(networks, defaultIface, null, null, List.of());
- }
-
- @Test
- public void testStatsIfacesChanged() throws Exception {
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-
- final List<Network> onlyCell = List.of(mCellNetworkAgent.getNetwork());
- final List<Network> onlyWifi = List.of(mWiFiNetworkAgent.getNetwork());
-
- LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- LinkProperties wifiLp = new LinkProperties();
- wifiLp.setInterfaceName(WIFI_IFNAME);
-
- // Simple connection should have updated ifaces
- mCellNetworkAgent.connect(false);
- mCellNetworkAgent.sendLinkProperties(cellLp);
- waitForIdle();
- expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
- reset(mStatsManager);
-
- // Default network switch should update ifaces.
- mWiFiNetworkAgent.connect(false);
- mWiFiNetworkAgent.sendLinkProperties(wifiLp);
- waitForIdle();
- assertEquals(wifiLp, mService.getActiveLinkProperties());
- expectNotifyNetworkStatus(onlyWifi, WIFI_IFNAME);
- reset(mStatsManager);
-
- // Disconnect should update ifaces.
- mWiFiNetworkAgent.disconnect();
- waitForIdle();
- expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
- reset(mStatsManager);
-
- // Metered change should update ifaces
- mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- waitForIdle();
- expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
- reset(mStatsManager);
-
- mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- waitForIdle();
- expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
- reset(mStatsManager);
-
- // Temp metered change shouldn't update ifaces
- mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
- waitForIdle();
- verify(mStatsManager, never()).notifyNetworkStatus(eq(onlyCell),
- any(List.class), eq(MOBILE_IFNAME), any(List.class));
- reset(mStatsManager);
-
- // Roaming change should update ifaces
- mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
- waitForIdle();
- expectNotifyNetworkStatus(onlyCell, MOBILE_IFNAME);
- reset(mStatsManager);
-
- // Test VPNs.
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(VPN_IFNAME);
-
- mMockVpn.establishForMyUid(lp);
- assertUidRangesUpdatedForMyUid(true);
-
- final List<Network> cellAndVpn =
- List.of(mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork());
-
- // A VPN with default (null) underlying networks sets the underlying network's interfaces...
- expectNotifyNetworkStatus(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- List.of(MOBILE_IFNAME));
-
- // ...and updates them as the default network switches.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- mWiFiNetworkAgent.sendLinkProperties(wifiLp);
- final Network[] onlyNull = new Network[]{null};
- final List<Network> wifiAndVpn =
- List.of(mWiFiNetworkAgent.getNetwork(), mMockVpn.getNetwork());
- final List<Network> cellAndWifi =
- List.of(mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork());
- final Network[] cellNullAndWifi =
- new Network[]{mCellNetworkAgent.getNetwork(), null, mWiFiNetworkAgent.getNetwork()};
-
- waitForIdle();
- assertEquals(wifiLp, mService.getActiveLinkProperties());
- expectNotifyNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
- List.of(WIFI_IFNAME));
- reset(mStatsManager);
-
- // A VPN that sets its underlying networks passes the underlying interfaces, and influences
- // the default interface sent to NetworkStatsService by virtue of applying to the system
- // server UID (or, in this test, to the test's UID). This is the reason for sending
- // MOBILE_IFNAME even though the default network is wifi.
- // TODO: fix this to pass in the actual default network interface. Whether or not the VPN
- // applies to the system server UID should not have any bearing on network stats.
- mMockVpn.setUnderlyingNetworks(onlyCell.toArray(new Network[0]));
- waitForIdle();
- expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- List.of(MOBILE_IFNAME));
- reset(mStatsManager);
-
- mMockVpn.setUnderlyingNetworks(cellAndWifi.toArray(new Network[0]));
- waitForIdle();
- expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- List.of(MOBILE_IFNAME, WIFI_IFNAME));
- reset(mStatsManager);
-
- // Null underlying networks are ignored.
- mMockVpn.setUnderlyingNetworks(cellNullAndWifi);
- waitForIdle();
- expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- List.of(MOBILE_IFNAME, WIFI_IFNAME));
- reset(mStatsManager);
-
- // If an underlying network disconnects, that interface should no longer be underlying.
- // This doesn't actually work because disconnectAndDestroyNetwork only notifies
- // NetworkStatsService before the underlying network is actually removed. So the underlying
- // network will only be removed if notifyIfacesChangedForNetworkStats is called again. This
- // could result in incorrect data usage measurements if the interface used by the
- // disconnected network is reused by a system component that does not register an agent for
- // it (e.g., tethering).
- mCellNetworkAgent.disconnect();
- waitForIdle();
- assertNull(mService.getLinkProperties(mCellNetworkAgent.getNetwork()));
- expectNotifyNetworkStatus(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
- List.of(MOBILE_IFNAME, WIFI_IFNAME));
-
- // Confirm that we never tell NetworkStatsService that cell is no longer the underlying
- // network for the VPN...
- verify(mStatsManager, never()).notifyNetworkStatus(any(List.class),
- any(List.class), any() /* anyString() doesn't match null */,
- argThat(infos -> infos.get(0).getUnderlyingInterfaces().size() == 1
- && WIFI_IFNAME.equals(infos.get(0).getUnderlyingInterfaces().get(0))));
- verifyNoMoreInteractions(mStatsManager);
- reset(mStatsManager);
-
- // ... but if something else happens that causes notifyIfacesChangedForNetworkStats to be
- // called again, it does. For example, connect Ethernet, but with a low score, such that it
- // does not become the default network.
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
- mEthernetNetworkAgent.setScore(
- new NetworkScore.Builder().setLegacyInt(30).setExiting(true).build());
- mEthernetNetworkAgent.connect(false);
- waitForIdle();
- verify(mStatsManager).notifyNetworkStatus(any(List.class),
- any(List.class), any() /* anyString() doesn't match null */,
- argThat(vpnInfos -> vpnInfos.get(0).getUnderlyingInterfaces().size() == 1
- && WIFI_IFNAME.equals(vpnInfos.get(0).getUnderlyingInterfaces().get(0))));
- mEthernetNetworkAgent.disconnect();
- waitForIdle();
- reset(mStatsManager);
-
- // When a VPN declares no underlying networks (i.e., no connectivity), getAllVpnInfo
- // does not return the VPN, so CS does not pass it to NetworkStatsService. This causes
- // NetworkStatsFactory#adjustForTunAnd464Xlat not to attempt any VPN data migration, which
- // is probably a performance improvement (though it's very unlikely that a VPN would declare
- // no underlying networks).
- // Also, for the same reason as above, the active interface passed in is null.
- mMockVpn.setUnderlyingNetworks(new Network[0]);
- waitForIdle();
- expectNotifyNetworkStatus(wifiAndVpn, null);
- reset(mStatsManager);
-
- // Specifying only a null underlying network is the same as no networks.
- mMockVpn.setUnderlyingNetworks(onlyNull);
- waitForIdle();
- expectNotifyNetworkStatus(wifiAndVpn, null);
- reset(mStatsManager);
-
- // Specifying networks that are all disconnected is the same as specifying no networks.
- mMockVpn.setUnderlyingNetworks(onlyCell.toArray(new Network[0]));
- waitForIdle();
- expectNotifyNetworkStatus(wifiAndVpn, null);
- reset(mStatsManager);
-
- // Passing in null again means follow the default network again.
- mMockVpn.setUnderlyingNetworks(null);
- waitForIdle();
- expectNotifyNetworkStatus(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
- List.of(WIFI_IFNAME));
- reset(mStatsManager);
- }
-
- @Test
- public void testBasicDnsConfigurationPushed() throws Exception {
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
-
- // Clear any interactions that occur as a result of CS starting up.
- reset(mMockDnsResolver);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- waitForIdle();
- verify(mMockDnsResolver, never()).setResolverConfiguration(any());
- verifyNoMoreInteractions(mMockDnsResolver);
-
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- // Add IPv4 and IPv6 default routes, because DNS-over-TLS code does
- // "is-reachable" testing in order to not program netd with unreachable
- // nameservers that it might try repeated to validate.
- cellLp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
- cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
- MOBILE_IFNAME));
- cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
- cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
- MOBILE_IFNAME));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- mCellNetworkAgent.connect(false);
- waitForIdle();
-
- verify(mMockDnsResolver, times(1)).createNetworkCache(
- eq(mCellNetworkAgent.getNetwork().netId));
- // CS tells dnsresolver about the empty DNS config for this network.
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
- reset(mMockDnsResolver);
-
- cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- waitForIdle();
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(1, resolvrParams.servers.length);
- assertTrue(ArrayUtils.contains(resolvrParams.servers, "2001:db8::1"));
- // Opportunistic mode.
- assertTrue(ArrayUtils.contains(resolvrParams.tlsServers, "2001:db8::1"));
- reset(mMockDnsResolver);
-
- cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- waitForIdle();
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(2, resolvrParams.servers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
- // Opportunistic mode.
- assertEquals(2, resolvrParams.tlsServers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
- reset(mMockDnsResolver);
-
- final String TLS_SPECIFIER = "tls.example.com";
- final String TLS_SERVER6 = "2001:db8:53::53";
- final InetAddress[] TLS_IPS = new InetAddress[]{ InetAddress.getByName(TLS_SERVER6) };
- final String[] TLS_SERVERS = new String[]{ TLS_SERVER6 };
- mCellNetworkAgent.mNmCallbacks.notifyPrivateDnsConfigResolved(
- new PrivateDnsConfig(TLS_SPECIFIER, TLS_IPS).toParcel());
-
- waitForIdle();
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(2, resolvrParams.servers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[]{"2001:db8::1", "192.0.2.1"}));
- reset(mMockDnsResolver);
- }
-
- @Test
- public void testDnsConfigurationTransTypesPushed() throws Exception {
- // Clear any interactions that occur as a result of CS starting up.
- reset(mMockDnsResolver);
-
- final NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
- .build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- verify(mMockDnsResolver, times(1)).createNetworkCache(
- eq(mWiFiNetworkAgent.getNetwork().netId));
- verify(mMockDnsResolver, times(2)).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- final ResolverParamsParcel resolverParams = mResolverParamsParcelCaptor.getValue();
- assertContainsExactly(resolverParams.transportTypes, TRANSPORT_WIFI);
- reset(mMockDnsResolver);
- }
-
- @Test
- public void testPrivateDnsNotification() throws Exception {
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
- .build();
- TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
- // Bring up wifi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- // Private DNS resolution failed, checking if the notification will be shown or not.
- mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */);
- mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- waitForIdle();
- // If network validation failed, NetworkMonitor will re-evaluate the network.
- // ConnectivityService should filter the redundant notification. This part is trying to
- // simulate that situation and check if ConnectivityService could filter that case.
- mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- waitForIdle();
- verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).notify(anyString(),
- eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any());
- // If private DNS resolution successful, the PRIVATE_DNS_BROKEN notification shouldn't be
- // shown.
- mWiFiNetworkAgent.setNetworkValid(true /* isStrictMode */);
- mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- waitForIdle();
- verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).cancel(anyString(),
- eq(NotificationType.PRIVATE_DNS_BROKEN.eventId));
- // If private DNS resolution failed again, the PRIVATE_DNS_BROKEN notification should be
- // shown again.
- mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */);
- mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- waitForIdle();
- verify(mNotificationManager, timeout(TIMEOUT_MS).times(2)).notify(anyString(),
- eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any());
- }
-
- @Test
- public void testPrivateDnsSettingsChange() throws Exception {
- // Clear any interactions that occur as a result of CS starting up.
- reset(mMockDnsResolver);
-
- // The default on Android is opportunistic mode ("Automatic").
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
-
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.requestNetwork(cellRequest, cellNetworkCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- waitForIdle();
- // CS tells netd about the empty DNS config for this network.
- verify(mMockDnsResolver, never()).setResolverConfiguration(any());
- verifyNoMoreInteractions(mMockDnsResolver);
-
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- // Add IPv4 and IPv6 default routes, because DNS-over-TLS code does
- // "is-reachable" testing in order to not program netd with unreachable
- // nameservers that it might try repeated to validate.
- cellLp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
- cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
- MOBILE_IFNAME));
- cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
- cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
- MOBILE_IFNAME));
- cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
- cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
-
- mCellNetworkAgent.sendLinkProperties(cellLp);
- mCellNetworkAgent.connect(false);
- waitForIdle();
- verify(mMockDnsResolver, times(1)).createNetworkCache(
- eq(mCellNetworkAgent.getNetwork().netId));
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(2, resolvrParams.tlsServers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
- // Opportunistic mode.
- assertEquals(2, resolvrParams.tlsServers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
- reset(mMockDnsResolver);
- cellNetworkCallback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED,
- mCellNetworkAgent);
- CallbackEntry.LinkPropertiesChanged cbi = cellNetworkCallback.expectCallback(
- CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.BLOCKED_STATUS, mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertFalse(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
-
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
- verify(mMockDnsResolver, times(1)).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(2, resolvrParams.servers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
- reset(mMockDnsResolver);
- cellNetworkCallback.assertNoCallback();
-
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(2, resolvrParams.servers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.servers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
- assertEquals(2, resolvrParams.tlsServers.length);
- assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
- new String[] { "2001:db8::1", "192.0.2.1" }));
- reset(mMockDnsResolver);
- cellNetworkCallback.assertNoCallback();
-
- setPrivateDnsSettings(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, "strict.example.com");
- // Can't test dns configuration for strict mode without properly mocking
- // out the DNS lookups, but can test that LinkProperties is updated.
- cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertTrue(cbi.getLp().isPrivateDnsActive());
- assertEquals("strict.example.com", cbi.getLp().getPrivateDnsServerName());
- }
-
- private PrivateDnsValidationEventParcel makePrivateDnsValidationEvent(
- final int netId, final String ipAddress, final String hostname, final int validation) {
- final PrivateDnsValidationEventParcel event = new PrivateDnsValidationEventParcel();
- event.netId = netId;
- event.ipAddress = ipAddress;
- event.hostname = hostname;
- event.validation = validation;
- return event;
- }
-
- @Test
- public void testLinkPropertiesWithPrivateDnsValidationEvents() throws Exception {
- // The default on Android is opportunistic mode ("Automatic").
- setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
-
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.requestNetwork(cellRequest, cellNetworkCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- waitForIdle();
- LinkProperties lp = new LinkProperties();
- mCellNetworkAgent.sendLinkProperties(lp);
- mCellNetworkAgent.connect(false);
- waitForIdle();
- cellNetworkCallback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED,
- mCellNetworkAgent);
- CallbackEntry.LinkPropertiesChanged cbi = cellNetworkCallback.expectCallback(
- CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackEntry.BLOCKED_STATUS, mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertFalse(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
- Set<InetAddress> dnsServers = new HashSet<>();
- checkDnsServers(cbi.getLp(), dnsServers);
-
- // Send a validation event for a server that is not part of the current
- // resolver config. The validation event should be ignored.
- mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
- makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId, "",
- "145.100.185.18", VALIDATION_RESULT_SUCCESS));
- cellNetworkCallback.assertNoCallback();
-
- // Add a dns server to the LinkProperties.
- LinkProperties lp2 = new LinkProperties(lp);
- lp2.addDnsServer(InetAddress.getByName("145.100.185.16"));
- mCellNetworkAgent.sendLinkProperties(lp2);
- cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertFalse(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
- dnsServers.add(InetAddress.getByName("145.100.185.16"));
- checkDnsServers(cbi.getLp(), dnsServers);
-
- // Send a validation event containing a hostname that is not part of
- // the current resolver config. The validation event should be ignored.
- mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
- makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId,
- "145.100.185.16", "hostname", VALIDATION_RESULT_SUCCESS));
- cellNetworkCallback.assertNoCallback();
-
- // Send a validation event where validation failed.
- mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
- makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId,
- "145.100.185.16", "", VALIDATION_RESULT_FAILURE));
- cellNetworkCallback.assertNoCallback();
-
- // Send a validation event where validation succeeded for a server in
- // the current resolver config. A LinkProperties callback with updated
- // private dns fields should be sent.
- mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent(
- makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId,
- "145.100.185.16", "", VALIDATION_RESULT_SUCCESS));
- cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertTrue(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
- checkDnsServers(cbi.getLp(), dnsServers);
-
- // The private dns fields in LinkProperties should be preserved when
- // the network agent sends unrelated changes.
- LinkProperties lp3 = new LinkProperties(lp2);
- lp3.setMtu(1300);
- mCellNetworkAgent.sendLinkProperties(lp3);
- cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertTrue(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
- checkDnsServers(cbi.getLp(), dnsServers);
- assertEquals(1300, cbi.getLp().getMtu());
-
- // Removing the only validated server should affect the private dns
- // fields in LinkProperties.
- LinkProperties lp4 = new LinkProperties(lp3);
- lp4.removeDnsServer(InetAddress.getByName("145.100.185.16"));
- mCellNetworkAgent.sendLinkProperties(lp4);
- cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- cellNetworkCallback.assertNoCallback();
- assertFalse(cbi.getLp().isPrivateDnsActive());
- assertNull(cbi.getLp().getPrivateDnsServerName());
- dnsServers.remove(InetAddress.getByName("145.100.185.16"));
- checkDnsServers(cbi.getLp(), dnsServers);
- assertEquals(1300, cbi.getLp().getMtu());
- }
-
- private void checkDirectlyConnectedRoutes(Object callbackObj,
- Collection<LinkAddress> linkAddresses, Collection<RouteInfo> otherRoutes) {
- assertTrue(callbackObj instanceof LinkProperties);
- LinkProperties lp = (LinkProperties) callbackObj;
-
- Set<RouteInfo> expectedRoutes = new ArraySet<>();
- expectedRoutes.addAll(otherRoutes);
- for (LinkAddress address : linkAddresses) {
- RouteInfo localRoute = new RouteInfo(address, null, lp.getInterfaceName());
- // Duplicates in linkAddresses are considered failures
- assertTrue(expectedRoutes.add(localRoute));
- }
- List<RouteInfo> observedRoutes = lp.getRoutes();
- assertEquals(expectedRoutes.size(), observedRoutes.size());
- assertTrue(observedRoutes.containsAll(expectedRoutes));
- }
-
- private static void checkDnsServers(Object callbackObj, Set<InetAddress> dnsServers) {
- assertTrue(callbackObj instanceof LinkProperties);
- LinkProperties lp = (LinkProperties) callbackObj;
- assertEquals(dnsServers.size(), lp.getDnsServers().size());
- assertTrue(lp.getDnsServers().containsAll(dnsServers));
- }
-
- @Test
- public void testApplyUnderlyingCapabilities() throws Exception {
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mCellNetworkAgent.connect(false /* validated */);
- mWiFiNetworkAgent.connect(false /* validated */);
-
- final NetworkCapabilities cellNc = new NetworkCapabilities()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_CONGESTED)
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
- .setLinkDownstreamBandwidthKbps(10);
- final NetworkCapabilities wifiNc = new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_METERED)
- .addCapability(NET_CAPABILITY_NOT_ROAMING)
- .addCapability(NET_CAPABILITY_NOT_CONGESTED)
- .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
- .setLinkUpstreamBandwidthKbps(20);
- mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */);
- mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */);
- waitForIdle();
-
- final Network mobile = mCellNetworkAgent.getNetwork();
- final Network wifi = mWiFiNetworkAgent.getNetwork();
-
- final NetworkCapabilities initialCaps = new NetworkCapabilities();
- initialCaps.addTransportType(TRANSPORT_VPN);
- initialCaps.addCapability(NET_CAPABILITY_INTERNET);
- initialCaps.removeCapability(NET_CAPABILITY_NOT_VPN);
-
- final NetworkCapabilities withNoUnderlying = new NetworkCapabilities();
- withNoUnderlying.addCapability(NET_CAPABILITY_INTERNET);
- withNoUnderlying.addCapability(NET_CAPABILITY_NOT_CONGESTED);
- withNoUnderlying.addCapability(NET_CAPABILITY_NOT_ROAMING);
- withNoUnderlying.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- withNoUnderlying.addTransportType(TRANSPORT_VPN);
- withNoUnderlying.removeCapability(NET_CAPABILITY_NOT_VPN);
-
- final NetworkCapabilities withMobileUnderlying = new NetworkCapabilities(withNoUnderlying);
- withMobileUnderlying.addTransportType(TRANSPORT_CELLULAR);
- withMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_ROAMING);
- withMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
- withMobileUnderlying.setLinkDownstreamBandwidthKbps(10);
-
- final NetworkCapabilities withWifiUnderlying = new NetworkCapabilities(withNoUnderlying);
- withWifiUnderlying.addTransportType(TRANSPORT_WIFI);
- withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED);
- withWifiUnderlying.setLinkUpstreamBandwidthKbps(20);
-
- final NetworkCapabilities withWifiAndMobileUnderlying =
- new NetworkCapabilities(withNoUnderlying);
- withWifiAndMobileUnderlying.addTransportType(TRANSPORT_CELLULAR);
- withWifiAndMobileUnderlying.addTransportType(TRANSPORT_WIFI);
- withWifiAndMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED);
- withWifiAndMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_ROAMING);
- withWifiAndMobileUnderlying.setLinkDownstreamBandwidthKbps(10);
- withWifiAndMobileUnderlying.setLinkUpstreamBandwidthKbps(20);
-
- final NetworkCapabilities initialCapsNotMetered = new NetworkCapabilities(initialCaps);
- initialCapsNotMetered.addCapability(NET_CAPABILITY_NOT_METERED);
-
- NetworkCapabilities caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{}, initialCapsNotMetered, caps);
- assertEquals(withNoUnderlying, caps);
-
- caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{null}, initialCapsNotMetered, caps);
- assertEquals(withNoUnderlying, caps);
-
- caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{mobile}, initialCapsNotMetered, caps);
- assertEquals(withMobileUnderlying, caps);
-
- mService.applyUnderlyingCapabilities(new Network[]{wifi}, initialCapsNotMetered, caps);
- assertEquals(withWifiUnderlying, caps);
-
- withWifiUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED);
- caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{wifi}, initialCaps, caps);
- assertEquals(withWifiUnderlying, caps);
-
- caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{mobile, wifi}, initialCaps, caps);
- assertEquals(withWifiAndMobileUnderlying, caps);
-
- withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED);
- caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
- initialCapsNotMetered, caps);
- assertEquals(withWifiAndMobileUnderlying, caps);
-
- caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
- initialCapsNotMetered, caps);
- assertEquals(withWifiAndMobileUnderlying, caps);
-
- mService.applyUnderlyingCapabilities(null, initialCapsNotMetered, caps);
- assertEquals(withWifiUnderlying, caps);
- }
-
- @Test
- public void testVpnConnectDisconnectUnderlyingNetwork() throws Exception {
- final TestNetworkCallback callback = new TestNetworkCallback();
- final NetworkRequest request = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN).build();
-
- mCm.registerNetworkCallback(request, callback);
-
- // Bring up a VPN that specifies an underlying network that does not exist yet.
- // Note: it's sort of meaningless for a VPN app to declare a network that doesn't exist yet,
- // (and doing so is difficult without using reflection) but it's good to test that the code
- // behaves approximately correctly.
- mMockVpn.establishForMyUid(false, true, false);
- assertUidRangesUpdatedForMyUid(true);
- final Network wifiNetwork = new Network(mNetIdManager.peekNextNetId());
- mMockVpn.setUnderlyingNetworks(new Network[]{wifiNetwork});
- callback.expectAvailableCallbacksUnvalidated(mMockVpn);
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasTransport(TRANSPORT_VPN));
- assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasTransport(TRANSPORT_WIFI));
-
- // Make that underlying network connect, and expect to see its capabilities immediately
- // reflected in the VPN's capabilities.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- assertEquals(wifiNetwork, mWiFiNetworkAgent.getNetwork());
- mWiFiNetworkAgent.connect(false);
- // TODO: the callback for the VPN happens before any callbacks are called for the wifi
- // network that has just connected. There appear to be two issues here:
- // 1. The VPN code will accept an underlying network as soon as getNetworkCapabilities() for
- // it returns non-null (which happens very early, during handleRegisterNetworkAgent).
- // This is not correct because that that point the network is not connected and cannot
- // pass any traffic.
- // 2. When a network connects, updateNetworkInfo propagates underlying network capabilities
- // before rematching networks.
- // Given that this scenario can't really happen, this is probably fine for now.
- callback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasTransport(TRANSPORT_VPN));
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasTransport(TRANSPORT_WIFI));
-
- // Disconnect the network, and expect to see the VPN capabilities change accordingly.
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- callback.expectCapabilitiesThat(mMockVpn, (nc) ->
- nc.getTransportTypes().length == 1 && nc.hasTransport(TRANSPORT_VPN));
-
- mMockVpn.disconnect();
- mCm.unregisterNetworkCallback(callback);
- }
-
- private void assertGetNetworkInfoOfGetActiveNetworkIsConnected(boolean expectedConnectivity) {
- // What Chromium used to do before https://chromium-review.googlesource.com/2605304
- assertEquals("Unexpected result for getActiveNetworkInfo(getActiveNetwork())",
- expectedConnectivity, mCm.getNetworkInfo(mCm.getActiveNetwork()).isConnected());
- }
-
- @Test
- public void testVpnUnderlyingNetworkSuspended() throws Exception {
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(callback);
-
- // Connect a VPN.
- mMockVpn.establishForMyUid(false /* validated */, true /* hasInternet */,
- false /* isStrictMode */);
- callback.expectAvailableCallbacksUnvalidated(mMockVpn);
-
- // Connect cellular data.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false /* validated */);
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- callback.assertNoCallback();
-
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
-
- // Suspend the cellular network and expect the VPN to be suspended.
- mCellNetworkAgent.suspend();
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- callback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
- callback.assertNoCallback();
-
- assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
- // VPN's main underlying network is suspended, so no connectivity.
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
-
- // Switch to another network. The VPN should no longer be suspended.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false /* validated */);
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_WIFI));
- callback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
- callback.assertNoCallback();
-
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
-
- // Unsuspend cellular and then switch back to it. The VPN remains not suspended.
- mCellNetworkAgent.resume();
- callback.assertNoCallback();
- mWiFiNetworkAgent.disconnect();
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- // Spurious double callback?
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- callback.assertNoCallback();
-
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
-
- // Suspend cellular and expect no connectivity.
- mCellNetworkAgent.suspend();
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- callback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
- callback.assertNoCallback();
-
- assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED);
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(false);
-
- // Resume cellular and expect that connectivity comes back.
- mCellNetworkAgent.resume();
- callback.expectCapabilitiesThat(mMockVpn,
- nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED)
- && nc.hasTransport(TRANSPORT_CELLULAR));
- callback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
- callback.assertNoCallback();
-
- assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
- .hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertGetNetworkInfoOfGetActiveNetworkIsConnected(true);
- }
-
- @Test
- public void testVpnNetworkActive() throws Exception {
- // NETWORK_SETTINGS is necessary to call registerSystemDefaultNetworkCallback.
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final int uid = Process.myUid();
-
- final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback genericNotVpnNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
- final NetworkRequest genericNotVpnRequest = new NetworkRequest.Builder().build();
- final NetworkRequest genericRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN).build();
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .addTransportType(TRANSPORT_VPN).build();
- mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
- mCm.registerNetworkCallback(genericNotVpnRequest, genericNotVpnNetworkCallback);
- mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
- mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
- mCm.registerDefaultNetworkCallback(defaultCallback);
- mCm.registerSystemDefaultNetworkCallback(systemDefaultCallback,
- new Handler(ConnectivityThread.getInstanceLooper()));
- defaultCallback.assertNoCallback();
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false);
-
- genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- genericNotVpnNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- systemDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- vpnNetworkCallback.assertNoCallback();
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- final Set<UidRange> ranges = uidRangesForUids(uid);
- mMockVpn.registerAgent(ranges);
- mMockVpn.setUnderlyingNetworks(new Network[0]);
-
- // VPN networks do not satisfy the default request and are automatically validated
- // by NetworkMonitor
- assertFalse(NetworkMonitorUtils.isValidationRequired(
- mMockVpn.getAgent().getNetworkCapabilities()));
- mMockVpn.getAgent().setNetworkValid(false /* isStrictMode */);
-
- mMockVpn.connect(false);
-
- genericNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- genericNotVpnNetworkCallback.assertNoCallback();
- wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- systemDefaultCallback.assertNoCallback();
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- assertEquals(mWiFiNetworkAgent.getNetwork(),
- systemDefaultCallback.getLastAvailableNetwork());
-
- ranges.clear();
- mMockVpn.setUids(ranges);
-
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- genericNotVpnNetworkCallback.assertNoCallback();
- wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
-
- // TODO : The default network callback should actually get a LOST call here (also see the
- // comment below for AVAILABLE). This is because ConnectivityService does not look at UID
- // ranges at all when determining whether a network should be rematched. In practice, VPNs
- // can't currently update their UIDs without disconnecting, so this does not matter too
- // much, but that is the reason the test here has to check for an update to the
- // capabilities instead of the expected LOST then AVAILABLE.
- defaultCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
- systemDefaultCallback.assertNoCallback();
-
- ranges.add(new UidRange(uid, uid));
- mMockVpn.setUids(ranges);
-
- genericNetworkCallback.expectAvailableCallbacksValidated(mMockVpn);
- genericNotVpnNetworkCallback.assertNoCallback();
- wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectAvailableCallbacksValidated(mMockVpn);
- // TODO : Here like above, AVAILABLE would be correct, but because this can't actually
- // happen outside of the test, ConnectivityService does not rematch callbacks.
- defaultCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
- systemDefaultCallback.assertNoCallback();
-
- mWiFiNetworkAgent.disconnect();
-
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- genericNotVpnNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- vpnNetworkCallback.assertNoCallback();
- defaultCallback.assertNoCallback();
- systemDefaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-
- mMockVpn.disconnect();
-
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- genericNotVpnNetworkCallback.assertNoCallback();
- wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- systemDefaultCallback.assertNoCallback();
- assertEquals(null, mCm.getActiveNetwork());
-
- mCm.unregisterNetworkCallback(genericNetworkCallback);
- mCm.unregisterNetworkCallback(wifiNetworkCallback);
- mCm.unregisterNetworkCallback(vpnNetworkCallback);
- mCm.unregisterNetworkCallback(defaultCallback);
- mCm.unregisterNetworkCallback(systemDefaultCallback);
- }
-
- @Test
- public void testVpnWithoutInternet() throws Exception {
- final int uid = Process.myUid();
-
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
-
- defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */,
- false /* isStrictMode */);
- assertUidRangesUpdatedForMyUid(true);
-
- defaultCallback.assertNoCallback();
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mMockVpn.disconnect();
- defaultCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(defaultCallback);
- }
-
- @Test
- public void testVpnWithInternet() throws Exception {
- final int uid = Process.myUid();
-
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
-
- defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mMockVpn.establishForMyUid(true /* validated */, true /* hasInternet */,
- false /* isStrictMode */);
- assertUidRangesUpdatedForMyUid(true);
-
- defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- mMockVpn.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
-
- mCm.unregisterNetworkCallback(defaultCallback);
- }
-
- @Test
- public void testVpnUnvalidated() throws Exception {
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(callback);
-
- // Bring up Ethernet.
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
- mEthernetNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
- callback.assertNoCallback();
-
- // Bring up a VPN that has the INTERNET capability, initially unvalidated.
- mMockVpn.establishForMyUid(false /* validated */, true /* hasInternet */,
- false /* isStrictMode */);
- assertUidRangesUpdatedForMyUid(true);
-
- // Even though the VPN is unvalidated, it becomes the default network for our app.
- callback.expectAvailableCallbacksUnvalidated(mMockVpn);
- callback.assertNoCallback();
-
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
-
- NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED));
- assertTrue(nc.hasCapability(NET_CAPABILITY_INTERNET));
-
- assertFalse(NetworkMonitorUtils.isValidationRequired(
- mMockVpn.getAgent().getNetworkCapabilities()));
- assertTrue(NetworkMonitorUtils.isPrivateDnsValidationRequired(
- mMockVpn.getAgent().getNetworkCapabilities()));
-
- // Pretend that the VPN network validates.
- mMockVpn.getAgent().setNetworkValid(false /* isStrictMode */);
- mMockVpn.getAgent().mNetworkMonitor.forceReevaluation(Process.myUid());
- // Expect to see the validated capability, but no other changes, because the VPN is already
- // the default network for the app.
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mMockVpn);
- callback.assertNoCallback();
-
- mMockVpn.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mMockVpn);
- callback.expectAvailableCallbacksValidated(mEthernetNetworkAgent);
- }
-
- @Test
- public void testVpnStartsWithUnderlyingCaps() throws Exception {
- final int uid = Process.myUid();
-
- final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
- final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .addTransportType(TRANSPORT_VPN)
- .build();
- mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
- vpnNetworkCallback.assertNoCallback();
-
- // Connect cell. It will become the default network, and in the absence of setting
- // underlying networks explicitly it will become the sole underlying network for the vpn.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- mCellNetworkAgent.connect(true);
-
- mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */,
- false /* isStrictMode */);
- assertUidRangesUpdatedForMyUid(true);
-
- vpnNetworkCallback.expectAvailableCallbacks(mMockVpn.getNetwork(),
- false /* suspended */, false /* validated */, false /* blocked */, TIMEOUT_MS);
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn.getNetwork(), TIMEOUT_MS,
- nc -> nc.hasCapability(NET_CAPABILITY_VALIDATED));
-
- final NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- assertTrue(nc.hasTransport(TRANSPORT_VPN));
- assertTrue(nc.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(nc.hasTransport(TRANSPORT_WIFI));
- assertTrue(nc.hasCapability(NET_CAPABILITY_VALIDATED));
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
- }
-
- private void assertDefaultNetworkCapabilities(int userId, NetworkAgentWrapper... networks) {
- final NetworkCapabilities[] defaultCaps = mService.getDefaultNetworkCapabilitiesForUser(
- userId, "com.android.calling.package", "com.test");
- final String defaultCapsString = Arrays.toString(defaultCaps);
- assertEquals(defaultCapsString, defaultCaps.length, networks.length);
- final Set<NetworkCapabilities> defaultCapsSet = new ArraySet<>(defaultCaps);
- for (NetworkAgentWrapper network : networks) {
- final NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
- final String msg = "Did not find " + nc + " in " + Arrays.toString(defaultCaps);
- assertTrue(msg, defaultCapsSet.contains(nc));
- }
- }
-
- @Test
- public void testVpnSetUnderlyingNetworks() throws Exception {
- final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
- final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .addTransportType(TRANSPORT_VPN)
- .build();
- NetworkCapabilities nc;
- mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
- vpnNetworkCallback.assertNoCallback();
-
- mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */,
- false /* isStrictMode */);
- assertUidRangesUpdatedForMyUid(true);
-
- vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- assertTrue(nc.hasTransport(TRANSPORT_VPN));
- assertFalse(nc.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(nc.hasTransport(TRANSPORT_WIFI));
- // For safety reasons a VPN without underlying networks is considered metered.
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
- // A VPN without underlying networks is not suspended.
- assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
-
- final int userId = UserHandle.getUserId(Process.myUid());
- assertDefaultNetworkCapabilities(userId /* no networks */);
-
- // Connect cell and use it as an underlying network.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- mCellNetworkAgent.connect(true);
-
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mCellNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- mWiFiNetworkAgent.connect(true);
-
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
-
- // Don't disconnect, but note the VPN is not using wifi any more.
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mCellNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- // The return value of getDefaultNetworkCapabilitiesForUser always includes the default
- // network (wifi) as well as the underlying networks (cell).
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
-
- // Remove NOT_SUSPENDED from the only network and observe VPN is now suspended.
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && !caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- vpnNetworkCallback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
-
- // Add NOT_SUSPENDED again and observe VPN is no longer suspended.
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- vpnNetworkCallback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
-
- // Use Wifi but not cell. Note the VPN is now unmetered and not suspended.
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mWiFiNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertDefaultNetworkCapabilities(userId, mWiFiNetworkAgent);
-
- // Use both again.
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
-
- // Cell is suspended again. As WiFi is not, this should not cause a callback.
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
- vpnNetworkCallback.assertNoCallback();
-
- // Stop using WiFi. The VPN is suspended again.
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mCellNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && !caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- vpnNetworkCallback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
-
- // Use both again.
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
- && caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- vpnNetworkCallback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
-
- // Disconnect cell. Receive update without even removing the dead network from the
- // underlying networks – it's dead anyway. Not metered any more.
- mCellNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertDefaultNetworkCapabilities(userId, mWiFiNetworkAgent);
-
- // Disconnect wifi too. No underlying networks means this is now metered.
- mWiFiNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- // When a network disconnects, the callbacks are fired before all state is updated, so for a
- // short time, synchronous calls will behave as if the network is still connected. Wait for
- // things to settle.
- waitForIdle();
- assertDefaultNetworkCapabilities(userId /* no networks */);
-
- mMockVpn.disconnect();
- }
-
- @Test
- public void testNullUnderlyingNetworks() throws Exception {
- final int uid = Process.myUid();
-
- final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
- final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .addTransportType(TRANSPORT_VPN)
- .build();
- NetworkCapabilities nc;
- mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
- vpnNetworkCallback.assertNoCallback();
-
- mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */,
- false /* isStrictMode */);
- assertUidRangesUpdatedForMyUid(true);
-
- vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- assertTrue(nc.hasTransport(TRANSPORT_VPN));
- assertFalse(nc.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(nc.hasTransport(TRANSPORT_WIFI));
- // By default, VPN is set to track default network (i.e. its underlying networks is null).
- // In case of no default network, VPN is considered metered.
- assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
-
- // Connect to Cell; Cell is the default network.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
-
- // Connect to WiFi; WiFi is the new default.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED));
-
- // Disconnect Cell. The default network did not change, so there shouldn't be any changes in
- // the capabilities.
- mCellNetworkAgent.disconnect();
-
- // Disconnect wifi too. Now we have no default network.
- mWiFiNetworkAgent.disconnect();
-
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
- (caps) -> caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
-
- mMockVpn.disconnect();
- }
-
- @Test
- public void testRestrictedProfileAffectsVpnUidRanges() throws Exception {
- // NETWORK_SETTINGS is necessary to see the UID ranges in NetworkCapabilities.
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final NetworkRequest request = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- // Bring up a VPN
- mMockVpn.establishForMyUid();
- assertUidRangesUpdatedForMyUid(true);
- callback.expectAvailableThenValidatedCallbacks(mMockVpn);
- callback.assertNoCallback();
-
- final int uid = Process.myUid();
- NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- assertNotNull("nc=" + nc, nc.getUids());
- assertEquals(nc.getUids(), UidRange.toIntRanges(uidRangesForUids(uid)));
- assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
-
- // Set an underlying network and expect to see the VPN transports change.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCapabilitiesThat(mMockVpn, (caps)
- -> caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_WIFI));
- callback.expectCapabilitiesThat(mWiFiNetworkAgent, (caps)
- -> caps.hasCapability(NET_CAPABILITY_VALIDATED));
-
- when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER))
- .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID));
-
- final Intent addedIntent = new Intent(ACTION_USER_ADDED);
- addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
- addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
-
- // Send a USER_ADDED broadcast for it.
- processBroadcast(addedIntent);
-
- // Expect that the VPN UID ranges contain both |uid| and the UID range for the newly-added
- // restricted user.
- final UidRange rRange = UidRange.createForUser(UserHandle.of(RESTRICTED_USER));
- final Range<Integer> restrictUidRange = new Range<Integer>(rRange.start, rRange.stop);
- final Range<Integer> singleUidRange = new Range<Integer>(uid, uid);
- callback.expectCapabilitiesThat(mMockVpn, (caps)
- -> caps.getUids().size() == 2
- && caps.getUids().contains(singleUidRange)
- && caps.getUids().contains(restrictUidRange)
- && caps.hasTransport(TRANSPORT_VPN)
- && caps.hasTransport(TRANSPORT_WIFI));
-
- // Change the VPN's capabilities somehow (specifically, disconnect wifi).
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- callback.expectCapabilitiesThat(mMockVpn, (caps)
- -> caps.getUids().size() == 2
- && caps.getUids().contains(singleUidRange)
- && caps.getUids().contains(restrictUidRange)
- && caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_WIFI));
-
- // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
- final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
- removedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
- removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
- processBroadcast(removedIntent);
-
- // Expect that the VPN gains the UID range for the restricted user, and that the capability
- // change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved.
- callback.expectCapabilitiesThat(mMockVpn, (caps)
- -> caps.getUids().size() == 1
- && caps.getUids().contains(singleUidRange)
- && caps.hasTransport(TRANSPORT_VPN)
- && !caps.hasTransport(TRANSPORT_WIFI));
- }
-
- @Test
- public void testLockdownVpnWithRestrictedProfiles() throws Exception {
- // For ConnectivityService#setAlwaysOnVpnPackage.
- mServiceContext.setPermission(
- Manifest.permission.CONTROL_ALWAYS_ON_VPN, PERMISSION_GRANTED);
- // For call Vpn#setAlwaysOnPackage.
- mServiceContext.setPermission(
- Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
- // Necessary to see the UID ranges in NetworkCapabilities.
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final NetworkRequest request = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- final int uid = Process.myUid();
-
- // Connect wifi and check that UIDs in the main and restricted profiles have network access.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true /* validated */);
- final int restrictedUid = UserHandle.getUid(RESTRICTED_USER, 42 /* appId */);
- assertNotNull(mCm.getActiveNetworkForUid(uid));
- assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
-
- // Enable always-on VPN lockdown. The main user loses network access because no VPN is up.
- final ArrayList<String> allowList = new ArrayList<>();
- mVpnManagerService.setAlwaysOnVpnPackage(PRIMARY_USER, ALWAYS_ON_PACKAGE,
- true /* lockdown */, allowList);
- waitForIdle();
- assertNull(mCm.getActiveNetworkForUid(uid));
- // This is arguably overspecified: a UID that is not running doesn't have an active network.
- // But it's useful to check that non-default users do not lose network access, and to prove
- // that the loss of connectivity below is indeed due to the restricted profile coming up.
- assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
-
- // Start the restricted profile, and check that the UID within it loses network access.
- when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER))
- .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID));
- when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO,
- RESTRICTED_USER_INFO));
- // TODO: check that VPN app within restricted profile still has access, etc.
- final Intent addedIntent = new Intent(ACTION_USER_ADDED);
- addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
- addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
- processBroadcast(addedIntent);
- assertNull(mCm.getActiveNetworkForUid(uid));
- assertNull(mCm.getActiveNetworkForUid(restrictedUid));
-
- // Stop the restricted profile, and check that the UID within it has network access again.
- when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO));
-
- // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
- final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
- removedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(RESTRICTED_USER));
- removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
- processBroadcast(removedIntent);
- assertNull(mCm.getActiveNetworkForUid(uid));
- assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
-
- mVpnManagerService.setAlwaysOnVpnPackage(PRIMARY_USER, null, false /* lockdown */,
- allowList);
- waitForIdle();
- }
-
- @Test
- public void testIsActiveNetworkMeteredOverWifi() throws Exception {
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
-
- assertFalse(mCm.isActiveNetworkMetered());
- }
-
- @Test
- public void testIsActiveNetworkMeteredOverCell() throws Exception {
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- mCellNetworkAgent.connect(true);
- waitForIdle();
-
- assertTrue(mCm.isActiveNetworkMetered());
- }
-
- @Test
- public void testIsActiveNetworkMeteredOverVpnTrackingPlatformDefault() throws Exception {
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- mCellNetworkAgent.connect(true);
- waitForIdle();
- assertTrue(mCm.isActiveNetworkMetered());
-
- // Connect VPN network. By default it is using current default network (Cell).
- mMockVpn.establishForMyUid();
- assertUidRangesUpdatedForMyUid(true);
-
- // Ensure VPN is now the active network.
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
-
- // Expect VPN to be metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // Connect WiFi.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- // VPN should still be the active network.
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
-
- // Expect VPN to be unmetered as it should now be using WiFi (new default).
- assertFalse(mCm.isActiveNetworkMetered());
-
- // Disconnecting Cell should not affect VPN's meteredness.
- mCellNetworkAgent.disconnect();
- waitForIdle();
-
- assertFalse(mCm.isActiveNetworkMetered());
-
- // Disconnect WiFi; Now there is no platform default network.
- mWiFiNetworkAgent.disconnect();
- waitForIdle();
-
- // VPN without any underlying networks is treated as metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- mMockVpn.disconnect();
- }
-
- @Test
- public void testIsActiveNetworkMeteredOverVpnSpecifyingUnderlyingNetworks() throws Exception {
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- mCellNetworkAgent.connect(true);
- waitForIdle();
- assertTrue(mCm.isActiveNetworkMetered());
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- assertFalse(mCm.isActiveNetworkMetered());
-
- // Connect VPN network.
- mMockVpn.establishForMyUid();
- assertUidRangesUpdatedForMyUid(true);
-
- // Ensure VPN is now the active network.
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
- // VPN is using Cell
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mCellNetworkAgent.getNetwork() });
- waitForIdle();
-
- // Expect VPN to be metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // VPN is now using WiFi
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mWiFiNetworkAgent.getNetwork() });
- waitForIdle();
-
- // Expect VPN to be unmetered
- assertFalse(mCm.isActiveNetworkMetered());
-
- // VPN is using Cell | WiFi.
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
- waitForIdle();
-
- // Expect VPN to be metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // VPN is using WiFi | Cell.
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mWiFiNetworkAgent.getNetwork(), mCellNetworkAgent.getNetwork() });
- waitForIdle();
-
- // Order should not matter and VPN should still be metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // VPN is not using any underlying networks.
- mMockVpn.setUnderlyingNetworks(new Network[0]);
- waitForIdle();
-
- // VPN without underlying networks is treated as metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
- mMockVpn.disconnect();
- }
-
- @Test
- public void testIsActiveNetworkMeteredOverAlwaysMeteredVpn() throws Exception {
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- assertFalse(mCm.isActiveNetworkMetered());
-
- // Connect VPN network.
- mMockVpn.registerAgent(true /* isAlwaysMetered */, uidRangesForUids(Process.myUid()),
- new LinkProperties());
- mMockVpn.connect(true);
- waitForIdle();
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
-
- // VPN is tracking current platform default (WiFi).
- mMockVpn.setUnderlyingNetworks(null);
- waitForIdle();
-
- // Despite VPN using WiFi (which is unmetered), VPN itself is marked as always metered.
- assertTrue(mCm.isActiveNetworkMetered());
-
-
- // VPN explicitly declares WiFi as its underlying network.
- mMockVpn.setUnderlyingNetworks(
- new Network[] { mWiFiNetworkAgent.getNetwork() });
- waitForIdle();
-
- // Doesn't really matter whether VPN declares its underlying networks explicitly.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // With WiFi lost, VPN is basically without any underlying networks. And in that case it is
- // anyways suppose to be metered.
- mWiFiNetworkAgent.disconnect();
- waitForIdle();
-
- assertTrue(mCm.isActiveNetworkMetered());
-
- mMockVpn.disconnect();
- }
-
- private class DetailedBlockedStatusCallback extends TestNetworkCallback {
- public void expectAvailableThenValidatedCallbacks(HasNetwork n, int blockedStatus) {
- super.expectAvailableThenValidatedCallbacks(n.getNetwork(), blockedStatus, TIMEOUT_MS);
- }
- public void expectBlockedStatusCallback(HasNetwork n, int blockedStatus) {
- // This doesn't work:
- // super.expectBlockedStatusCallback(blockedStatus, n.getNetwork());
- super.expectBlockedStatusCallback(blockedStatus, n.getNetwork(), TIMEOUT_MS);
- }
- public void onBlockedStatusChanged(Network network, int blockedReasons) {
- getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons));
- }
- }
-
- @Test
- public void testNetworkBlockedStatus() throws Exception {
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .build();
- mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
- final DetailedBlockedStatusCallback detailedCallback = new DetailedBlockedStatusCallback();
- mCm.registerNetworkCallback(cellRequest, detailedCallback);
-
- mockUidNetworkingBlocked();
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- detailedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent,
- BLOCKED_REASON_NONE);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mCellNetworkAgent);
-
- setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER);
- cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
- BLOCKED_REASON_BATTERY_SAVER);
- assertNull(mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertExtraInfoFromCmBlocked(mCellNetworkAgent);
-
- // If blocked state does not change but blocked reason does, the boolean callback is called.
- // TODO: investigate de-duplicating.
- setBlockedReasonChanged(BLOCKED_METERED_REASON_USER_RESTRICTED);
- cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
- BLOCKED_METERED_REASON_USER_RESTRICTED);
-
- setBlockedReasonChanged(BLOCKED_REASON_NONE);
- cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mCellNetworkAgent);
-
- setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
- cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
- BLOCKED_METERED_REASON_DATA_SAVER);
- assertNull(mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertExtraInfoFromCmBlocked(mCellNetworkAgent);
-
- // Restrict the network based on UID rule and NOT_METERED capability change.
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
- cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
- detailedCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mCellNetworkAgent);
-
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
- mCellNetworkAgent);
- cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
- detailedCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
- mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
- BLOCKED_METERED_REASON_DATA_SAVER);
- assertNull(mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertExtraInfoFromCmBlocked(mCellNetworkAgent);
-
- setBlockedReasonChanged(BLOCKED_REASON_NONE);
- cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mCellNetworkAgent);
-
- setBlockedReasonChanged(BLOCKED_REASON_NONE);
- cellNetworkCallback.assertNoCallback();
- detailedCallback.assertNoCallback();
-
- // Restrict background data. Networking is not blocked because the network is unmetered.
- setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
- cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
- BLOCKED_METERED_REASON_DATA_SAVER);
- assertNull(mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertExtraInfoFromCmBlocked(mCellNetworkAgent);
- setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
- cellNetworkCallback.assertNoCallback();
-
- setBlockedReasonChanged(BLOCKED_REASON_NONE);
- cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
- detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mCellNetworkAgent);
-
- setBlockedReasonChanged(BLOCKED_REASON_NONE);
- cellNetworkCallback.assertNoCallback();
- detailedCallback.assertNoCallback();
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mCellNetworkAgent);
-
- mCm.unregisterNetworkCallback(cellNetworkCallback);
- }
-
- @Test
- public void testNetworkBlockedStatusBeforeAndAfterConnect() throws Exception {
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
- mockUidNetworkingBlocked();
-
- // No Networkcallbacks invoked before any network is active.
- setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER);
- setBlockedReasonChanged(BLOCKED_REASON_NONE);
- setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
- defaultCallback.assertNoCallback();
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
- defaultCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mCellNetworkAgent);
-
- // Allow to use the network after switching to NOT_METERED network.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
-
- // Switch to METERED network. Restrict the use of the network.
- mWiFiNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksValidatedAndBlocked(mCellNetworkAgent);
-
- // Network becomes NOT_METERED.
- mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- defaultCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
- defaultCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
-
- // Verify there's no Networkcallbacks invoked after data saver on/off.
- setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
- setBlockedReasonChanged(BLOCKED_REASON_NONE);
- defaultCallback.assertNoCallback();
-
- mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(defaultCallback);
- }
-
- private void expectNetworkRejectNonSecureVpn(InOrder inOrder, boolean add,
- UidRangeParcel... expected) throws Exception {
- inOrder.verify(mMockNetd).networkRejectNonSecureVpn(eq(add), aryEq(expected));
- }
-
- private void checkNetworkInfo(NetworkInfo ni, int type, DetailedState state) {
- assertNotNull(ni);
- assertEquals(type, ni.getType());
- assertEquals(ConnectivityManager.getNetworkTypeName(type), state, ni.getDetailedState());
- if (state == DetailedState.CONNECTED || state == DetailedState.SUSPENDED) {
- assertNotNull(ni.getExtraInfo());
- } else {
- // Technically speaking, a network that's in CONNECTING state will generally have a
- // non-null extraInfo. This doesn't actually happen in this test because it never calls
- // a legacy API while a network is connecting. When a network is in CONNECTING state
- // because of legacy lockdown VPN, its extraInfo is always null.
- assertNull(ni.getExtraInfo());
- }
- }
-
- private void assertActiveNetworkInfo(int type, DetailedState state) {
- checkNetworkInfo(mCm.getActiveNetworkInfo(), type, state);
- }
- private void assertNetworkInfo(int type, DetailedState state) {
- checkNetworkInfo(mCm.getNetworkInfo(type), type, state);
- }
-
- private void assertExtraInfoFromCm(TestNetworkAgentWrapper network, boolean present) {
- final NetworkInfo niForNetwork = mCm.getNetworkInfo(network.getNetwork());
- final NetworkInfo niForType = mCm.getNetworkInfo(network.getLegacyType());
- if (present) {
- assertEquals(network.getExtraInfo(), niForNetwork.getExtraInfo());
- assertEquals(network.getExtraInfo(), niForType.getExtraInfo());
- } else {
- assertNull(niForNetwork.getExtraInfo());
- assertNull(niForType.getExtraInfo());
- }
- }
-
- private void assertExtraInfoFromCmBlocked(TestNetworkAgentWrapper network) {
- assertExtraInfoFromCm(network, false);
- }
-
- private void assertExtraInfoFromCmPresent(TestNetworkAgentWrapper network) {
- assertExtraInfoFromCm(network, true);
- }
-
- // Checks that each of the |agents| receive a blocked status change callback with the specified
- // |blocked| value, in any order. This is needed because when an event affects multiple
- // networks, ConnectivityService does not guarantee the order in which callbacks are fired.
- private void assertBlockedCallbackInAnyOrder(TestNetworkCallback callback, boolean blocked,
- TestNetworkAgentWrapper... agents) {
- final List<Network> expectedNetworks = Arrays.asList(agents).stream()
- .map((agent) -> agent.getNetwork())
- .collect(Collectors.toList());
-
- // Expect exactly one blocked callback for each agent.
- for (int i = 0; i < agents.length; i++) {
- CallbackEntry e = callback.expectCallbackThat(TIMEOUT_MS, (c) ->
- c instanceof CallbackEntry.BlockedStatus
- && ((CallbackEntry.BlockedStatus) c).getBlocked() == blocked);
- Network network = e.getNetwork();
- assertTrue("Received unexpected blocked callback for network " + network,
- expectedNetworks.remove(network));
- }
- }
-
- @Test
- public void testNetworkBlockedStatusAlwaysOnVpn() throws Exception {
- mServiceContext.setPermission(
- Manifest.permission.CONTROL_ALWAYS_ON_VPN, PERMISSION_GRANTED);
- mServiceContext.setPermission(
- Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final TestNetworkCallback callback = new TestNetworkCallback();
- final NetworkRequest request = new NetworkRequest.Builder()
- .removeCapability(NET_CAPABILITY_NOT_VPN)
- .build();
- mCm.registerNetworkCallback(request, callback);
-
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- final TestNetworkCallback vpnUidCallback = new TestNetworkCallback();
- final NetworkRequest vpnUidRequest = new NetworkRequest.Builder().build();
- registerNetworkCallbackAsUid(vpnUidRequest, vpnUidCallback, VPN_UID);
-
- final TestNetworkCallback vpnUidDefaultCallback = new TestNetworkCallback();
- registerDefaultNetworkCallbackAsUid(vpnUidDefaultCallback, VPN_UID);
-
- final TestNetworkCallback vpnDefaultCallbackAsUid = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallbackForUid(VPN_UID, vpnDefaultCallbackAsUid,
- new Handler(ConnectivityThread.getInstanceLooper()));
-
- final int uid = Process.myUid();
- final int userId = UserHandle.getUserId(uid);
- final ArrayList<String> allowList = new ArrayList<>();
- mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
- allowList);
- waitForIdle();
-
- UidRangeParcel firstHalf = new UidRangeParcel(1, VPN_UID - 1);
- UidRangeParcel secondHalf = new UidRangeParcel(VPN_UID + 1, 99999);
- InOrder inOrder = inOrder(mMockNetd);
- expectNetworkRejectNonSecureVpn(inOrder, true, firstHalf, secondHalf);
-
- // Connect a network when lockdown is active, expect to see it blocked.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(false /* validated */);
- callback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
- vpnUidCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- vpnUidDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- vpnDefaultCallbackAsUid.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertNull(mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
- // Mobile is BLOCKED even though it's not actually connected.
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
-
- // Disable lockdown, expect to see the network unblocked.
- mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
- callback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
- defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
- vpnUidCallback.assertNoCallback();
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
- expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-
- // Add our UID to the allowlist and re-enable lockdown, expect network is not blocked.
- allowList.add(TEST_PACKAGE_NAME);
- mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
- allowList);
- callback.assertNoCallback();
- defaultCallback.assertNoCallback();
- vpnUidCallback.assertNoCallback();
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
-
- // The following requires that the UID of this test package is greater than VPN_UID. This
- // is always true in practice because a plain AOSP build with no apps installed has almost
- // 200 packages installed.
- final UidRangeParcel piece1 = new UidRangeParcel(1, VPN_UID - 1);
- final UidRangeParcel piece2 = new UidRangeParcel(VPN_UID + 1, uid - 1);
- final UidRangeParcel piece3 = new UidRangeParcel(uid + 1, 99999);
- expectNetworkRejectNonSecureVpn(inOrder, true, piece1, piece2, piece3);
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-
- // Connect a new network, expect it to be unblocked.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(false /* validated */);
- callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- defaultCallback.assertNoCallback();
- vpnUidCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- // Cellular is DISCONNECTED because it's not the default and there are no requests for it.
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-
- // Disable lockdown, remove our UID from the allowlist, and re-enable lockdown.
- // Everything should now be blocked.
- mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
- waitForIdle();
- expectNetworkRejectNonSecureVpn(inOrder, false, piece1, piece2, piece3);
- allowList.clear();
- mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
- allowList);
- waitForIdle();
- expectNetworkRejectNonSecureVpn(inOrder, true, firstHalf, secondHalf);
- defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
- assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
- vpnUidCallback.assertNoCallback();
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertNull(mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
-
- // Disable lockdown. Everything is unblocked.
- mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
- defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
- assertBlockedCallbackInAnyOrder(callback, false, mWiFiNetworkAgent, mCellNetworkAgent);
- vpnUidCallback.assertNoCallback();
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-
- // Enable and disable an always-on VPN package without lockdown. Expect no changes.
- reset(mMockNetd);
- mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, false /* lockdown */,
- allowList);
- inOrder.verify(mMockNetd, never()).networkRejectNonSecureVpn(anyBoolean(), any());
- callback.assertNoCallback();
- defaultCallback.assertNoCallback();
- vpnUidCallback.assertNoCallback();
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-
- mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
- inOrder.verify(mMockNetd, never()).networkRejectNonSecureVpn(anyBoolean(), any());
- callback.assertNoCallback();
- defaultCallback.assertNoCallback();
- vpnUidCallback.assertNoCallback();
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-
- // Enable lockdown and connect a VPN. The VPN is not blocked.
- mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
- allowList);
- defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
- assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
- vpnUidCallback.assertNoCallback();
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertNull(mCm.getActiveNetwork());
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
-
- mMockVpn.establishForMyUid();
- assertUidRangesUpdatedForMyUid(true);
- defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- vpnUidCallback.assertNoCallback(); // vpnUidCallback has NOT_VPN capability.
- vpnUidDefaultCallback.assertNoCallback(); // VPN does not apply to VPN_UID
- vpnDefaultCallbackAsUid.assertNoCallback();
- assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
-
- mMockVpn.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
- vpnUidCallback.assertNoCallback();
- vpnUidDefaultCallback.assertNoCallback();
- vpnDefaultCallbackAsUid.assertNoCallback();
- assertNull(mCm.getActiveNetwork());
-
- mCm.unregisterNetworkCallback(callback);
- mCm.unregisterNetworkCallback(defaultCallback);
- mCm.unregisterNetworkCallback(vpnUidCallback);
- mCm.unregisterNetworkCallback(vpnUidDefaultCallback);
- mCm.unregisterNetworkCallback(vpnDefaultCallbackAsUid);
- }
-
- private void setupLegacyLockdownVpn() {
- final String profileName = "testVpnProfile";
- final byte[] profileTag = profileName.getBytes(StandardCharsets.UTF_8);
- when(mVpnProfileStore.get(Credentials.LOCKDOWN_VPN)).thenReturn(profileTag);
-
- final VpnProfile profile = new VpnProfile(profileName);
- profile.name = "My VPN";
- profile.server = "192.0.2.1";
- profile.dnsServers = "8.8.8.8";
- profile.type = VpnProfile.TYPE_IPSEC_XAUTH_PSK;
- final byte[] encodedProfile = profile.encode();
- when(mVpnProfileStore.get(Credentials.VPN + profileName)).thenReturn(encodedProfile);
- }
-
- private void establishLegacyLockdownVpn(Network underlying) throws Exception {
- // The legacy lockdown VPN only supports userId 0, and must have an underlying network.
- assertNotNull(underlying);
- mMockVpn.setVpnType(VpnManager.TYPE_VPN_LEGACY);
- // The legacy lockdown VPN only supports userId 0.
- final Set<UidRange> ranges = Collections.singleton(PRIMARY_UIDRANGE);
- mMockVpn.registerAgent(ranges);
- mMockVpn.setUnderlyingNetworks(new Network[]{underlying});
- mMockVpn.connect(true);
- }
-
- @Test
- public void testLegacyLockdownVpn() throws Exception {
- mServiceContext.setPermission(
- Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
- // For LockdownVpnTracker to call registerSystemDefaultNetworkCallback.
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
- mCm.registerSystemDefaultNetworkCallback(systemDefaultCallback,
- new Handler(ConnectivityThread.getInstanceLooper()));
-
- // Pretend lockdown VPN was configured.
- setupLegacyLockdownVpn();
-
- // LockdownVpnTracker disables the Vpn teardown code and enables lockdown.
- // Check the VPN's state before it does so.
- assertTrue(mMockVpn.getEnableTeardown());
- assertFalse(mMockVpn.getLockdown());
-
- // Send a USER_UNLOCKED broadcast so CS starts LockdownVpnTracker.
- final int userId = UserHandle.getUserId(Process.myUid());
- final Intent addedIntent = new Intent(ACTION_USER_UNLOCKED);
- addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
- addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- processBroadcast(addedIntent);
-
- // Lockdown VPN disables teardown and enables lockdown.
- assertFalse(mMockVpn.getEnableTeardown());
- assertTrue(mMockVpn.getLockdown());
-
- // Bring up a network.
- // Expect nothing to happen because the network does not have an IPv4 default route: legacy
- // VPN only supports IPv4.
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName("rmnet0");
- cellLp.addLinkAddress(new LinkAddress("2001:db8::1/64"));
- cellLp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, "rmnet0"));
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
- mCellNetworkAgent.connect(false /* validated */);
- callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
- systemDefaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
- waitForIdle();
- assertNull(mMockVpn.getAgent());
-
- // Add an IPv4 address. Ideally the VPN should start, but it doesn't because nothing calls
- // LockdownVpnTracker#handleStateChangedLocked. This is a bug.
- // TODO: consider fixing this.
- cellLp.addLinkAddress(new LinkAddress("192.0.2.2/25"));
- cellLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "rmnet0"));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- callback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- systemDefaultCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
- mCellNetworkAgent);
- waitForIdle();
- assertNull(mMockVpn.getAgent());
-
- // Disconnect, then try again with a network that supports IPv4 at connection time.
- // Expect lockdown VPN to come up.
- ExpectedBroadcast b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
- mCellNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- systemDefaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- b1.expectBroadcast();
-
- // When lockdown VPN is active, the NetworkInfo state in CONNECTIVITY_ACTION is overwritten
- // with the state of the VPN network. So expect a CONNECTING broadcast.
- b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTING);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
- mCellNetworkAgent.connect(false /* validated */);
- callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
- systemDefaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
- b1.expectBroadcast();
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED);
- assertExtraInfoFromCmBlocked(mCellNetworkAgent);
-
- // TODO: it would be nice if we could simply rely on the production code here, and have
- // LockdownVpnTracker start the VPN, have the VPN code register its NetworkAgent with
- // ConnectivityService, etc. That would require duplicating a fair bit of code from the
- // Vpn tests around how to mock out LegacyVpnRunner. But even if we did that, this does not
- // work for at least two reasons:
- // 1. In this test, calling registerNetworkAgent does not actually result in an agent being
- // registered. This is because nothing calls onNetworkMonitorCreated, which is what
- // actually ends up causing handleRegisterNetworkAgent to be called. Code in this test
- // that wants to register an agent must use TestNetworkAgentWrapper.
- // 2. Even if we exposed Vpn#agentConnect to the test, and made MockVpn#agentConnect call
- // the TestNetworkAgentWrapper code, this would deadlock because the
- // TestNetworkAgentWrapper code cannot be called on the handler thread since it calls
- // waitForIdle().
- mMockVpn.expectStartLegacyVpnRunner();
- b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
- ExpectedBroadcast b2 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
- establishLegacyLockdownVpn(mCellNetworkAgent.getNetwork());
- callback.expectAvailableThenValidatedCallbacks(mMockVpn);
- defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- systemDefaultCallback.assertNoCallback();
- NetworkCapabilities vpnNc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- b1.expectBroadcast();
- b2.expectBroadcast();
- assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mCellNetworkAgent);
- assertTrue(vpnNc.hasTransport(TRANSPORT_VPN));
- assertTrue(vpnNc.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(vpnNc.hasTransport(TRANSPORT_WIFI));
- assertFalse(vpnNc.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertVpnTransportInfo(vpnNc, VpnManager.TYPE_VPN_LEGACY);
-
- // Switch default network from cell to wifi. Expect VPN to disconnect and reconnect.
- final LinkProperties wifiLp = new LinkProperties();
- wifiLp.setInterfaceName("wlan0");
- wifiLp.addLinkAddress(new LinkAddress("192.0.2.163/25"));
- wifiLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "wlan0"));
- final NetworkCapabilities wifiNc = new NetworkCapabilities();
- wifiNc.addTransportType(TRANSPORT_WIFI);
- wifiNc.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp, wifiNc);
-
- b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED);
- // Wifi is CONNECTING because the VPN isn't up yet.
- b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTING);
- ExpectedBroadcast b3 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
- mWiFiNetworkAgent.connect(false /* validated */);
- b1.expectBroadcast();
- b2.expectBroadcast();
- b3.expectBroadcast();
- mMockVpn.expectStopVpnRunnerPrivileged();
- mMockVpn.expectStartLegacyVpnRunner();
-
- // TODO: why is wifi not blocked? Is it because when this callback is sent, the VPN is still
- // connected, so the network is not considered blocked by the lockdown UID ranges? But the
- // fact that a VPN is connected should only result in the VPN itself being unblocked, not
- // any other network. Bug in isUidBlockedByVpn?
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackEntry.LOST, mMockVpn);
- defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
- defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
- systemDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- // While the VPN is reconnecting on the new network, everything is blocked.
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
- assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED);
- assertExtraInfoFromCmBlocked(mWiFiNetworkAgent);
-
- // The VPN comes up again on wifi.
- b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
- b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- establishLegacyLockdownVpn(mWiFiNetworkAgent.getNetwork());
- callback.expectAvailableThenValidatedCallbacks(mMockVpn);
- defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
- systemDefaultCallback.assertNoCallback();
- b1.expectBroadcast();
- b2.expectBroadcast();
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mWiFiNetworkAgent);
- vpnNc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
- assertTrue(vpnNc.hasTransport(TRANSPORT_VPN));
- assertTrue(vpnNc.hasTransport(TRANSPORT_WIFI));
- assertFalse(vpnNc.hasTransport(TRANSPORT_CELLULAR));
- assertTrue(vpnNc.hasCapability(NET_CAPABILITY_NOT_METERED));
-
- // Disconnect cell. Nothing much happens since it's not the default network.
- mCellNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- defaultCallback.assertNoCallback();
- systemDefaultCallback.assertNoCallback();
-
- assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
- assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED);
- assertExtraInfoFromCmPresent(mWiFiNetworkAgent);
-
- b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
- b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- systemDefaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- b1.expectBroadcast();
- callback.expectCapabilitiesThat(mMockVpn, nc -> !nc.hasTransport(TRANSPORT_WIFI));
- mMockVpn.expectStopVpnRunnerPrivileged();
- callback.expectCallback(CallbackEntry.LOST, mMockVpn);
- b2.expectBroadcast();
- }
-
- /**
- * Test mutable and requestable network capabilities such as
- * {@link NetworkCapabilities#NET_CAPABILITY_TRUSTED} and
- * {@link NetworkCapabilities#NET_CAPABILITY_NOT_VCN_MANAGED}. Verify that the
- * {@code ConnectivityService} re-assign the networks accordingly.
- */
- @Test
- public final void testLoseMutableAndRequestableCaps() throws Exception {
- final int[] testCaps = new int [] {
- NET_CAPABILITY_TRUSTED,
- NET_CAPABILITY_NOT_VCN_MANAGED
- };
- for (final int testCap : testCaps) {
- // Create requests with and without the testing capability.
- final TestNetworkCallback callbackWithCap = new TestNetworkCallback();
- final TestNetworkCallback callbackWithoutCap = new TestNetworkCallback();
- mCm.requestNetwork(new NetworkRequest.Builder().addCapability(testCap).build(),
- callbackWithCap);
- mCm.requestNetwork(new NetworkRequest.Builder().removeCapability(testCap).build(),
- callbackWithoutCap);
-
- // Setup networks with testing capability and verify the default network changes.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.addCapability(testCap);
- mCellNetworkAgent.connect(true);
- callbackWithCap.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- callbackWithoutCap.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
- reset(mMockNetd);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(testCap);
- mWiFiNetworkAgent.connect(true);
- callbackWithCap.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- callbackWithoutCap.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- verify(mMockNetd).networkSetDefault(eq(mWiFiNetworkAgent.getNetwork().netId));
- reset(mMockNetd);
-
- // Remove the testing capability on wifi, verify the callback and default network
- // changes back to cellular.
- mWiFiNetworkAgent.removeCapability(testCap);
- callbackWithCap.expectAvailableCallbacksValidated(mCellNetworkAgent);
- callbackWithoutCap.expectCapabilitiesWithout(testCap, mWiFiNetworkAgent);
- verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
- reset(mMockNetd);
-
- mCellNetworkAgent.removeCapability(testCap);
- callbackWithCap.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- callbackWithoutCap.assertNoCallback();
- verify(mMockNetd).networkClearDefault();
-
- mCm.unregisterNetworkCallback(callbackWithCap);
- mCm.unregisterNetworkCallback(callbackWithoutCap);
- }
- }
-
- @Test
- public final void testBatteryStatsNetworkType() throws Exception {
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName("cell0");
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
- mCellNetworkAgent.connect(true);
- waitForIdle();
- verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext,
- cellLp.getInterfaceName(),
- new int[] { TRANSPORT_CELLULAR });
-
- final LinkProperties wifiLp = new LinkProperties();
- wifiLp.setInterfaceName("wifi0");
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext,
- wifiLp.getInterfaceName(),
- new int[] { TRANSPORT_WIFI });
-
- mCellNetworkAgent.disconnect();
- mWiFiNetworkAgent.disconnect();
-
- cellLp.setInterfaceName("wifi0");
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
- mCellNetworkAgent.connect(true);
- waitForIdle();
- verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext,
- cellLp.getInterfaceName(),
- new int[] { TRANSPORT_CELLULAR });
- mCellNetworkAgent.disconnect();
- }
-
- /**
- * Make simulated InterfaceConfigParcel for Nat464Xlat to query clat lower layer info.
- */
- private InterfaceConfigurationParcel getClatInterfaceConfigParcel(LinkAddress la) {
- final InterfaceConfigurationParcel cfg = new InterfaceConfigurationParcel();
- cfg.hwAddr = "11:22:33:44:55:66";
- cfg.ipv4Addr = la.getAddress().getHostAddress();
- cfg.prefixLength = la.getPrefixLength();
- return cfg;
- }
-
- /**
- * Make expected stack link properties, copied from Nat464Xlat.
- */
- private LinkProperties makeClatLinkProperties(LinkAddress la) {
- LinkAddress clatAddress = la;
- LinkProperties stacked = new LinkProperties();
- stacked.setInterfaceName(CLAT_PREFIX + MOBILE_IFNAME);
- RouteInfo ipv4Default = new RouteInfo(
- new LinkAddress(Inet4Address.ANY, 0),
- clatAddress.getAddress(), CLAT_PREFIX + MOBILE_IFNAME);
- stacked.addRoute(ipv4Default);
- stacked.addLinkAddress(clatAddress);
- return stacked;
- }
-
- private Nat64PrefixEventParcel makeNat64PrefixEvent(final int netId, final int prefixOperation,
- final String prefixAddress, final int prefixLength) {
- final Nat64PrefixEventParcel event = new Nat64PrefixEventParcel();
- event.netId = netId;
- event.prefixOperation = prefixOperation;
- event.prefixAddress = prefixAddress;
- event.prefixLength = prefixLength;
- return event;
- }
-
- @Test
- public void testStackedLinkProperties() throws Exception {
- final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24");
- final LinkAddress myIpv6 = new LinkAddress("2001:db8:1::1/64");
- final String kNat64PrefixString = "2001:db8:64:64:64:64::";
- final IpPrefix kNat64Prefix = new IpPrefix(InetAddress.getByName(kNat64PrefixString), 96);
- final String kOtherNat64PrefixString = "64:ff9b::";
- final IpPrefix kOtherNat64Prefix = new IpPrefix(
- InetAddress.getByName(kOtherNat64PrefixString), 96);
- final RouteInfo defaultRoute = new RouteInfo((IpPrefix) null, myIpv6.getAddress(),
- MOBILE_IFNAME);
- final RouteInfo ipv6Subnet = new RouteInfo(myIpv6, null, MOBILE_IFNAME);
- final RouteInfo ipv4Subnet = new RouteInfo(myIpv4, null, MOBILE_IFNAME);
- final RouteInfo stackedDefault = new RouteInfo((IpPrefix) null, myIpv4.getAddress(),
- CLAT_PREFIX + MOBILE_IFNAME);
-
- final NetworkRequest networkRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
-
- // Prepare ipv6 only link properties.
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- cellLp.addLinkAddress(myIpv6);
- cellLp.addRoute(defaultRoute);
- cellLp.addRoute(ipv6Subnet);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
- reset(mMockDnsResolver);
- reset(mMockNetd);
-
- // Connect with ipv6 link properties. Expect prefix discovery to be started.
- mCellNetworkAgent.connect(true);
- final int cellNetId = mCellNetworkAgent.getNetwork().netId;
- waitForIdle();
-
- verify(mMockNetd, times(1)).networkCreate(nativeNetworkConfigPhysical(cellNetId,
- INetd.PERMISSION_NONE));
- assertRoutesAdded(cellNetId, ipv6Subnet, defaultRoute);
- verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
- verify(mMockNetd, times(1)).networkAddInterface(cellNetId, MOBILE_IFNAME);
- verify(mDeps).reportNetworkInterfaceForTransports(mServiceContext,
- cellLp.getInterfaceName(),
- new int[] { TRANSPORT_CELLULAR });
-
- networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
-
- // Switching default network updates TCP buffer sizes.
- verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
- // Add an IPv4 address. Expect prefix discovery to be stopped. Netd doesn't tell us that
- // the NAT64 prefix was removed because one was never discovered.
- cellLp.addLinkAddress(myIpv4);
- mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- assertRoutesAdded(cellNetId, ipv4Subnet);
- verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
- verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
-
- // Make sure BatteryStats was not told about any v4- interfaces, as none should have
- // come online yet.
- waitForIdle();
- verify(mDeps, never())
- .reportNetworkInterfaceForTransports(eq(mServiceContext), startsWith("v4-"), any());
-
- verifyNoMoreInteractions(mMockNetd);
- verifyNoMoreInteractions(mMockDnsResolver);
- reset(mMockNetd);
- reset(mMockDnsResolver);
- when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
- .thenReturn(getClatInterfaceConfigParcel(myIpv4));
-
- // Remove IPv4 address. Expect prefix discovery to be started again.
- cellLp.removeLinkAddress(myIpv4);
- mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
- assertRoutesRemoved(cellNetId, ipv4Subnet);
-
- // When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
- Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent);
- assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix());
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
- makeNat64PrefixEvent(cellNetId, PREFIX_OPERATION_ADDED, kNat64PrefixString, 96));
- LinkProperties lpBeforeClat = networkCallback.expectCallback(
- CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent).getLp();
- assertEquals(0, lpBeforeClat.getStackedLinks().size());
- assertEquals(kNat64Prefix, lpBeforeClat.getNat64Prefix());
- verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
-
- // Clat iface comes up. Expect stacked link to be added.
- clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork())
- .getStackedLinks();
- assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0));
- assertRoutesAdded(cellNetId, stackedDefault);
- verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
- // Change trivial linkproperties and see if stacked link is preserved.
- cellLp.addDnsServer(InetAddress.getByName("8.8.8.8"));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
-
- List<LinkProperties> stackedLpsAfterChange =
- mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getStackedLinks();
- assertNotEquals(stackedLpsAfterChange, Collections.EMPTY_LIST);
- assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0));
-
- verify(mMockDnsResolver, times(1)).setResolverConfiguration(
- mResolverParamsParcelCaptor.capture());
- ResolverParamsParcel resolvrParams = mResolverParamsParcelCaptor.getValue();
- assertEquals(1, resolvrParams.servers.length);
- assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8"));
-
- for (final LinkProperties stackedLp : stackedLpsAfterChange) {
- verify(mDeps).reportNetworkInterfaceForTransports(
- mServiceContext, stackedLp.getInterfaceName(),
- new int[] { TRANSPORT_CELLULAR });
- }
- reset(mMockNetd);
- when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
- .thenReturn(getClatInterfaceConfigParcel(myIpv4));
- // Change the NAT64 prefix without first removing it.
- // Expect clatd to be stopped and started with the new prefix.
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
- cellNetId, PREFIX_OPERATION_ADDED, kOtherNat64PrefixString, 96));
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getStackedLinks().size() == 0);
- verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
- assertRoutesRemoved(cellNetId, stackedDefault);
- verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
-
- verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kOtherNat64Prefix.toString());
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getNat64Prefix().equals(kOtherNat64Prefix));
- clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getStackedLinks().size() == 1);
- assertRoutesAdded(cellNetId, stackedDefault);
- verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
- reset(mMockNetd);
-
- // Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
- // linkproperties are cleaned up.
- cellLp.addLinkAddress(myIpv4);
- cellLp.addRoute(ipv4Subnet);
- mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- assertRoutesAdded(cellNetId, ipv4Subnet);
- verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
- verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
-
- // As soon as stop is called, the linkproperties lose the stacked interface.
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork());
- LinkProperties expected = new LinkProperties(cellLp);
- expected.setNat64Prefix(kOtherNat64Prefix);
- assertEquals(expected, actualLpAfterIpv4);
- assertEquals(0, actualLpAfterIpv4.getStackedLinks().size());
- assertRoutesRemoved(cellNetId, stackedDefault);
-
- // The interface removed callback happens but has no effect after stop is called.
- clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
- networkCallback.assertNoCallback();
- verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
- verifyNoMoreInteractions(mMockNetd);
- verifyNoMoreInteractions(mMockDnsResolver);
- reset(mMockNetd);
- reset(mMockDnsResolver);
- when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
- .thenReturn(getClatInterfaceConfigParcel(myIpv4));
-
- // Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
- cellNetId, PREFIX_OPERATION_REMOVED, kOtherNat64PrefixString, 96));
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getNat64Prefix() == null);
-
- // Remove IPv4 address and expect prefix discovery and clatd to be started again.
- cellLp.removeLinkAddress(myIpv4);
- cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
- cellLp.removeDnsServer(InetAddress.getByName("8.8.8.8"));
- mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- assertRoutesRemoved(cellNetId, ipv4Subnet); // Directly-connected routes auto-added.
- verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
- cellNetId, PREFIX_OPERATION_ADDED, kNat64PrefixString, 96));
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
-
- // Clat iface comes up. Expect stacked link to be added.
- clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getStackedLinks().size() == 1 && lp.getNat64Prefix() != null);
- assertRoutesAdded(cellNetId, stackedDefault);
- verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
-
- // NAT64 prefix is removed. Expect that clat is stopped.
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent(
- cellNetId, PREFIX_OPERATION_REMOVED, kNat64PrefixString, 96));
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null);
- assertRoutesRemoved(cellNetId, ipv4Subnet, stackedDefault);
-
- // Stop has no effect because clat is already stopped.
- verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- (lp) -> lp.getStackedLinks().size() == 0);
- verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
- verify(mMockNetd, times(1)).interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME);
- verifyNoMoreInteractions(mMockNetd);
- // Clean up.
- mCellNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- networkCallback.assertNoCallback();
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- private void expectNat64PrefixChange(TestableNetworkCallback callback,
- TestNetworkAgentWrapper agent, IpPrefix prefix) {
- callback.expectLinkPropertiesThat(agent, x -> Objects.equals(x.getNat64Prefix(), prefix));
- }
-
- @Test
- public void testNat64PrefixMultipleSources() throws Exception {
- final String iface = "wlan0";
- final String pref64FromRaStr = "64:ff9b::";
- final String pref64FromDnsStr = "2001:db8:64::";
- final IpPrefix pref64FromRa = new IpPrefix(InetAddress.getByName(pref64FromRaStr), 96);
- final IpPrefix pref64FromDns = new IpPrefix(InetAddress.getByName(pref64FromDnsStr), 96);
- final IpPrefix newPref64FromRa = new IpPrefix("2001:db8:64:64:64:64::/96");
-
- final NetworkRequest request = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, callback);
-
- final LinkProperties baseLp = new LinkProperties();
- baseLp.setInterfaceName(iface);
- baseLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
- baseLp.addDnsServer(InetAddress.getByName("2001:4860:4860::6464"));
-
- reset(mMockNetd, mMockDnsResolver);
- InOrder inOrder = inOrder(mMockNetd, mMockDnsResolver);
-
- // If a network already has a NAT64 prefix on connect, clatd is started immediately and
- // prefix discovery is never started.
- LinkProperties lp = new LinkProperties(baseLp);
- lp.setNat64Prefix(pref64FromRa);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, lp);
- mWiFiNetworkAgent.connect(false);
- final Network network = mWiFiNetworkAgent.getNetwork();
- int netId = network.getNetId();
- callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString());
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString());
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
- callback.assertNoCallback();
- assertEquals(pref64FromRa, mCm.getLinkProperties(network).getNat64Prefix());
-
- // If the RA prefix is withdrawn, clatd is stopped and prefix discovery is started.
- lp.setNat64Prefix(null);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, null);
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
- inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
-
- // If the RA prefix appears while DNS discovery is in progress, discovery is stopped and
- // clatd is started with the prefix from the RA.
- lp.setNat64Prefix(pref64FromRa);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromRa);
- inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString());
- inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString());
-
- // Withdraw the RA prefix so we can test the case where an RA prefix appears after DNS
- // discovery has succeeded.
- lp.setNat64Prefix(null);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, null);
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
- inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
-
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
- makeNat64PrefixEvent(netId, PREFIX_OPERATION_ADDED, pref64FromDnsStr, 96));
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns);
- inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString());
-
- // If an RA advertises the same prefix that was discovered by DNS, nothing happens: prefix
- // discovery is not stopped, and there are no callbacks.
- lp.setNat64Prefix(pref64FromDns);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- callback.assertNoCallback();
- inOrder.verify(mMockNetd, never()).clatdStop(iface);
- inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
- inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString());
-
- // If the RA is later withdrawn, nothing happens again.
- lp.setNat64Prefix(null);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- callback.assertNoCallback();
- inOrder.verify(mMockNetd, never()).clatdStop(iface);
- inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
- inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString());
-
- // If the RA prefix changes, clatd is restarted and prefix discovery is stopped.
- lp.setNat64Prefix(pref64FromRa);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromRa);
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
-
- // Stopping prefix discovery results in a prefix removed notification.
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
- makeNat64PrefixEvent(netId, PREFIX_OPERATION_REMOVED, pref64FromDnsStr, 96));
-
- inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString());
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString());
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
-
- // If the RA prefix changes, clatd is restarted and prefix discovery is not started.
- lp.setNat64Prefix(newPref64FromRa);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, newPref64FromRa);
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
- inOrder.verify(mMockNetd).clatdStart(iface, newPref64FromRa.toString());
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, newPref64FromRa.toString());
- inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
-
- // If the RA prefix changes to the same value, nothing happens.
- lp.setNat64Prefix(newPref64FromRa);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- callback.assertNoCallback();
- assertEquals(newPref64FromRa, mCm.getLinkProperties(network).getNat64Prefix());
- inOrder.verify(mMockNetd, never()).clatdStop(iface);
- inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
- inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString());
-
- // The transition between no prefix and DNS prefix is tested in testStackedLinkProperties.
-
- // If the same prefix is learned first by DNS and then by RA, and clat is later stopped,
- // (e.g., because the network disconnects) setPrefix64(netid, "") is never called.
- lp.setNat64Prefix(null);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, null);
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).setPrefix64(netId, "");
- inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId);
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
- makeNat64PrefixEvent(netId, PREFIX_OPERATION_ADDED, pref64FromDnsStr, 96));
- expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns);
- inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString());
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), any());
-
- lp.setNat64Prefix(pref64FromDns);
- mWiFiNetworkAgent.sendLinkProperties(lp);
- callback.assertNoCallback();
- inOrder.verify(mMockNetd, never()).clatdStop(iface);
- inOrder.verify(mMockNetd, never()).clatdStart(eq(iface), anyString());
- inOrder.verify(mMockDnsResolver, never()).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).startPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString());
-
- // When tearing down a network, clat state is only updated after CALLBACK_LOST is fired, but
- // before CONNECTIVITY_ACTION is sent. Wait for CONNECTIVITY_ACTION before verifying that
- // clat has been stopped, or the test will be flaky.
- ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
- mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- b.expectBroadcast();
-
- inOrder.verify(mMockNetd).clatdStop(iface);
- inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId);
- inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), anyString());
-
- mCm.unregisterNetworkCallback(callback);
- }
-
- @Test
- public void testWith464XlatDisable() throws Exception {
- doReturn(false).when(mDeps).getCellular464XlatEnabled();
-
- final TestNetworkCallback callback = new TestNetworkCallback();
- final TestNetworkCallback defaultCallback = new TestNetworkCallback();
- final NetworkRequest networkRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
- mCm.registerNetworkCallback(networkRequest, callback);
- mCm.registerDefaultNetworkCallback(defaultCallback);
-
- // Bring up validated cell.
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
- cellLp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, MOBILE_IFNAME));
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
-
- mCellNetworkAgent.sendLinkProperties(cellLp);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- final int cellNetId = mCellNetworkAgent.getNetwork().netId;
- waitForIdle();
-
- verify(mMockDnsResolver, never()).startPrefix64Discovery(cellNetId);
- Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent);
- assertTrue("Nat464Xlat was not IDLE", !clat.isStarted());
-
- // This cannot happen because prefix discovery cannot succeed if it is never started.
- mService.mResolverUnsolEventCallback.onNat64PrefixEvent(
- makeNat64PrefixEvent(cellNetId, PREFIX_OPERATION_ADDED, "64:ff9b::", 96));
-
- // ... but still, check that even if it did, clatd would not be started.
- verify(mMockNetd, never()).clatdStart(anyString(), anyString());
- assertTrue("Nat464Xlat was not IDLE", !clat.isStarted());
- }
-
- @Test
- public void testDataActivityTracking() throws Exception {
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- final NetworkRequest networkRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- final LinkProperties cellLp = new LinkProperties();
- cellLp.setInterfaceName(MOBILE_IFNAME);
- mCellNetworkAgent.sendLinkProperties(cellLp);
- mCellNetworkAgent.connect(true);
- networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- verify(mMockNetd, times(1)).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final LinkProperties wifiLp = new LinkProperties();
- wifiLp.setInterfaceName(WIFI_IFNAME);
- mWiFiNetworkAgent.sendLinkProperties(wifiLp);
-
- // Network switch
- mWiFiNetworkAgent.connect(true);
- networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- networkCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- verify(mMockNetd, times(1)).idletimerAddInterface(eq(WIFI_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_WIFI)));
- verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
-
- // Disconnect wifi and switch back to cell
- reset(mMockNetd);
- mWiFiNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- assertNoCallbacks(networkCallback);
- verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(WIFI_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_WIFI)));
- verify(mMockNetd, times(1)).idletimerAddInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
-
- // reconnect wifi
- reset(mMockNetd);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- wifiLp.setInterfaceName(WIFI_IFNAME);
- mWiFiNetworkAgent.sendLinkProperties(wifiLp);
- mWiFiNetworkAgent.connect(true);
- networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- networkCallback.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- verify(mMockNetd, times(1)).idletimerAddInterface(eq(WIFI_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_WIFI)));
- verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
-
- // Disconnect cell
- reset(mMockNetd);
- mCellNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- // LOST callback is triggered earlier than removing idle timer. Broadcast should also be
- // sent as network being switched. Ensure rule removal for cell will not be triggered
- // unexpectedly before network being removed.
- waitForIdle();
- verify(mMockNetd, times(0)).idletimerRemoveInterface(eq(MOBILE_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_CELLULAR)));
- verify(mMockNetd, times(1)).networkDestroy(eq(mCellNetworkAgent.getNetwork().netId));
- verify(mMockDnsResolver, times(1))
- .destroyNetworkCache(eq(mCellNetworkAgent.getNetwork().netId));
-
- // Disconnect wifi
- ExpectedBroadcast b = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
- mWiFiNetworkAgent.disconnect();
- b.expectBroadcast();
- verify(mMockNetd, times(1)).idletimerRemoveInterface(eq(WIFI_IFNAME), anyInt(),
- eq(Integer.toString(TRANSPORT_WIFI)));
-
- // Clean up
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- private void verifyTcpBufferSizeChange(String tcpBufferSizes) throws Exception {
- String[] values = tcpBufferSizes.split(",");
- String rmemValues = String.join(" ", values[0], values[1], values[2]);
- String wmemValues = String.join(" ", values[3], values[4], values[5]);
- verify(mMockNetd, atLeastOnce()).setTcpRWmemorySize(rmemValues, wmemValues);
- reset(mMockNetd);
- }
-
- @Test
- public void testTcpBufferReset() throws Exception {
- final String testTcpBufferSizes = "1,2,3,4,5,6";
- final NetworkRequest networkRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(networkRequest, networkCallback);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- reset(mMockNetd);
- // Switching default network updates TCP buffer sizes.
- mCellNetworkAgent.connect(false);
- networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
- // Change link Properties should have updated tcp buffer size.
- LinkProperties lp = new LinkProperties();
- lp.setTcpBufferSizes(testTcpBufferSizes);
- mCellNetworkAgent.sendLinkProperties(lp);
- networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
- verifyTcpBufferSizeChange(testTcpBufferSizes);
- // Clean up.
- mCellNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- networkCallback.assertNoCallback();
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- @Test
- public void testGetGlobalProxyForNetwork() throws Exception {
- final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- final Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
- when(mService.mProxyTracker.getGlobalProxy()).thenReturn(testProxyInfo);
- assertEquals(testProxyInfo, mService.getProxyForNetwork(wifiNetwork));
- }
-
- @Test
- public void testGetProxyForActiveNetwork() throws Exception {
- final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- assertNull(mService.getProxyForNetwork(null));
-
- final LinkProperties testLinkProperties = new LinkProperties();
- testLinkProperties.setHttpProxy(testProxyInfo);
-
- mWiFiNetworkAgent.sendLinkProperties(testLinkProperties);
- waitForIdle();
-
- assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
- }
-
- @Test
- public void testGetProxyForVPN() throws Exception {
- final ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("test", 8888);
-
- // Set up a WiFi network with no proxy
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- assertNull(mService.getProxyForNetwork(null));
-
- // Connect a VPN network with a proxy.
- LinkProperties testLinkProperties = new LinkProperties();
- testLinkProperties.setHttpProxy(testProxyInfo);
- mMockVpn.establishForMyUid(testLinkProperties);
- assertUidRangesUpdatedForMyUid(true);
-
- // Test that the VPN network returns a proxy, and the WiFi does not.
- assertEquals(testProxyInfo, mService.getProxyForNetwork(mMockVpn.getNetwork()));
- assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
- assertNull(mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork()));
-
- // Test that the VPN network returns no proxy when it is set to null.
- testLinkProperties.setHttpProxy(null);
- mMockVpn.sendLinkProperties(testLinkProperties);
- waitForIdle();
- assertNull(mService.getProxyForNetwork(mMockVpn.getNetwork()));
- assertNull(mService.getProxyForNetwork(null));
-
- // Set WiFi proxy and check that the vpn proxy is still null.
- testLinkProperties.setHttpProxy(testProxyInfo);
- mWiFiNetworkAgent.sendLinkProperties(testLinkProperties);
- waitForIdle();
- assertNull(mService.getProxyForNetwork(null));
-
- // Disconnect from VPN and check that the active network, which is now the WiFi, has the
- // correct proxy setting.
- mMockVpn.disconnect();
- waitForIdle();
- assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertEquals(testProxyInfo, mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork()));
- assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
- }
-
- @Test
- public void testFullyRoutedVpnResultsInInterfaceFilteringRules() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
- // The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
- mMockVpn.establish(lp, VPN_UID, vpnRange);
- assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
-
- // A connected VPN should have interface rules set up. There are two expected invocations,
- // one during the VPN initial connection, one during the VPN LinkProperties update.
- ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
- verify(mMockNetd, times(2)).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
- assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID);
- assertContainsExactly(uidCaptor.getAllValues().get(1), APP1_UID, APP2_UID);
- assertTrue(mService.mPermissionMonitor.getVpnUidRanges("tun0").equals(vpnRange));
-
- mMockVpn.disconnect();
- waitForIdle();
-
- // Disconnected VPN should have interface rules removed
- verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
- assertNull(mService.mPermissionMonitor.getVpnUidRanges("tun0"));
- }
-
- @Test
- public void testLegacyVpnDoesNotResultInInterfaceFilteringRule() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
- // The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
- mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
- assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
-
- // Legacy VPN should not have interface rules set up
- verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any());
- }
-
- @Test
- public void testLocalIpv4OnlyVpnDoesNotResultInInterfaceFilteringRule()
- throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0"));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
- // The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
- mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
- assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID);
-
- // IPv6 unreachable route should not be misinterpreted as a default route
- verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any());
- }
-
- @Test
- public void testVpnHandoverChangesInterfaceFilteringRule() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- // The uid range needs to cover the test app so the network is visible to it.
- final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
- mMockVpn.establish(lp, VPN_UID, vpnRange);
- assertVpnUidRangesUpdated(true, vpnRange, VPN_UID);
-
- // Connected VPN should have interface rules set up. There are two expected invocations,
- // one during VPN uid update, one during VPN LinkProperties update
- ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
- verify(mMockNetd, times(2)).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
- assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID);
- assertContainsExactly(uidCaptor.getAllValues().get(1), APP1_UID, APP2_UID);
-
- reset(mMockNetd);
- InOrder inOrder = inOrder(mMockNetd);
- lp.setInterfaceName("tun1");
- mMockVpn.sendLinkProperties(lp);
- waitForIdle();
- // VPN handover (switch to a new interface) should result in rules being updated (old rules
- // removed first, then new rules added)
- inOrder.verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
- inOrder.verify(mMockNetd).firewallAddUidInterfaceRules(eq("tun1"), uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
-
- reset(mMockNetd);
- lp = new LinkProperties();
- lp.setInterfaceName("tun1");
- lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun1"));
- mMockVpn.sendLinkProperties(lp);
- waitForIdle();
- // VPN not routing everything should no longer have interface filtering rules
- verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
-
- reset(mMockNetd);
- lp = new LinkProperties();
- lp.setInterfaceName("tun1");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- mMockVpn.sendLinkProperties(lp);
- waitForIdle();
- // Back to routing all IPv6 traffic should have filtering rules
- verify(mMockNetd).firewallAddUidInterfaceRules(eq("tun1"), uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
- }
-
- @Test
- public void testUidUpdateChangesInterfaceFilteringRule() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- // The uid range needs to cover the test app so the network is visible to it.
- final UidRange vpnRange = PRIMARY_UIDRANGE;
- final Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
- mMockVpn.establish(lp, VPN_UID, vpnRanges);
- assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
-
- reset(mMockNetd);
- InOrder inOrder = inOrder(mMockNetd);
-
- // Update to new range which is old range minus APP1, i.e. only APP2
- final Set<UidRange> newRanges = new HashSet<>(Arrays.asList(
- new UidRange(vpnRange.start, APP1_UID - 1),
- new UidRange(APP1_UID + 1, vpnRange.stop)));
- mMockVpn.setUids(newRanges);
- waitForIdle();
-
- ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
- // Verify old rules are removed before new rules are added
- inOrder.verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
- inOrder.verify(mMockNetd).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
- assertContainsExactly(uidCaptor.getValue(), APP2_UID);
- }
-
- @Test
- public void testLinkPropertiesWithWakeOnLanForActiveNetwork() throws Exception {
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
-
- LinkProperties wifiLp = new LinkProperties();
- wifiLp.setInterfaceName(WIFI_WOL_IFNAME);
- wifiLp.setWakeOnLanSupported(false);
-
- // Default network switch should update ifaces.
- mWiFiNetworkAgent.connect(false);
- mWiFiNetworkAgent.sendLinkProperties(wifiLp);
- waitForIdle();
-
- // ConnectivityService should have changed the WakeOnLanSupported to true
- wifiLp.setWakeOnLanSupported(true);
- assertEquals(wifiLp, mService.getActiveLinkProperties());
- }
-
- @Test
- public void testLegacyExtraInfoSentToNetworkMonitor() throws Exception {
- class TestNetworkAgent extends NetworkAgent {
- TestNetworkAgent(Context context, Looper looper, NetworkAgentConfig config) {
- super(context, looper, "MockAgent", new NetworkCapabilities(),
- new LinkProperties(), 40 , config, null /* provider */);
- }
- }
- final NetworkAgent naNoExtraInfo = new TestNetworkAgent(
- mServiceContext, mCsHandlerThread.getLooper(), new NetworkAgentConfig());
- naNoExtraInfo.register();
- verify(mNetworkStack).makeNetworkMonitor(any(), isNull(String.class), any());
- naNoExtraInfo.unregister();
-
- reset(mNetworkStack);
- final NetworkAgentConfig config =
- new NetworkAgentConfig.Builder().setLegacyExtraInfo("legacyinfo").build();
- final NetworkAgent naExtraInfo = new TestNetworkAgent(
- mServiceContext, mCsHandlerThread.getLooper(), config);
- naExtraInfo.register();
- verify(mNetworkStack).makeNetworkMonitor(any(), eq("legacyinfo"), any());
- naExtraInfo.unregister();
- }
-
- // To avoid granting location permission bypass.
- private void denyAllLocationPrivilegedPermissions() {
- mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- PERMISSION_DENIED);
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
- mServiceContext.setPermission(Manifest.permission.NETWORK_STACK,
- PERMISSION_DENIED);
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETUP_WIZARD,
- PERMISSION_DENIED);
- }
-
- private void setupLocationPermissions(
- int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
- denyAllLocationPrivilegedPermissions();
-
- final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.targetSdkVersion = targetSdk;
- when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any()))
- .thenReturn(applicationInfo);
- when(mPackageManager.getTargetSdkVersion(any())).thenReturn(targetSdk);
-
- when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(locationToggle);
-
- if (op != null) {
- when(mAppOpsManager.noteOp(eq(op), eq(Process.myUid()),
- eq(mContext.getPackageName()), eq(getAttributionTag()), anyString()))
- .thenReturn(AppOpsManager.MODE_ALLOWED);
- }
-
- if (perm != null) {
- mServiceContext.setPermission(perm, PERMISSION_GRANTED);
- }
- }
-
- private int getOwnerUidNetCapsPermission(int ownerUid, int callerUid,
- boolean includeLocationSensitiveInfo) {
- final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
-
- return mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, includeLocationSensitiveInfo, Process.myUid(), callerUid,
- mContext.getPackageName(), getAttributionTag())
- .getOwnerUid();
- }
-
- private void verifyTransportInfoCopyNetCapsPermission(
- int callerUid, boolean includeLocationSensitiveInfo,
- boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
- final TransportInfo transportInfo = mock(TransportInfo.class);
- when(transportInfo.getApplicableRedactions()).thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION);
- final NetworkCapabilities netCap =
- new NetworkCapabilities().setTransportInfo(transportInfo);
-
- mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, includeLocationSensitiveInfo, Process.myPid(), callerUid,
- mContext.getPackageName(), getAttributionTag());
- if (shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
- verify(transportInfo).makeCopy(REDACT_NONE);
- } else {
- verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
- }
- }
-
- private void verifyOwnerUidAndTransportInfoNetCapsPermission(
- boolean shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag,
- boolean shouldInclLocationSensitiveOwnerUidWithIncludeFlag,
- boolean shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag,
- boolean shouldInclLocationSensitiveTransportInfoWithIncludeFlag) {
- final int myUid = Process.myUid();
-
- final int expectedOwnerUidWithoutIncludeFlag =
- shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag
- ? myUid : INVALID_UID;
- assertEquals(expectedOwnerUidWithoutIncludeFlag, getOwnerUidNetCapsPermission(
- myUid, myUid, false /* includeLocationSensitiveInfo */));
-
- final int expectedOwnerUidWithIncludeFlag =
- shouldInclLocationSensitiveOwnerUidWithIncludeFlag ? myUid : INVALID_UID;
- assertEquals(expectedOwnerUidWithIncludeFlag, getOwnerUidNetCapsPermission(
- myUid, myUid, true /* includeLocationSensitiveInfo */));
-
- verifyTransportInfoCopyNetCapsPermission(myUid,
- false, /* includeLocationSensitiveInfo */
- shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag);
-
- verifyTransportInfoCopyNetCapsPermission(myUid,
- true, /* includeLocationSensitiveInfo */
- shouldInclLocationSensitiveTransportInfoWithIncludeFlag);
-
- }
-
- private void verifyOwnerUidAndTransportInfoNetCapsPermissionPreS() {
- verifyOwnerUidAndTransportInfoNetCapsPermission(
- // Ensure that owner uid is included even if the request asks to remove it (which is
- // the default) since the app has necessary permissions and targetSdk < S.
- true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- // Ensure that location info is removed if the request asks to remove it even if the
- // app has necessary permissions.
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
- );
- }
-
- @Test
- public void testCreateWithLocationInfoSanitizedWithFineLocationAfterQPreS()
- throws Exception {
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- verifyOwnerUidAndTransportInfoNetCapsPermissionPreS();
- }
-
- @Test
- public void testCreateWithLocationInfoSanitizedWithFineLocationPreSWithAndWithoutCallbackFlag()
- throws Exception {
- setupLocationPermissions(Build.VERSION_CODES.R, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- verifyOwnerUidAndTransportInfoNetCapsPermissionPreS();
- }
-
- @Test
- public void
- testCreateWithLocationInfoSanitizedWithFineLocationAfterSWithAndWithoutCallbackFlag()
- throws Exception {
- setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- verifyOwnerUidAndTransportInfoNetCapsPermission(
- // Ensure that the owner UID is removed if the request asks us to remove it even
- // if the app has necessary permissions since targetSdk >= S.
- false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- // Ensure that location info is removed if the request asks to remove it even if the
- // app has necessary permissions.
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
- );
- }
-
- @Test
- public void testCreateWithLocationInfoSanitizedWithCoarseLocationPreQ()
- throws Exception {
- setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION);
-
- verifyOwnerUidAndTransportInfoNetCapsPermissionPreS();
- }
-
- private void verifyOwnerUidAndTransportInfoNetCapsNotIncluded() {
- verifyOwnerUidAndTransportInfoNetCapsPermission(
- false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
- );
- }
-
- @Test
- public void testCreateWithLocationInfoSanitizedLocationOff() throws Exception {
- // Test that even with fine location permission, and UIDs matching, the UID is sanitized.
- setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- verifyOwnerUidAndTransportInfoNetCapsNotIncluded();
- }
-
- @Test
- public void testCreateWithLocationInfoSanitizedWrongUid() throws Exception {
- // Test that even with fine location permission, not being the owner leads to sanitization.
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- final int myUid = Process.myUid();
- assertEquals(Process.INVALID_UID,
- getOwnerUidNetCapsPermission(myUid + 1, myUid,
- true /* includeLocationSensitiveInfo */));
- }
-
- @Test
- public void testCreateWithLocationInfoSanitizedWithCoarseLocationAfterQ()
- throws Exception {
- // Test that not having fine location permission leads to sanitization.
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION);
-
- verifyOwnerUidAndTransportInfoNetCapsNotIncluded();
- }
-
- @Test
- public void testCreateWithLocationInfoSanitizedWithCoarseLocationAfterS()
- throws Exception {
- // Test that not having fine location permission leads to sanitization.
- setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_COARSE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION);
-
- verifyOwnerUidAndTransportInfoNetCapsNotIncluded();
- }
-
- @Test
- public void testCreateForCallerWithLocalMacAddressSanitizedWithLocalMacAddressPermission()
- throws Exception {
- mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_GRANTED);
-
- final TransportInfo transportInfo = mock(TransportInfo.class);
- when(transportInfo.getApplicableRedactions())
- .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS);
- final NetworkCapabilities netCap =
- new NetworkCapabilities().setTransportInfo(transportInfo);
-
- mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
- Process.myPid(), Process.myUid(),
- mContext.getPackageName(), getAttributionTag());
- // don't redact MAC_ADDRESS fields, only location sensitive fields.
- verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
- }
-
- @Test
- public void testCreateForCallerWithLocalMacAddressSanitizedWithoutLocalMacAddressPermission()
- throws Exception {
- mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_DENIED);
-
- final TransportInfo transportInfo = mock(TransportInfo.class);
- when(transportInfo.getApplicableRedactions())
- .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS);
- final NetworkCapabilities netCap =
- new NetworkCapabilities().setTransportInfo(transportInfo);
-
- mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
- Process.myPid(), Process.myUid(),
- mContext.getPackageName(), getAttributionTag());
- // redact both MAC_ADDRESS & location sensitive fields.
- verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION
- | REDACT_FOR_LOCAL_MAC_ADDRESS);
- }
-
- @Test
- public void testCreateForCallerWithLocalMacAddressSanitizedWithSettingsPermission()
- throws Exception {
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
-
- final TransportInfo transportInfo = mock(TransportInfo.class);
- when(transportInfo.getApplicableRedactions())
- .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
- final NetworkCapabilities netCap =
- new NetworkCapabilities().setTransportInfo(transportInfo);
-
- mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
- Process.myPid(), Process.myUid(),
- mContext.getPackageName(), getAttributionTag());
- // don't redact NETWORK_SETTINGS fields, only location sensitive fields.
- verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
- }
-
- @Test
- public void testCreateForCallerWithLocalMacAddressSanitizedWithoutSettingsPermission()
- throws Exception {
- mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_DENIED);
-
- final TransportInfo transportInfo = mock(TransportInfo.class);
- when(transportInfo.getApplicableRedactions())
- .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
- final NetworkCapabilities netCap =
- new NetworkCapabilities().setTransportInfo(transportInfo);
-
- mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
- netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
- Process.myPid(), Process.myUid(),
- mContext.getPackageName(), getAttributionTag());
- // redact both NETWORK_SETTINGS & location sensitive fields.
- verify(transportInfo).makeCopy(
- REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
- }
-
- /**
- * Test TransportInfo to verify redaction mechanism.
- */
- private static class TestTransportInfo implements TransportInfo {
- public final boolean locationRedacted;
- public final boolean localMacAddressRedacted;
- public final boolean settingsRedacted;
-
- TestTransportInfo() {
- locationRedacted = false;
- localMacAddressRedacted = false;
- settingsRedacted = false;
- }
-
- TestTransportInfo(boolean locationRedacted, boolean localMacAddressRedacted,
- boolean settingsRedacted) {
- this.locationRedacted = locationRedacted;
- this.localMacAddressRedacted =
- localMacAddressRedacted;
- this.settingsRedacted = settingsRedacted;
- }
-
- @Override
- public TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) {
- return new TestTransportInfo(
- locationRedacted | (redactions & REDACT_FOR_ACCESS_FINE_LOCATION) != 0,
- localMacAddressRedacted | (redactions & REDACT_FOR_LOCAL_MAC_ADDRESS) != 0,
- settingsRedacted | (redactions & REDACT_FOR_NETWORK_SETTINGS) != 0
- );
- }
-
- @Override
- public @NetworkCapabilities.RedactionType long getApplicableRedactions() {
- return REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS
- | REDACT_FOR_NETWORK_SETTINGS;
- }
-
- @Override
- public boolean equals(Object other) {
- if (!(other instanceof TestTransportInfo)) return false;
- TestTransportInfo that = (TestTransportInfo) other;
- return that.locationRedacted == this.locationRedacted
- && that.localMacAddressRedacted == this.localMacAddressRedacted
- && that.settingsRedacted == this.settingsRedacted;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(locationRedacted, localMacAddressRedacted, settingsRedacted);
- }
-
- @Override
- public String toString() {
- return String.format(
- "TestTransportInfo{locationRedacted=%s macRedacted=%s settingsRedacted=%s}",
- locationRedacted, localMacAddressRedacted, settingsRedacted);
- }
- }
-
- private TestTransportInfo getTestTransportInfo(NetworkCapabilities nc) {
- return (TestTransportInfo) nc.getTransportInfo();
- }
-
- private TestTransportInfo getTestTransportInfo(TestNetworkAgentWrapper n) {
- final NetworkCapabilities nc = mCm.getNetworkCapabilities(n.getNetwork());
- assertNotNull(nc);
- return getTestTransportInfo(nc);
- }
-
-
- private void verifyNetworkCallbackLocationDataInclusionUsingTransportInfoAndOwnerUidInNetCaps(
- @NonNull TestNetworkCallback wifiNetworkCallback, int actualOwnerUid,
- @NonNull TransportInfo actualTransportInfo, int expectedOwnerUid,
- @NonNull TransportInfo expectedTransportInfo) throws Exception {
- when(mPackageManager.getTargetSdkVersion(anyString())).thenReturn(Build.VERSION_CODES.S);
- final NetworkCapabilities ncTemplate =
- new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .setOwnerUid(actualOwnerUid);
-
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(),
- ncTemplate);
- mWiFiNetworkAgent.connect(false);
-
- wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
-
- // Send network capabilities update with TransportInfo to trigger capabilities changed
- // callback.
- mWiFiNetworkAgent.setNetworkCapabilities(
- ncTemplate.setTransportInfo(actualTransportInfo), true);
-
- wifiNetworkCallback.expectCapabilitiesThat(mWiFiNetworkAgent,
- nc -> Objects.equals(expectedOwnerUid, nc.getOwnerUid())
- && Objects.equals(expectedTransportInfo, nc.getTransportInfo()));
- }
-
- @Test
- public void testVerifyLocationDataIsNotIncludedWhenInclFlagNotSet() throws Exception {
- final TestNetworkCallback wifiNetworkCallack = new TestNetworkCallback();
- final int ownerUid = Process.myUid();
- final TransportInfo transportInfo = new TestTransportInfo();
- // Even though the test uid holds privileged permissions, mask location fields since
- // the callback did not explicitly opt-in to get location data.
- final TransportInfo sanitizedTransportInfo = new TestTransportInfo(
- true, /* locationRedacted */
- true, /* localMacAddressRedacted */
- true /* settingsRedacted */
- );
- // Should not expect location data since the callback does not set the flag for including
- // location data.
- verifyNetworkCallbackLocationDataInclusionUsingTransportInfoAndOwnerUidInNetCaps(
- wifiNetworkCallack, ownerUid, transportInfo, INVALID_UID, sanitizedTransportInfo);
- }
-
- @Test
- public void testTransportInfoRedactionInSynchronousCalls() throws Exception {
- final NetworkCapabilities ncTemplate = new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .setTransportInfo(new TestTransportInfo());
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(),
- ncTemplate);
- mWiFiNetworkAgent.connect(true /* validated; waits for callback */);
-
- // NETWORK_SETTINGS redaction is controlled by the NETWORK_SETTINGS permission
- assertTrue(getTestTransportInfo(mWiFiNetworkAgent).settingsRedacted);
- withPermission(NETWORK_SETTINGS, () -> {
- assertFalse(getTestTransportInfo(mWiFiNetworkAgent).settingsRedacted);
- });
- assertTrue(getTestTransportInfo(mWiFiNetworkAgent).settingsRedacted);
-
- // LOCAL_MAC_ADDRESS redaction is controlled by the LOCAL_MAC_ADDRESS permission
- assertTrue(getTestTransportInfo(mWiFiNetworkAgent).localMacAddressRedacted);
- withPermission(LOCAL_MAC_ADDRESS, () -> {
- assertFalse(getTestTransportInfo(mWiFiNetworkAgent).localMacAddressRedacted);
- });
- assertTrue(getTestTransportInfo(mWiFiNetworkAgent).localMacAddressRedacted);
-
- // Synchronous getNetworkCapabilities calls never return unredacted location-sensitive
- // information.
- assertTrue(getTestTransportInfo(mWiFiNetworkAgent).locationRedacted);
- setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
- assertTrue(getTestTransportInfo(mWiFiNetworkAgent).locationRedacted);
- denyAllLocationPrivilegedPermissions();
- assertTrue(getTestTransportInfo(mWiFiNetworkAgent).locationRedacted);
- }
-
- private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
- throws Exception {
- final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);
- mMockVpn.setVpnType(vpnType);
- mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange);
- assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid);
-
- final UnderlyingNetworkInfo underlyingNetworkInfo =
- new UnderlyingNetworkInfo(vpnOwnerUid, VPN_IFNAME, new ArrayList<String>());
- mMockVpn.setUnderlyingNetworkInfo(underlyingNetworkInfo);
- when(mDeps.getConnectionOwnerUid(anyInt(), any(), any())).thenReturn(42);
- }
-
- private void setupConnectionOwnerUidAsVpnApp(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
- throws Exception {
- setupConnectionOwnerUid(vpnOwnerUid, vpnType);
-
- // Test as VPN app
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
- mServiceContext.setPermission(
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, PERMISSION_DENIED);
- }
-
- private ConnectionInfo getTestConnectionInfo() throws Exception {
- return new ConnectionInfo(
- IPPROTO_TCP,
- new InetSocketAddress(InetAddresses.parseNumericAddress("1.2.3.4"), 1234),
- new InetSocketAddress(InetAddresses.parseNumericAddress("2.3.4.5"), 2345));
- }
-
- @Test
- public void testGetConnectionOwnerUidPlatformVpn() throws Exception {
- final int myUid = Process.myUid();
- setupConnectionOwnerUidAsVpnApp(myUid, VpnManager.TYPE_VPN_PLATFORM);
-
- assertEquals(INVALID_UID, mService.getConnectionOwnerUid(getTestConnectionInfo()));
- }
-
- @Test
- public void testGetConnectionOwnerUidVpnServiceWrongUser() throws Exception {
- final int myUid = Process.myUid();
- setupConnectionOwnerUidAsVpnApp(myUid + 1, VpnManager.TYPE_VPN_SERVICE);
-
- assertEquals(INVALID_UID, mService.getConnectionOwnerUid(getTestConnectionInfo()));
- }
-
- @Test
- public void testGetConnectionOwnerUidVpnServiceDoesNotThrow() throws Exception {
- final int myUid = Process.myUid();
- setupConnectionOwnerUidAsVpnApp(myUid, VpnManager.TYPE_VPN_SERVICE);
-
- assertEquals(42, mService.getConnectionOwnerUid(getTestConnectionInfo()));
- }
-
- @Test
- public void testGetConnectionOwnerUidVpnServiceNetworkStackDoesNotThrow() throws Exception {
- final int myUid = Process.myUid();
- setupConnectionOwnerUid(myUid, VpnManager.TYPE_VPN_SERVICE);
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
-
- assertEquals(42, mService.getConnectionOwnerUid(getTestConnectionInfo()));
- }
-
- @Test
- public void testGetConnectionOwnerUidVpnServiceMainlineNetworkStackDoesNotThrow()
- throws Exception {
- final int myUid = Process.myUid();
- setupConnectionOwnerUid(myUid, VpnManager.TYPE_VPN_SERVICE);
- mServiceContext.setPermission(
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, PERMISSION_GRANTED);
-
- assertEquals(42, mService.getConnectionOwnerUid(getTestConnectionInfo()));
- }
-
- private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid) {
- final PackageInfo packageInfo = new PackageInfo();
- if (hasSystemPermission) {
- packageInfo.requestedPermissions = new String[] {
- CHANGE_NETWORK_STATE, CONNECTIVITY_USE_RESTRICTED_NETWORKS };
- packageInfo.requestedPermissionsFlags = new int[] {
- REQUESTED_PERMISSION_GRANTED, REQUESTED_PERMISSION_GRANTED };
- } else {
- packageInfo.requestedPermissions = new String[0];
- }
- packageInfo.applicationInfo = new ApplicationInfo();
- packageInfo.applicationInfo.privateFlags = 0;
- packageInfo.applicationInfo.uid = UserHandle.getUid(UserHandle.USER_SYSTEM,
- UserHandle.getAppId(uid));
- return packageInfo;
- }
-
- @Test
- public void testRegisterConnectivityDiagnosticsCallbackInvalidRequest() throws Exception {
- final NetworkRequest request =
- new NetworkRequest(
- new NetworkCapabilities(), TYPE_ETHERNET, 0, NetworkRequest.Type.NONE);
- try {
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
- fail("registerConnectivityDiagnosticsCallback should throw on invalid NetworkRequest");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- private void assertRouteInfoParcelMatches(RouteInfo route, RouteInfoParcel parcel) {
- assertEquals(route.getDestination().toString(), parcel.destination);
- assertEquals(route.getInterface(), parcel.ifName);
- assertEquals(route.getMtu(), parcel.mtu);
-
- switch (route.getType()) {
- case RouteInfo.RTN_UNICAST:
- if (route.hasGateway()) {
- assertEquals(route.getGateway().getHostAddress(), parcel.nextHop);
- } else {
- assertEquals(INetd.NEXTHOP_NONE, parcel.nextHop);
- }
- break;
- case RouteInfo.RTN_UNREACHABLE:
- assertEquals(INetd.NEXTHOP_UNREACHABLE, parcel.nextHop);
- break;
- case RouteInfo.RTN_THROW:
- assertEquals(INetd.NEXTHOP_THROW, parcel.nextHop);
- break;
- default:
- assertEquals(INetd.NEXTHOP_NONE, parcel.nextHop);
- break;
- }
- }
-
- private void assertRoutesAdded(int netId, RouteInfo... routes) throws Exception {
- ArgumentCaptor<RouteInfoParcel> captor = ArgumentCaptor.forClass(RouteInfoParcel.class);
- verify(mMockNetd, times(routes.length)).networkAddRouteParcel(eq(netId), captor.capture());
- for (int i = 0; i < routes.length; i++) {
- assertRouteInfoParcelMatches(routes[i], captor.getAllValues().get(i));
- }
- }
-
- private void assertRoutesRemoved(int netId, RouteInfo... routes) throws Exception {
- ArgumentCaptor<RouteInfoParcel> captor = ArgumentCaptor.forClass(RouteInfoParcel.class);
- verify(mMockNetd, times(routes.length)).networkRemoveRouteParcel(eq(netId),
- captor.capture());
- for (int i = 0; i < routes.length; i++) {
- assertRouteInfoParcelMatches(routes[i], captor.getAllValues().get(i));
- }
- }
-
- @Test
- public void testRegisterUnregisterConnectivityDiagnosticsCallback() throws Exception {
- final NetworkRequest wifiRequest =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build();
- when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
-
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName());
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- verify(mIBinder).linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
- verify(mConnectivityDiagnosticsCallback).asBinder();
- assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
-
- mService.unregisterConnectivityDiagnosticsCallback(mConnectivityDiagnosticsCallback);
- verify(mIBinder, timeout(TIMEOUT_MS))
- .unlinkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
- assertFalse(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
- verify(mConnectivityDiagnosticsCallback, atLeastOnce()).asBinder();
- }
-
- @Test
- public void testRegisterDuplicateConnectivityDiagnosticsCallback() throws Exception {
- final NetworkRequest wifiRequest =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build();
- when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
-
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName());
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- verify(mIBinder).linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
- verify(mConnectivityDiagnosticsCallback).asBinder();
- assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
-
- // Register the same callback again
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName());
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder));
- }
-
- public NetworkAgentInfo fakeMobileNai(NetworkCapabilities nc) {
- final NetworkInfo info = new NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE,
- ConnectivityManager.getNetworkTypeName(TYPE_MOBILE),
- TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE));
- return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(),
- nc, new NetworkScore.Builder().setLegacyInt(0).build(),
- mServiceContext, null, new NetworkAgentConfig(), mService, null, null, 0,
- INVALID_UID, TEST_LINGER_DELAY_MS, mQosCallbackTracker,
- new ConnectivityService.Dependencies());
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception {
- final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
-
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
- assertTrue(
- "NetworkStack permission not applied",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid(), Process.myUid(), naiWithoutUid,
- mContext.getOpPackageName()));
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsWrongUidPackageName() throws Exception {
- final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
-
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
-
- assertFalse(
- "Mismatched uid/package name should not pass the location permission check",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid() + 1, Process.myUid() + 1, naiWithoutUid,
- mContext.getOpPackageName()));
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsNoLocationPermission() throws Exception {
- final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
-
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
-
- assertFalse(
- "ACCESS_FINE_LOCATION permission necessary for Connectivity Diagnostics",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid(), Process.myUid(), naiWithoutUid,
- mContext.getOpPackageName()));
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsActiveVpn() throws Exception {
- final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities());
-
- mMockVpn.establishForMyUid();
- assertUidRangesUpdatedForMyUid(true);
-
- // Wait for networks to connect and broadcasts to be sent before removing permissions.
- waitForIdle();
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
-
- assertTrue(mMockVpn.setUnderlyingNetworks(new Network[] {naiWithoutUid.network}));
- waitForIdle();
- assertTrue(
- "Active VPN permission not applied",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid(), Process.myUid(), naiWithoutUid,
- mContext.getOpPackageName()));
-
- assertTrue(mMockVpn.setUnderlyingNetworks(null));
- waitForIdle();
- assertFalse(
- "VPN shouldn't receive callback on non-underlying network",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid(), Process.myUid(), naiWithoutUid,
- mContext.getOpPackageName()));
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsNetworkAdministrator() throws Exception {
- final NetworkCapabilities nc = new NetworkCapabilities();
- nc.setAdministratorUids(new int[] {Process.myUid()});
- final NetworkAgentInfo naiWithUid = fakeMobileNai(nc);
-
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
-
- assertTrue(
- "NetworkCapabilities administrator uid permission not applied",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid(), Process.myUid(), naiWithUid, mContext.getOpPackageName()));
- }
-
- @Test
- public void testCheckConnectivityDiagnosticsPermissionsFails() throws Exception {
- final NetworkCapabilities nc = new NetworkCapabilities();
- nc.setOwnerUid(Process.myUid());
- nc.setAdministratorUids(new int[] {Process.myUid()});
- final NetworkAgentInfo naiWithUid = fakeMobileNai(nc);
-
- setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION);
- mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
-
- // Use wrong pid and uid
- assertFalse(
- "Permissions allowed when they shouldn't be granted",
- mService.checkConnectivityDiagnosticsPermissions(
- Process.myPid() + 1, Process.myUid() + 1, naiWithUid,
- mContext.getOpPackageName()));
- }
-
- @Test
- public void testRegisterConnectivityDiagnosticsCallbackCallsOnConnectivityReport()
- throws Exception {
- // Set up the Network, which leads to a ConnectivityReport being cached for the network.
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(callback);
- final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setInterfaceName(INTERFACE_NAME);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, linkProperties);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- callback.assertNoCallback();
-
- final NetworkRequest request = new NetworkRequest.Builder().build();
- when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
-
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
-
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- verify(mConnectivityDiagnosticsCallback)
- .onConnectivityReportAvailable(argThat(report -> {
- return INTERFACE_NAME.equals(report.getLinkProperties().getInterfaceName())
- && report.getNetworkCapabilities().hasTransport(TRANSPORT_CELLULAR);
- }));
- }
-
- private void setUpConnectivityDiagnosticsCallback() throws Exception {
- final NetworkRequest request = new NetworkRequest.Builder().build();
- when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
-
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
-
- mService.registerConnectivityDiagnosticsCallback(
- mConnectivityDiagnosticsCallback, request, mContext.getPackageName());
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- // Connect the cell agent verify that it notifies TestNetworkCallback that it is available
- final TestNetworkCallback callback = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(callback);
-
- final NetworkCapabilities ncTemplate = new NetworkCapabilities()
- .addTransportType(TRANSPORT_CELLULAR)
- .setTransportInfo(new TestTransportInfo());
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, new LinkProperties(),
- ncTemplate);
- mCellNetworkAgent.connect(true);
- callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- callback.assertNoCallback();
- }
-
- private boolean areConnDiagCapsRedacted(NetworkCapabilities nc) {
- TestTransportInfo ti = (TestTransportInfo) nc.getTransportInfo();
- return nc.getUids() == null
- && nc.getAdministratorUids().length == 0
- && nc.getOwnerUid() == Process.INVALID_UID
- && getTestTransportInfo(nc).locationRedacted
- && getTestTransportInfo(nc).localMacAddressRedacted
- && getTestTransportInfo(nc).settingsRedacted;
- }
-
- @Test
- public void testConnectivityDiagnosticsCallbackOnConnectivityReportAvailable()
- throws Exception {
- setUpConnectivityDiagnosticsCallback();
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- // Verify onConnectivityReport fired
- verify(mConnectivityDiagnosticsCallback).onConnectivityReportAvailable(
- argThat(report -> areConnDiagCapsRedacted(report.getNetworkCapabilities())));
- }
-
- @Test
- public void testConnectivityDiagnosticsCallbackOnDataStallSuspected() throws Exception {
- setUpConnectivityDiagnosticsCallback();
-
- // Trigger notifyDataStallSuspected() on the INetworkMonitorCallbacks instance in the
- // cellular network agent
- mCellNetworkAgent.notifyDataStallSuspected();
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- // Verify onDataStallSuspected fired
- verify(mConnectivityDiagnosticsCallback).onDataStallSuspected(
- argThat(report -> areConnDiagCapsRedacted(report.getNetworkCapabilities())));
- }
-
- @Test
- public void testConnectivityDiagnosticsCallbackOnConnectivityReported() throws Exception {
- setUpConnectivityDiagnosticsCallback();
-
- final Network n = mCellNetworkAgent.getNetwork();
- final boolean hasConnectivity = true;
- mService.reportNetworkConnectivity(n, hasConnectivity);
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- // Verify onNetworkConnectivityReported fired
- verify(mConnectivityDiagnosticsCallback)
- .onNetworkConnectivityReported(eq(n), eq(hasConnectivity));
-
- final boolean noConnectivity = false;
- mService.reportNetworkConnectivity(n, noConnectivity);
-
- // Block until all other events are done processing.
- HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
-
- // Wait for onNetworkConnectivityReported to fire
- verify(mConnectivityDiagnosticsCallback)
- .onNetworkConnectivityReported(eq(n), eq(noConnectivity));
- }
-
- @Test
- public void testRouteAddDeleteUpdate() throws Exception {
- final NetworkRequest request = new NetworkRequest.Builder().build();
- final TestNetworkCallback networkCallback = new TestNetworkCallback();
- mCm.registerNetworkCallback(request, networkCallback);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- reset(mMockNetd);
- mCellNetworkAgent.connect(false);
- networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- final int netId = mCellNetworkAgent.getNetwork().netId;
-
- final String iface = "rmnet_data0";
- final InetAddress gateway = InetAddress.getByName("fe80::5678");
- RouteInfo direct = RouteInfo.makeHostRoute(gateway, iface);
- RouteInfo rio1 = new RouteInfo(new IpPrefix("2001:db8:1::/48"), gateway, iface);
- RouteInfo rio2 = new RouteInfo(new IpPrefix("2001:db8:2::/48"), gateway, iface);
- RouteInfo defaultRoute = new RouteInfo((IpPrefix) null, gateway, iface);
- RouteInfo defaultWithMtu = new RouteInfo(null, gateway, iface, RouteInfo.RTN_UNICAST,
- 1280 /* mtu */);
-
- // Send LinkProperties and check that we ask netd to add routes.
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(iface);
- lp.addRoute(direct);
- lp.addRoute(rio1);
- lp.addRoute(defaultRoute);
- mCellNetworkAgent.sendLinkProperties(lp);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, x -> x.getRoutes().size() == 3);
-
- assertRoutesAdded(netId, direct, rio1, defaultRoute);
- reset(mMockNetd);
-
- // Send updated LinkProperties and check that we ask netd to add, remove, update routes.
- assertTrue(lp.getRoutes().contains(defaultRoute));
- lp.removeRoute(rio1);
- lp.addRoute(rio2);
- lp.addRoute(defaultWithMtu);
- // Ensure adding the same route with a different MTU replaces the previous route.
- assertFalse(lp.getRoutes().contains(defaultRoute));
- assertTrue(lp.getRoutes().contains(defaultWithMtu));
-
- mCellNetworkAgent.sendLinkProperties(lp);
- networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
- x -> x.getRoutes().contains(rio2));
-
- assertRoutesRemoved(netId, rio1);
- assertRoutesAdded(netId, rio2);
-
- ArgumentCaptor<RouteInfoParcel> captor = ArgumentCaptor.forClass(RouteInfoParcel.class);
- verify(mMockNetd).networkUpdateRouteParcel(eq(netId), captor.capture());
- assertRouteInfoParcelMatches(defaultWithMtu, captor.getValue());
-
-
- mCm.unregisterNetworkCallback(networkCallback);
- }
-
- @Test
- public void testDumpDoesNotCrash() {
- mServiceContext.setPermission(DUMP, PERMISSION_GRANTED);
- // Filing a couple requests prior to testing the dump.
- final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
- final NetworkRequest genericRequest = new NetworkRequest.Builder()
- .clearCapabilities().build();
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
- mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
- final StringWriter stringWriter = new StringWriter();
-
- mService.dump(new FileDescriptor(), new PrintWriter(stringWriter), new String[0]);
-
- assertFalse(stringWriter.toString().isEmpty());
- }
-
- @Test
- public void testRequestsSortedByIdSortsCorrectly() {
- final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
- final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
- final NetworkRequest genericRequest = new NetworkRequest.Builder()
- .clearCapabilities().build();
- final NetworkRequest wifiRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_WIFI).build();
- final NetworkRequest cellRequest = new NetworkRequest.Builder()
- .addTransportType(TRANSPORT_CELLULAR).build();
- mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
- mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
- mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
- waitForIdle();
-
- final ConnectivityService.NetworkRequestInfo[] nriOutput = mService.requestsSortedById();
-
- assertTrue(nriOutput.length > 1);
- for (int i = 0; i < nriOutput.length - 1; i++) {
- final boolean isRequestIdInOrder =
- nriOutput[i].mRequests.get(0).requestId
- < nriOutput[i + 1].mRequests.get(0).requestId;
- assertTrue(isRequestIdInOrder);
- }
- }
-
- private void assertUidRangesUpdatedForMyUid(boolean add) throws Exception {
- final int uid = Process.myUid();
- assertVpnUidRangesUpdated(add, uidRangesForUids(uid), uid);
- }
-
- private void assertVpnUidRangesUpdated(boolean add, Set<UidRange> vpnRanges, int exemptUid)
- throws Exception {
- InOrder inOrder = inOrder(mMockNetd);
- ArgumentCaptor<int[]> exemptUidCaptor = ArgumentCaptor.forClass(int[].class);
-
- inOrder.verify(mMockNetd, times(1)).socketDestroy(eq(toUidRangeStableParcels(vpnRanges)),
- exemptUidCaptor.capture());
- assertContainsExactly(exemptUidCaptor.getValue(), Process.VPN_UID, exemptUid);
-
- if (add) {
- inOrder.verify(mMockNetd, times(1))
- .networkAddUidRanges(eq(mMockVpn.getNetwork().getNetId()),
- eq(toUidRangeStableParcels(vpnRanges)));
- } else {
- inOrder.verify(mMockNetd, times(1))
- .networkRemoveUidRanges(eq(mMockVpn.getNetwork().getNetId()),
- eq(toUidRangeStableParcels(vpnRanges)));
- }
-
- inOrder.verify(mMockNetd, times(1)).socketDestroy(eq(toUidRangeStableParcels(vpnRanges)),
- exemptUidCaptor.capture());
- assertContainsExactly(exemptUidCaptor.getValue(), Process.VPN_UID, exemptUid);
- }
-
- @Test
- public void testVpnUidRangesUpdate() throws Exception {
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName("tun0");
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- final UidRange vpnRange = PRIMARY_UIDRANGE;
- Set<UidRange> vpnRanges = Collections.singleton(vpnRange);
- mMockVpn.establish(lp, VPN_UID, vpnRanges);
- assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID);
-
- reset(mMockNetd);
- // Update to new range which is old range minus APP1, i.e. only APP2
- final Set<UidRange> newRanges = new HashSet<>(Arrays.asList(
- new UidRange(vpnRange.start, APP1_UID - 1),
- new UidRange(APP1_UID + 1, vpnRange.stop)));
- mMockVpn.setUids(newRanges);
- waitForIdle();
-
- assertVpnUidRangesUpdated(true, newRanges, VPN_UID);
- assertVpnUidRangesUpdated(false, vpnRanges, VPN_UID);
- }
-
- @Test
- public void testInvalidRequestTypes() {
- final int[] invalidReqTypeInts = new int[]{-1, NetworkRequest.Type.NONE.ordinal(),
- NetworkRequest.Type.LISTEN.ordinal(), NetworkRequest.Type.values().length};
- final NetworkCapabilities nc = new NetworkCapabilities().addTransportType(TRANSPORT_WIFI);
-
- for (int reqTypeInt : invalidReqTypeInts) {
- assertThrows("Expect throws for invalid request type " + reqTypeInt,
- IllegalArgumentException.class,
- () -> mService.requestNetwork(Process.INVALID_UID, nc, reqTypeInt, null, 0,
- null, ConnectivityManager.TYPE_NONE, NetworkCallback.FLAG_NONE,
- mContext.getPackageName(), getAttributionTag())
- );
- }
- }
-
- @Test
- public void testKeepConnected() throws Exception {
- setAlwaysOnNetworks(false);
- registerDefaultNetworkCallbacks();
- final TestNetworkCallback allNetworksCb = new TestNetworkCallback();
- final NetworkRequest allNetworksRequest = new NetworkRequest.Builder().clearCapabilities()
- .build();
- mCm.registerNetworkCallback(allNetworksRequest, allNetworksCb);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true /* validated */);
-
- mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- allNetworksCb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true /* validated */);
-
- mDefaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- // While the default callback doesn't see the network before it's validated, the listen
- // sees the network come up and validate later
- allNetworksCb.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- allNetworksCb.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent);
- allNetworksCb.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- allNetworksCb.expectCallback(CallbackEntry.LOST, mCellNetworkAgent,
- TEST_LINGER_DELAY_MS * 2);
-
- // The cell network has disconnected (see LOST above) because it was outscored and
- // had no requests (see setAlwaysOnNetworks(false) above)
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- final NetworkScore score = new NetworkScore.Builder().setLegacyInt(30).build();
- mCellNetworkAgent.setScore(score);
- mCellNetworkAgent.connect(false /* validated */);
-
- // The cell network gets torn down right away.
- allNetworksCb.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- allNetworksCb.expectCallback(CallbackEntry.LOST, mCellNetworkAgent,
- TEST_NASCENT_DELAY_MS * 2);
- allNetworksCb.assertNoCallback();
-
- // Now create a cell network with KEEP_CONNECTED_FOR_HANDOVER and make sure it's
- // not disconnected immediately when outscored.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- final NetworkScore scoreKeepup = new NetworkScore.Builder().setLegacyInt(30)
- .setKeepConnectedReason(KEEP_CONNECTED_FOR_HANDOVER).build();
- mCellNetworkAgent.setScore(scoreKeepup);
- mCellNetworkAgent.connect(true /* validated */);
-
- allNetworksCb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mDefaultNetworkCallback.assertNoCallback();
-
- mWiFiNetworkAgent.disconnect();
-
- allNetworksCb.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
- mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
-
- // Reconnect a WiFi network and make sure the cell network is still not torn down.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true /* validated */);
-
- allNetworksCb.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- mDefaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
-
- // Now remove the reason to keep connected and make sure the network lingers and is
- // torn down.
- mCellNetworkAgent.setScore(new NetworkScore.Builder().setLegacyInt(30).build());
- allNetworksCb.expectCallback(CallbackEntry.LOSING, mCellNetworkAgent,
- TEST_NASCENT_DELAY_MS * 2);
- allNetworksCb.expectCallback(CallbackEntry.LOST, mCellNetworkAgent,
- TEST_LINGER_DELAY_MS * 2);
- mDefaultNetworkCallback.assertNoCallback();
-
- mCm.unregisterNetworkCallback(allNetworksCb);
- // mDefaultNetworkCallback will be unregistered by tearDown()
- }
-
- private class QosCallbackMockHelper {
- @NonNull public final QosFilter mFilter;
- @NonNull public final IQosCallback mCallback;
- @NonNull public final TestNetworkAgentWrapper mAgentWrapper;
- @NonNull private final List<IQosCallback> mCallbacks = new ArrayList();
-
- QosCallbackMockHelper() throws Exception {
- Log.d(TAG, "QosCallbackMockHelper: ");
- mFilter = mock(QosFilter.class);
-
- // Ensure the network is disconnected before anything else occurs
- assertNull(mCellNetworkAgent);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- verifyActiveNetwork(TRANSPORT_CELLULAR);
- waitForIdle();
- final Network network = mCellNetworkAgent.getNetwork();
-
- final Pair<IQosCallback, IBinder> pair = createQosCallback();
- mCallback = pair.first;
-
- when(mFilter.getNetwork()).thenReturn(network);
- when(mFilter.validate()).thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
- mAgentWrapper = mCellNetworkAgent;
- }
-
- void registerQosCallback(@NonNull final QosFilter filter,
- @NonNull final IQosCallback callback) {
- mCallbacks.add(callback);
- final NetworkAgentInfo nai =
- mService.getNetworkAgentInfoForNetwork(filter.getNetwork());
- mService.registerQosCallbackInternal(filter, callback, nai);
- }
-
- void tearDown() {
- for (int i = 0; i < mCallbacks.size(); i++) {
- mService.unregisterQosCallback(mCallbacks.get(i));
- }
- }
- }
-
- private Pair<IQosCallback, IBinder> createQosCallback() {
- final IQosCallback callback = mock(IQosCallback.class);
- final IBinder binder = mock(Binder.class);
- when(callback.asBinder()).thenReturn(binder);
- when(binder.isBinderAlive()).thenReturn(true);
- return new Pair<>(callback, binder);
- }
-
-
- @Test
- public void testQosCallbackRegistration() throws Exception {
- mQosCallbackMockHelper = new QosCallbackMockHelper();
- final NetworkAgentWrapper wrapper = mQosCallbackMockHelper.mAgentWrapper;
-
- when(mQosCallbackMockHelper.mFilter.validate())
- .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
- mQosCallbackMockHelper.registerQosCallback(
- mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
-
- final NetworkAgentWrapper.CallbackType.OnQosCallbackRegister cbRegister1 =
- (NetworkAgentWrapper.CallbackType.OnQosCallbackRegister)
- wrapper.getCallbackHistory().poll(1000, x -> true);
- assertNotNull(cbRegister1);
-
- final int registerCallbackId = cbRegister1.mQosCallbackId;
- mService.unregisterQosCallback(mQosCallbackMockHelper.mCallback);
- final NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister cbUnregister;
- cbUnregister = (NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister)
- wrapper.getCallbackHistory().poll(1000, x -> true);
- assertNotNull(cbUnregister);
- assertEquals(registerCallbackId, cbUnregister.mQosCallbackId);
- assertNull(wrapper.getCallbackHistory().poll(200, x -> true));
- }
-
- @Test
- public void testQosCallbackNoRegistrationOnValidationError() throws Exception {
- mQosCallbackMockHelper = new QosCallbackMockHelper();
-
- when(mQosCallbackMockHelper.mFilter.validate())
- .thenReturn(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
- mQosCallbackMockHelper.registerQosCallback(
- mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
- waitForIdle();
- verify(mQosCallbackMockHelper.mCallback)
- .onError(eq(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED));
- }
-
- @Test
- public void testQosCallbackAvailableAndLost() throws Exception {
- mQosCallbackMockHelper = new QosCallbackMockHelper();
- final int sessionId = 10;
- final int qosCallbackId = 1;
-
- when(mQosCallbackMockHelper.mFilter.validate())
- .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
- mQosCallbackMockHelper.registerQosCallback(
- mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
- waitForIdle();
-
- final EpsBearerQosSessionAttributes attributes = new EpsBearerQosSessionAttributes(
- 1, 2, 3, 4, 5, new ArrayList<>());
- mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
- .sendQosSessionAvailable(qosCallbackId, sessionId, attributes);
- waitForIdle();
-
- verify(mQosCallbackMockHelper.mCallback).onQosEpsBearerSessionAvailable(argThat(session ->
- session.getSessionId() == sessionId
- && session.getSessionType() == QosSession.TYPE_EPS_BEARER), eq(attributes));
-
- mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
- .sendQosSessionLost(qosCallbackId, sessionId, QosSession.TYPE_EPS_BEARER);
- waitForIdle();
- verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
- session.getSessionId() == sessionId
- && session.getSessionType() == QosSession.TYPE_EPS_BEARER));
- }
-
- @Test
- public void testNrQosCallbackAvailableAndLost() throws Exception {
- mQosCallbackMockHelper = new QosCallbackMockHelper();
- final int sessionId = 10;
- final int qosCallbackId = 1;
-
- when(mQosCallbackMockHelper.mFilter.validate())
- .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
- mQosCallbackMockHelper.registerQosCallback(
- mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
- waitForIdle();
-
- final NrQosSessionAttributes attributes = new NrQosSessionAttributes(
- 1, 2, 3, 4, 5, 6, 7, new ArrayList<>());
- mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
- .sendQosSessionAvailable(qosCallbackId, sessionId, attributes);
- waitForIdle();
-
- verify(mQosCallbackMockHelper.mCallback).onNrQosSessionAvailable(argThat(session ->
- session.getSessionId() == sessionId
- && session.getSessionType() == QosSession.TYPE_NR_BEARER), eq(attributes));
-
- mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
- .sendQosSessionLost(qosCallbackId, sessionId, QosSession.TYPE_NR_BEARER);
- waitForIdle();
- verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
- session.getSessionId() == sessionId
- && session.getSessionType() == QosSession.TYPE_NR_BEARER));
- }
-
- @Test
- public void testQosCallbackTooManyRequests() throws Exception {
- mQosCallbackMockHelper = new QosCallbackMockHelper();
-
- when(mQosCallbackMockHelper.mFilter.validate())
- .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
- for (int i = 0; i < 100; i++) {
- final Pair<IQosCallback, IBinder> pair = createQosCallback();
-
- try {
- mQosCallbackMockHelper.registerQosCallback(
- mQosCallbackMockHelper.mFilter, pair.first);
- } catch (ServiceSpecificException e) {
- assertEquals(e.errorCode, ConnectivityManager.Errors.TOO_MANY_REQUESTS);
- if (i < 50) {
- fail("TOO_MANY_REQUESTS thrown too early, the count is " + i);
- }
-
- // As long as there is at least 50 requests, it is safe to assume it works.
- // Note: The count isn't being tested precisely against 100 because the counter
- // is shared with request network.
- return;
- }
- }
- fail("TOO_MANY_REQUESTS never thrown");
- }
-
- private UidRange createUidRange(int userId) {
- return UidRange.createForUser(UserHandle.of(userId));
- }
-
- private void mockGetApplicationInfo(@NonNull final String packageName, @NonNull final int uid) {
- final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.uid = uid;
- try {
- when(mPackageManager.getApplicationInfo(eq(packageName), anyInt()))
- .thenReturn(applicationInfo);
- } catch (Exception e) {
- fail(e.getMessage());
- }
- }
-
- private void mockGetApplicationInfoThrowsNameNotFound(@NonNull final String packageName)
- throws Exception {
- when(mPackageManager.getApplicationInfo(eq(packageName), anyInt()))
- .thenThrow(new PackageManager.NameNotFoundException(packageName));
- }
-
- private void mockHasSystemFeature(@NonNull final String featureName,
- @NonNull final boolean hasFeature) {
- when(mPackageManager.hasSystemFeature(eq(featureName)))
- .thenReturn(hasFeature);
- }
-
- private Range<Integer> getNriFirstUidRange(
- @NonNull final ConnectivityService.NetworkRequestInfo nri) {
- return nri.mRequests.get(0).networkCapabilities.getUids().iterator().next();
- }
-
- private OemNetworkPreferences createDefaultOemNetworkPreferences(
- @OemNetworkPreferences.OemNetworkPreference final int preference) {
- // Arrange PackageManager mocks
- mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
-
- // Build OemNetworkPreferences object
- return new OemNetworkPreferences.Builder()
- .addNetworkPreference(TEST_PACKAGE_NAME, preference)
- .build();
- }
-
- @Test
- public void testOemNetworkRequestFactoryPreferenceUninitializedThrowsError()
- throws PackageManager.NameNotFoundException {
- @OemNetworkPreferences.OemNetworkPreference final int prefToTest =
- OEM_NETWORK_PREFERENCE_UNINITIALIZED;
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- assertThrows(IllegalArgumentException.class,
- () -> mService.new OemNetworkRequestFactory()
- .createNrisFromOemNetworkPreferences(
- createDefaultOemNetworkPreferences(prefToTest)));
- }
-
- @Test
- public void testOemNetworkRequestFactoryPreferenceOemPaid()
- throws Exception {
- // Expectations
- final int expectedNumOfNris = 1;
- final int expectedNumOfRequests = 3;
-
- @OemNetworkPreferences.OemNetworkPreference final int prefToTest =
- OEM_NETWORK_PREFERENCE_OEM_PAID;
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
- mService.new OemNetworkRequestFactory()
- .createNrisFromOemNetworkPreferences(
- createDefaultOemNetworkPreferences(prefToTest));
-
- final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
- assertEquals(expectedNumOfNris, nris.size());
- assertEquals(expectedNumOfRequests, mRequests.size());
- assertTrue(mRequests.get(0).isListen());
- assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_VALIDATED));
- assertTrue(mRequests.get(1).isRequest());
- assertTrue(mRequests.get(1).hasCapability(NET_CAPABILITY_OEM_PAID));
- assertEquals(NetworkRequest.Type.TRACK_DEFAULT, mRequests.get(2).type);
- assertTrue(mService.getDefaultRequest().networkCapabilities.equalsNetCapabilities(
- mRequests.get(2).networkCapabilities));
- }
-
- @Test
- public void testOemNetworkRequestFactoryPreferenceOemPaidNoFallback()
- throws Exception {
- // Expectations
- final int expectedNumOfNris = 1;
- final int expectedNumOfRequests = 2;
-
- @OemNetworkPreferences.OemNetworkPreference final int prefToTest =
- OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
- mService.new OemNetworkRequestFactory()
- .createNrisFromOemNetworkPreferences(
- createDefaultOemNetworkPreferences(prefToTest));
-
- final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
- assertEquals(expectedNumOfNris, nris.size());
- assertEquals(expectedNumOfRequests, mRequests.size());
- assertTrue(mRequests.get(0).isListen());
- assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_VALIDATED));
- assertTrue(mRequests.get(1).isRequest());
- assertTrue(mRequests.get(1).hasCapability(NET_CAPABILITY_OEM_PAID));
- }
-
- @Test
- public void testOemNetworkRequestFactoryPreferenceOemPaidOnly()
- throws Exception {
- // Expectations
- final int expectedNumOfNris = 1;
- final int expectedNumOfRequests = 1;
-
- @OemNetworkPreferences.OemNetworkPreference final int prefToTest =
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
- mService.new OemNetworkRequestFactory()
- .createNrisFromOemNetworkPreferences(
- createDefaultOemNetworkPreferences(prefToTest));
-
- final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
- assertEquals(expectedNumOfNris, nris.size());
- assertEquals(expectedNumOfRequests, mRequests.size());
- assertTrue(mRequests.get(0).isRequest());
- assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_OEM_PAID));
- }
-
- @Test
- public void testOemNetworkRequestFactoryPreferenceOemPrivateOnly()
- throws Exception {
- // Expectations
- final int expectedNumOfNris = 1;
- final int expectedNumOfRequests = 1;
-
- @OemNetworkPreferences.OemNetworkPreference final int prefToTest =
- OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
- mService.new OemNetworkRequestFactory()
- .createNrisFromOemNetworkPreferences(
- createDefaultOemNetworkPreferences(prefToTest));
-
- final List<NetworkRequest> mRequests = nris.iterator().next().mRequests;
- assertEquals(expectedNumOfNris, nris.size());
- assertEquals(expectedNumOfRequests, mRequests.size());
- assertTrue(mRequests.get(0).isRequest());
- assertTrue(mRequests.get(0).hasCapability(NET_CAPABILITY_OEM_PRIVATE));
- assertFalse(mRequests.get(0).hasCapability(NET_CAPABILITY_OEM_PAID));
- }
-
- @Test
- public void testOemNetworkRequestFactoryCreatesCorrectNumOfNris()
- throws Exception {
- // Expectations
- final int expectedNumOfNris = 2;
-
- // Arrange PackageManager mocks
- final String testPackageName2 = "com.google.apps.dialer";
- mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
- mockGetApplicationInfo(testPackageName2, TEST_PACKAGE_UID);
-
- // Build OemNetworkPreferences object
- final int testOemPref = OEM_NETWORK_PREFERENCE_OEM_PAID;
- final int testOemPref2 = OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
- final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
- .addNetworkPreference(TEST_PACKAGE_NAME, testOemPref)
- .addNetworkPreference(testPackageName2, testOemPref2)
- .build();
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
- mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(pref);
-
- assertNotNull(nris);
- assertEquals(expectedNumOfNris, nris.size());
- }
-
- @Test
- public void testOemNetworkRequestFactoryMultiplePrefsCorrectlySetsUids()
- throws Exception {
- // Arrange PackageManager mocks
- final String testPackageName2 = "com.google.apps.dialer";
- final int testPackageNameUid2 = 456;
- mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
- mockGetApplicationInfo(testPackageName2, testPackageNameUid2);
-
- // Build OemNetworkPreferences object
- final int testOemPref = OEM_NETWORK_PREFERENCE_OEM_PAID;
- final int testOemPref2 = OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
- final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
- .addNetworkPreference(TEST_PACKAGE_NAME, testOemPref)
- .addNetworkPreference(testPackageName2, testOemPref2)
- .build();
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final List<ConnectivityService.NetworkRequestInfo> nris =
- new ArrayList<>(
- mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(
- pref));
-
- // Sort by uid to access nris by index
- nris.sort(Comparator.comparingInt(nri -> getNriFirstUidRange(nri).getLower()));
- assertEquals(TEST_PACKAGE_UID, (int) getNriFirstUidRange(nris.get(0)).getLower());
- assertEquals(TEST_PACKAGE_UID, (int) getNriFirstUidRange(nris.get(0)).getUpper());
- assertEquals(testPackageNameUid2, (int) getNriFirstUidRange(nris.get(1)).getLower());
- assertEquals(testPackageNameUid2, (int) getNriFirstUidRange(nris.get(1)).getUpper());
- }
-
- @Test
- public void testOemNetworkRequestFactoryMultipleUsersCorrectlySetsUids()
- throws Exception {
- // Arrange users
- final int secondUser = 10;
- final UserHandle secondUserHandle = new UserHandle(secondUser);
- when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE, secondUserHandle));
-
- // Arrange PackageManager mocks
- mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
-
- // Build OemNetworkPreferences object
- final int testOemPref = OEM_NETWORK_PREFERENCE_OEM_PAID;
- final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
- .addNetworkPreference(TEST_PACKAGE_NAME, testOemPref)
- .build();
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final List<ConnectivityService.NetworkRequestInfo> nris =
- new ArrayList<>(
- mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(
- pref));
-
- // UIDs for all users and all managed packages should be present.
- // Two users each with two packages.
- final int expectedUidSize = 2;
- final List<Range<Integer>> uids =
- new ArrayList<>(nris.get(0).mRequests.get(0).networkCapabilities.getUids());
- assertEquals(expectedUidSize, uids.size());
-
- // Sort by uid to access nris by index
- uids.sort(Comparator.comparingInt(uid -> uid.getLower()));
- final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
- assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getLower());
- assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getUpper());
- assertEquals(secondUserTestPackageUid, (int) uids.get(1).getLower());
- assertEquals(secondUserTestPackageUid, (int) uids.get(1).getUpper());
- }
-
- @Test
- public void testOemNetworkRequestFactoryAddsPackagesToCorrectPreference()
- throws Exception {
- // Expectations
- final int expectedNumOfNris = 1;
- final int expectedNumOfAppUids = 2;
-
- // Arrange PackageManager mocks
- final String testPackageName2 = "com.google.apps.dialer";
- final int testPackageNameUid2 = 456;
- mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
- mockGetApplicationInfo(testPackageName2, testPackageNameUid2);
-
- // Build OemNetworkPreferences object
- final int testOemPref = OEM_NETWORK_PREFERENCE_OEM_PAID;
- final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
- .addNetworkPreference(TEST_PACKAGE_NAME, testOemPref)
- .addNetworkPreference(testPackageName2, testOemPref)
- .build();
-
- // Act on OemNetworkRequestFactory.createNrisFromOemNetworkPreferences()
- final ArraySet<ConnectivityService.NetworkRequestInfo> nris =
- mService.new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(pref);
-
- assertEquals(expectedNumOfNris, nris.size());
- assertEquals(expectedNumOfAppUids,
- nris.iterator().next().mRequests.get(0).networkCapabilities.getUids().size());
- }
-
- @Test
- public void testSetOemNetworkPreferenceNullListenerAndPrefParamThrowsNpe() {
- mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
-
- // Act on ConnectivityService.setOemNetworkPreference()
- assertThrows(NullPointerException.class,
- () -> mService.setOemNetworkPreference(
- null,
- null));
- }
-
- @Test
- public void testSetOemNetworkPreferenceFailsForNonAutomotive()
- throws Exception {
- mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, false);
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
-
- // Act on ConnectivityService.setOemNetworkPreference()
- assertThrows(UnsupportedOperationException.class,
- () -> mService.setOemNetworkPreference(
- createDefaultOemNetworkPreferences(networkPref),
- new TestOemListenerCallback()));
- }
-
- private void setOemNetworkPreferenceAgentConnected(final int transportType,
- final boolean connectAgent) throws Exception {
- switch(transportType) {
- // Corresponds to a metered cellular network. Will be used for the default network.
- case TRANSPORT_CELLULAR:
- if (!connectAgent) {
- mCellNetworkAgent.disconnect();
- break;
- }
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
- mCellNetworkAgent.connect(true);
- break;
- // Corresponds to a restricted ethernet network with OEM_PAID/OEM_PRIVATE.
- case TRANSPORT_ETHERNET:
- if (!connectAgent) {
- stopOemManagedNetwork();
- break;
- }
- startOemManagedNetwork(true);
- break;
- // Corresponds to unmetered Wi-Fi.
- case TRANSPORT_WIFI:
- if (!connectAgent) {
- mWiFiNetworkAgent.disconnect();
- break;
- }
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.connect(true);
- break;
- default:
- throw new AssertionError("Unsupported transport type passed in.");
-
- }
- waitForIdle();
- }
-
- private void startOemManagedNetwork(final boolean isOemPaid) throws Exception {
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
- mEthernetNetworkAgent.addCapability(
- isOemPaid ? NET_CAPABILITY_OEM_PAID : NET_CAPABILITY_OEM_PRIVATE);
- mEthernetNetworkAgent.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- mEthernetNetworkAgent.connect(true);
- }
-
- private void stopOemManagedNetwork() {
- mEthernetNetworkAgent.disconnect();
- waitForIdle();
- }
-
- private void verifyMultipleDefaultNetworksTracksCorrectly(
- final int expectedOemRequestsSize,
- @NonNull final Network expectedDefaultNetwork,
- @NonNull final Network expectedPerAppNetwork) {
- // The current test setup assumes two tracked default network requests; one for the default
- // network and the other for the OEM network preference being tested. This will be validated
- // each time to confirm it doesn't change under test.
- final int expectedDefaultNetworkRequestsSize = 2;
- assertEquals(expectedDefaultNetworkRequestsSize, mService.mDefaultNetworkRequests.size());
- for (final ConnectivityService.NetworkRequestInfo defaultRequest
- : mService.mDefaultNetworkRequests) {
- final Network defaultNetwork = defaultRequest.getSatisfier() == null
- ? null : defaultRequest.getSatisfier().network();
- // If this is the default request.
- if (defaultRequest == mService.mDefaultRequest) {
- assertEquals(
- expectedDefaultNetwork,
- defaultNetwork);
- // Make sure this value doesn't change.
- assertEquals(1, defaultRequest.mRequests.size());
- continue;
- }
- assertEquals(expectedPerAppNetwork, defaultNetwork);
- assertEquals(expectedOemRequestsSize, defaultRequest.mRequests.size());
- }
- verifyMultipleDefaultCallbacks(expectedDefaultNetwork, expectedPerAppNetwork);
- }
-
- /**
- * Verify default callbacks for 'available' fire as expected. This will only run if
- * registerDefaultNetworkCallbacks() was executed prior and will only be different if the
- * setOemNetworkPreference() per-app API was used for the current process.
- * @param expectedSystemDefault the expected network for the system default.
- * @param expectedPerAppDefault the expected network for the current process's default.
- */
- private void verifyMultipleDefaultCallbacks(
- @NonNull final Network expectedSystemDefault,
- @NonNull final Network expectedPerAppDefault) {
- if (null != mSystemDefaultNetworkCallback && null != expectedSystemDefault
- && mService.mNoServiceNetwork.network() != expectedSystemDefault) {
- // getLastAvailableNetwork() is used as this method can be called successively with
- // the same network to validate therefore expectAvailableThenValidatedCallbacks
- // can't be used.
- assertEquals(mSystemDefaultNetworkCallback.getLastAvailableNetwork(),
- expectedSystemDefault);
- }
- if (null != mDefaultNetworkCallback && null != expectedPerAppDefault
- && mService.mNoServiceNetwork.network() != expectedPerAppDefault) {
- assertEquals(mDefaultNetworkCallback.getLastAvailableNetwork(),
- expectedPerAppDefault);
- }
- }
-
- private void registerDefaultNetworkCallbacks() {
- // Using Manifest.permission.NETWORK_SETTINGS for registerSystemDefaultNetworkCallback()
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
- mSystemDefaultNetworkCallback = new TestNetworkCallback();
- mDefaultNetworkCallback = new TestNetworkCallback();
- mProfileDefaultNetworkCallback = new TestNetworkCallback();
- mCm.registerSystemDefaultNetworkCallback(mSystemDefaultNetworkCallback,
- new Handler(ConnectivityThread.getInstanceLooper()));
- mCm.registerDefaultNetworkCallback(mDefaultNetworkCallback);
- registerDefaultNetworkCallbackAsUid(mProfileDefaultNetworkCallback,
- TEST_WORK_PROFILE_APP_UID);
- // TODO: test using ConnectivityManager#registerDefaultNetworkCallbackAsUid as well.
- mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
- }
-
- private void unregisterDefaultNetworkCallbacks() {
- if (null != mDefaultNetworkCallback) {
- mCm.unregisterNetworkCallback(mDefaultNetworkCallback);
- }
- if (null != mSystemDefaultNetworkCallback) {
- mCm.unregisterNetworkCallback(mSystemDefaultNetworkCallback);
- }
- if (null != mProfileDefaultNetworkCallback) {
- mCm.unregisterNetworkCallback(mProfileDefaultNetworkCallback);
- }
- }
-
- private void setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(
- @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup)
- throws Exception {
- final int testPackageNameUid = TEST_PACKAGE_UID;
- final String testPackageName = "per.app.defaults.package";
- setupMultipleDefaultNetworksForOemNetworkPreferenceTest(
- networkPrefToSetup, testPackageNameUid, testPackageName);
- }
-
- private void setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(
- @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup)
- throws Exception {
- final int testPackageNameUid = Process.myUid();
- final String testPackageName = "per.app.defaults.package";
- setupMultipleDefaultNetworksForOemNetworkPreferenceTest(
- networkPrefToSetup, testPackageNameUid, testPackageName);
- }
-
- private void setupMultipleDefaultNetworksForOemNetworkPreferenceTest(
- @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup,
- final int testPackageUid, @NonNull final String testPackageName) throws Exception {
- // Only the default request should be included at start.
- assertEquals(1, mService.mDefaultNetworkRequests.size());
-
- final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUids(testPackageUid));
- setupSetOemNetworkPreferenceForPreferenceTest(
- networkPrefToSetup, uidRanges, testPackageName);
- }
-
- private void setupSetOemNetworkPreferenceForPreferenceTest(
- @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup,
- @NonNull final UidRangeParcel[] uidRanges,
- @NonNull final String testPackageName)
- throws Exception {
- // These tests work off a single UID therefore using 'start' is valid.
- mockGetApplicationInfo(testPackageName, uidRanges[0].start);
-
- setOemNetworkPreference(networkPrefToSetup, testPackageName);
- }
-
- private void setOemNetworkPreference(final int networkPrefToSetup,
- @NonNull final String... testPackageNames)
- throws Exception {
- mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
-
- // Build OemNetworkPreferences object
- final OemNetworkPreferences.Builder builder = new OemNetworkPreferences.Builder();
- for (final String packageName : testPackageNames) {
- builder.addNetworkPreference(packageName, networkPrefToSetup);
- }
- final OemNetworkPreferences pref = builder.build();
-
- // Act on ConnectivityService.setOemNetworkPreference()
- final TestOemListenerCallback oemPrefListener = new TestOemListenerCallback();
- mService.setOemNetworkPreference(pref, oemPrefListener);
-
- // Verify call returned successfully
- oemPrefListener.expectOnComplete();
- }
-
- private static class TestOemListenerCallback implements IOnCompleteListener {
- final CompletableFuture<Object> mDone = new CompletableFuture<>();
-
- @Override
- public void onComplete() {
- mDone.complete(new Object());
- }
-
- void expectOnComplete() {
- try {
- mDone.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (TimeoutException e) {
- fail("Expected onComplete() not received after " + TIMEOUT_MS + " ms");
- } catch (Exception e) {
- fail(e.getMessage());
- }
- }
-
- @Override
- public IBinder asBinder() {
- return null;
- }
- }
-
- @Test
- public void testMultiDefaultGetActiveNetworkIsCorrect() throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
- final int expectedOemPrefRequestSize = 1;
- registerDefaultNetworkCallbacks();
-
- // Setup the test process to use networkPref for their default network.
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- // The active network for the default should be null at this point as this is a retricted
- // network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mEthernetNetworkAgent.getNetwork());
-
- // Verify that the active network is correct
- verifyActiveNetwork(TRANSPORT_ETHERNET);
- // default NCs will be unregistered in tearDown
- }
-
- @Test
- public void testMultiDefaultIsActiveNetworkMeteredIsCorrect() throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
- final int expectedOemPrefRequestSize = 1;
- registerDefaultNetworkCallbacks();
-
- // Setup the test process to use networkPref for their default network.
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
-
- // Returns true by default when no network is available.
- assertTrue(mCm.isActiveNetworkMetered());
-
- // Connect to an unmetered restricted network that will only be available to the OEM pref.
- mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
- mEthernetNetworkAgent.addCapability(NET_CAPABILITY_OEM_PAID);
- mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mEthernetNetworkAgent.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- mEthernetNetworkAgent.connect(true);
- waitForIdle();
-
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mEthernetNetworkAgent.getNetwork());
-
- assertFalse(mCm.isActiveNetworkMetered());
- // default NCs will be unregistered in tearDown
- }
-
- @Test
- public void testPerAppDefaultRegisterDefaultNetworkCallback() throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
- final int expectedOemPrefRequestSize = 1;
- final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
-
- // Register the default network callback before the pref is already set. This means that
- // the policy will be applied to the callback on setOemNetworkPreference().
- mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
- defaultNetworkCallback.assertNoCallback();
-
- final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
- withPermission(NETWORK_SETTINGS, () ->
- mCm.registerDefaultNetworkCallbackForUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
- new Handler(ConnectivityThread.getInstanceLooper())));
-
- // Setup the test process to use networkPref for their default network.
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- // The active nai for the default is null at this point as this is a restricted network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mEthernetNetworkAgent.getNetwork());
-
- // At this point with a restricted network used, the available callback should trigger.
- defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
- mEthernetNetworkAgent.getNetwork());
- otherUidDefaultCallback.assertNoCallback();
-
- // Now bring down the default network which should trigger a LOST callback.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
-
- // At this point, with no network is available, the lost callback should trigger
- defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
- otherUidDefaultCallback.assertNoCallback();
-
- // Confirm we can unregister without issues.
- mCm.unregisterNetworkCallback(defaultNetworkCallback);
- mCm.unregisterNetworkCallback(otherUidDefaultCallback);
- }
-
- @Test
- public void testPerAppDefaultRegisterDefaultNetworkCallbackAfterPrefSet() throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
- final int expectedOemPrefRequestSize = 1;
- final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
-
- // Setup the test process to use networkPref for their default network.
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
-
- // Register the default network callback after the pref is already set. This means that
- // the policy will be applied to the callback on requestNetwork().
- mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
- defaultNetworkCallback.assertNoCallback();
-
- final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
- withPermission(NETWORK_SETTINGS, () ->
- mCm.registerDefaultNetworkCallbackForUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
- new Handler(ConnectivityThread.getInstanceLooper())));
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- // The active nai for the default is null at this point as this is a restricted network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mEthernetNetworkAgent.getNetwork());
-
- // At this point with a restricted network used, the available callback should trigger
- defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
- mEthernetNetworkAgent.getNetwork());
- otherUidDefaultCallback.assertNoCallback();
-
- // Now bring down the default network which should trigger a LOST callback.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- otherUidDefaultCallback.assertNoCallback();
-
- // At this point, with no network is available, the lost callback should trigger
- defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
- otherUidDefaultCallback.assertNoCallback();
-
- // Confirm we can unregister without issues.
- mCm.unregisterNetworkCallback(defaultNetworkCallback);
- mCm.unregisterNetworkCallback(otherUidDefaultCallback);
- }
-
- @Test
- public void testPerAppDefaultRegisterDefaultNetworkCallbackDoesNotFire() throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
- final int expectedOemPrefRequestSize = 1;
- final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
- final int userId = UserHandle.getUserId(Process.myUid());
-
- mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
- defaultNetworkCallback.assertNoCallback();
-
- final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
- withPermission(NETWORK_SETTINGS, () ->
- mCm.registerDefaultNetworkCallbackForUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
- new Handler(ConnectivityThread.getInstanceLooper())));
-
- // Setup a process different than the test process to use the default network. This means
- // that the defaultNetworkCallback won't be tracked by the per-app policy.
- setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(networkPref);
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- // The active nai for the default is null at this point as this is a restricted network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mEthernetNetworkAgent.getNetwork());
-
- // As this callback does not have access to the OEM_PAID network, it will not fire.
- defaultNetworkCallback.assertNoCallback();
- assertDefaultNetworkCapabilities(userId /* no networks */);
-
- // The other UID does have access, and gets a callback.
- otherUidDefaultCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
-
- // Bring up unrestricted cellular. This should now satisfy the default network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // At this point with an unrestricted network used, the available callback should trigger
- // The other UID is unaffected and remains on the paid network.
- defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
- mCellNetworkAgent.getNetwork());
- assertDefaultNetworkCapabilities(userId, mCellNetworkAgent);
- otherUidDefaultCallback.assertNoCallback();
-
- // Now bring down the per-app network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
-
- // Since the callback didn't use the per-app network, only the other UID gets a callback.
- // Because the preference specifies no fallback, it does not switch to cellular.
- defaultNetworkCallback.assertNoCallback();
- otherUidDefaultCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
-
- // Now bring down the default network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
-
- // As this callback was tracking the default, this should now trigger.
- defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- otherUidDefaultCallback.assertNoCallback();
-
- // Confirm we can unregister without issues.
- mCm.unregisterNetworkCallback(defaultNetworkCallback);
- mCm.unregisterNetworkCallback(otherUidDefaultCallback);
- }
-
- /**
- * This method assumes that the same uidRanges input will be used to verify that dependencies
- * are called as expected.
- */
- private void verifySetOemNetworkPreferenceForPreference(
- @NonNull final UidRangeParcel[] uidRanges,
- final int addUidRangesNetId,
- final int addUidRangesTimes,
- final int removeUidRangesNetId,
- final int removeUidRangesTimes,
- final boolean shouldDestroyNetwork) throws RemoteException {
- verifySetOemNetworkPreferenceForPreference(uidRanges, uidRanges,
- addUidRangesNetId, addUidRangesTimes, removeUidRangesNetId, removeUidRangesTimes,
- shouldDestroyNetwork);
- }
-
- private void verifySetOemNetworkPreferenceForPreference(
- @NonNull final UidRangeParcel[] addedUidRanges,
- @NonNull final UidRangeParcel[] removedUidRanges,
- final int addUidRangesNetId,
- final int addUidRangesTimes,
- final int removeUidRangesNetId,
- final int removeUidRangesTimes,
- final boolean shouldDestroyNetwork) throws RemoteException {
- final boolean useAnyIdForAdd = OEM_PREF_ANY_NET_ID == addUidRangesNetId;
- final boolean useAnyIdForRemove = OEM_PREF_ANY_NET_ID == removeUidRangesNetId;
-
- // Validate netd.
- verify(mMockNetd, times(addUidRangesTimes))
- .networkAddUidRanges(
- (useAnyIdForAdd ? anyInt() : eq(addUidRangesNetId)), eq(addedUidRanges));
- verify(mMockNetd, times(removeUidRangesTimes))
- .networkRemoveUidRanges(
- (useAnyIdForRemove ? anyInt() : eq(removeUidRangesNetId)),
- eq(removedUidRanges));
- if (shouldDestroyNetwork) {
- verify(mMockNetd, times(1))
- .networkDestroy((useAnyIdForRemove ? anyInt() : eq(removeUidRangesNetId)));
- }
- reset(mMockNetd);
- }
-
- /**
- * Test the tracked default requests clear previous OEM requests on setOemNetworkPreference().
- */
- @Test
- public void testSetOemNetworkPreferenceClearPreviousOemValues() throws Exception {
- @OemNetworkPreferences.OemNetworkPreference int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID;
- final int testPackageUid = 123;
- final String testPackageName = "com.google.apps.contacts";
- final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUids(testPackageUid));
-
- // Validate the starting requests only includes the fallback request.
- assertEquals(1, mService.mDefaultNetworkRequests.size());
-
- // Add an OEM default network request to track.
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, testPackageName);
-
- // Two requests should exist, one for the fallback and one for the pref.
- assertEquals(2, mService.mDefaultNetworkRequests.size());
-
- networkPref = OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, testPackageName);
-
- // Two requests should still exist validating the previous per-app request was replaced.
- assertEquals(2, mService.mDefaultNetworkRequests.size());
- }
-
- /**
- * Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID in the following order:
- * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID -> fallback
- */
- @Test
- public void testMultilayerForPreferenceOemPaidEvaluatesCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID;
-
- // Arrange PackageManager mocks
- final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
-
- // Verify the starting state. No networks should be connected.
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Test lowest to highest priority requests.
- // Bring up metered cellular. This will satisfy the fallback network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mWiFiNetworkAgent.getNetwork().netId, 1 /* times */,
- mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Disconnecting OEM_PAID should have no effect as it is lower in priority then unmetered.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- // netd should not be called as default networks haven't changed.
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Disconnecting unmetered should put PANS on lowest priority fallback request.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- mWiFiNetworkAgent.getNetwork().netId, 0 /* times */,
- true /* shouldDestroyNetwork */);
-
- // Disconnecting the fallback network should result in no connectivity.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- mCellNetworkAgent.getNetwork().netId, 0 /* times */,
- true /* shouldDestroyNetwork */);
- }
-
- /**
- * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK in the following order:
- * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID
- */
- @Test
- public void testMultilayerForPreferenceOemPaidNoFallbackEvaluatesCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
-
- // Arrange PackageManager mocks
- final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
-
- // Verify the starting state. This preference doesn't support using the fallback network
- // therefore should be on the disconnected network as it has no networks to connect to.
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Test lowest to highest priority requests.
- // Bring up metered cellular. This will satisfy the fallback network.
- // This preference should not use this network as it doesn't support fallback usage.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mWiFiNetworkAgent.getNetwork().netId, 1 /* times */,
- mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Disconnecting unmetered should put PANS on OEM_PAID.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
- mWiFiNetworkAgent.getNetwork().netId, 0 /* times */,
- true /* shouldDestroyNetwork */);
-
- // Disconnecting OEM_PAID should result in no connectivity.
- // OEM_PAID_NO_FALLBACK not supporting a fallback now uses the disconnected network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- mEthernetNetworkAgent.getNetwork().netId, 0 /* times */,
- true /* shouldDestroyNetwork */);
- }
-
- /**
- * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY in the following order:
- * NET_CAPABILITY_OEM_PAID
- * This preference should only apply to OEM_PAID networks.
- */
- @Test
- public void testMultilayerForPreferenceOemPaidOnlyEvaluatesCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
-
- // Arrange PackageManager mocks
- final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
-
- // Verify the starting state. This preference doesn't support using the fallback network
- // therefore should be on the disconnected network as it has no networks to connect to.
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up metered cellular. This should not apply to this preference.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up unmetered Wi-Fi. This should not apply to this preference.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Disconnecting OEM_PAID should result in no connectivity.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- mEthernetNetworkAgent.getNetwork().netId, 0 /* times */,
- true /* shouldDestroyNetwork */);
- }
-
- /**
- * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY in the following order:
- * NET_CAPABILITY_OEM_PRIVATE
- * This preference should only apply to OEM_PRIVATE networks.
- */
- @Test
- public void testMultilayerForPreferenceOemPrivateOnlyEvaluatesCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
-
- // Arrange PackageManager mocks
- final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
-
- // Verify the starting state. This preference doesn't support using the fallback network
- // therefore should be on the disconnected network as it has no networks to connect to.
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up metered cellular. This should not apply to this preference.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up unmetered Wi-Fi. This should not apply to this preference.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Bring up ethernet with OEM_PRIVATE. This will satisfy NET_CAPABILITY_OEM_PRIVATE.
- startOemManagedNetwork(false);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mEthernetNetworkAgent.getNetwork().netId, 1 /* times */,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Disconnecting OEM_PRIVATE should result in no connectivity.
- stopOemManagedNetwork();
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mService.mNoServiceNetwork.network.getNetId(), 1 /* times */,
- mEthernetNetworkAgent.getNetwork().netId, 0 /* times */,
- true /* shouldDestroyNetwork */);
- }
-
- @Test
- public void testMultilayerForMultipleUsersEvaluatesCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID;
-
- // Arrange users
- final int secondUser = 10;
- final UserHandle secondUserHandle = new UserHandle(secondUser);
- when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE, secondUserHandle));
-
- // Arrange PackageManager mocks
- final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
- final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(
- uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid));
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
-
- // Verify the starting state. No networks should be connected.
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Test that we correctly add the expected values for multiple users.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Test that we correctly remove the expected values for multiple users.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
- verifySetOemNetworkPreferenceForPreference(uidRanges,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- mCellNetworkAgent.getNetwork().netId, 0 /* times */,
- true /* shouldDestroyNetwork */);
- }
-
- @Test
- public void testMultilayerForBroadcastedUsersEvaluatesCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID;
-
- // Arrange users
- final int secondUser = 10;
- final UserHandle secondUserHandle = new UserHandle(secondUser);
- when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE));
-
- // Arrange PackageManager mocks
- final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
- final UidRangeParcel[] uidRangesSingleUser =
- toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
- final UidRangeParcel[] uidRangesBothUsers =
- toUidRangeStableParcels(
- uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid));
- setupSetOemNetworkPreferenceForPreferenceTest(
- networkPref, uidRangesSingleUser, TEST_PACKAGE_NAME);
-
- // Verify the starting state. No networks should be connected.
- verifySetOemNetworkPreferenceForPreference(uidRangesSingleUser,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Test that we correctly add the expected values for multiple users.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifySetOemNetworkPreferenceForPreference(uidRangesSingleUser,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Send a broadcast indicating a user was added.
- when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE, secondUserHandle));
- final Intent addedIntent = new Intent(ACTION_USER_ADDED);
- addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(secondUser));
- processBroadcast(addedIntent);
-
- // Test that we correctly add values for all users and remove for the single user.
- verifySetOemNetworkPreferenceForPreference(uidRangesBothUsers, uidRangesSingleUser,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Send a broadcast indicating a user was removed.
- when(mUserManager.getUserHandles(anyBoolean())).thenReturn(
- Arrays.asList(PRIMARY_USER_HANDLE));
- final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
- removedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(secondUser));
- processBroadcast(removedIntent);
-
- // Test that we correctly add values for the single user and remove for the all users.
- verifySetOemNetworkPreferenceForPreference(uidRangesSingleUser, uidRangesBothUsers,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- false /* shouldDestroyNetwork */);
- }
-
- @Test
- public void testMultilayerForPackageChangesEvaluatesCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID;
- final String packageScheme = "package:";
-
- // Arrange PackageManager mocks
- final String packageToInstall = "package.to.install";
- final int packageToInstallUid = 81387;
- final UidRangeParcel[] uidRangesSinglePackage =
- toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
- mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
- mockGetApplicationInfoThrowsNameNotFound(packageToInstall);
- setOemNetworkPreference(networkPref, TEST_PACKAGE_NAME, packageToInstall);
- grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid(), packageToInstall);
-
- // Verify the starting state. No networks should be connected.
- verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Test that we correctly add the expected values for installed packages.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- OEM_PREF_ANY_NET_ID, 0 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Set the system to recognize the package to be installed
- mockGetApplicationInfo(packageToInstall, packageToInstallUid);
- final UidRangeParcel[] uidRangesAllPackages =
- toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID, packageToInstallUid));
-
- // Send a broadcast indicating a package was installed.
- final Intent addedIntent = new Intent(ACTION_PACKAGE_ADDED);
- addedIntent.setData(Uri.parse(packageScheme + packageToInstall));
- processBroadcast(addedIntent);
-
- // Test the single package is removed and the combined packages are added.
- verifySetOemNetworkPreferenceForPreference(uidRangesAllPackages, uidRangesSinglePackage,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Set the system to no longer recognize the package to be installed
- mockGetApplicationInfoThrowsNameNotFound(packageToInstall);
-
- // Send a broadcast indicating a package was removed.
- final Intent removedIntent = new Intent(ACTION_PACKAGE_REMOVED);
- removedIntent.setData(Uri.parse(packageScheme + packageToInstall));
- processBroadcast(removedIntent);
-
- // Test the combined packages are removed and the single package is added.
- verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage, uidRangesAllPackages,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- false /* shouldDestroyNetwork */);
-
- // Set the system to change the installed package's uid
- final int replacedTestPackageUid = TEST_PACKAGE_UID + 1;
- mockGetApplicationInfo(TEST_PACKAGE_NAME, replacedTestPackageUid);
- final UidRangeParcel[] uidRangesReplacedPackage =
- toUidRangeStableParcels(uidRangesForUids(replacedTestPackageUid));
-
- // Send a broadcast indicating a package was replaced.
- final Intent replacedIntent = new Intent(ACTION_PACKAGE_REPLACED);
- replacedIntent.setData(Uri.parse(packageScheme + TEST_PACKAGE_NAME));
- processBroadcast(replacedIntent);
-
- // Test the original uid is removed and is replaced with the new uid.
- verifySetOemNetworkPreferenceForPreference(uidRangesReplacedPackage, uidRangesSinglePackage,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- mCellNetworkAgent.getNetwork().netId, 1 /* times */,
- false /* shouldDestroyNetwork */);
- }
-
- /**
- * Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID in the following order:
- * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID -> fallback
- */
- @Test
- public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPaidCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
- final int expectedDefaultRequestSize = 2;
- final int expectedOemPrefRequestSize = 3;
- registerDefaultNetworkCallbacks();
-
- // The fallback as well as the OEM preference should now be tracked.
- assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size());
-
- // Test lowest to highest priority requests.
- // Bring up metered cellular. This will satisfy the fallback network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mCellNetworkAgent.getNetwork());
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mWiFiNetworkAgent.getNetwork(),
- mWiFiNetworkAgent.getNetwork());
-
- // Disconnecting unmetered Wi-Fi will put the pref on OEM_PAID and fallback on cellular.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Disconnecting cellular should keep OEM network on OEM_PAID and fallback will be null.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mEthernetNetworkAgent.getNetwork());
-
- // Disconnecting OEM_PAID will put both on null as it is the last network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- null);
-
- // default callbacks will be unregistered in tearDown
- }
-
- @Test
- public void testNetworkFactoryRequestsWithMultilayerRequest()
- throws Exception {
- // First use OEM_PAID preference to create a multi-layer request : 1. listen for
- // unmetered, 2. request network with cap OEM_PAID, 3, request the default network for
- // fallback.
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
-
- final HandlerThread handlerThread = new HandlerThread("MockFactory");
- handlerThread.start();
- NetworkCapabilities internetFilter = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- final MockNetworkFactory internetFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "internetFactory", internetFilter, mCsHandlerThread);
- internetFactory.setScoreFilter(40);
- internetFactory.register();
- // Default internet request only. The unmetered request is never sent to factories (it's a
- // LISTEN, not requestable). The 3rd (fallback) request in OEM_PAID NRI is TRACK_DEFAULT
- // which is also not sent to factories. Finally, the OEM_PAID request doesn't match the
- // internetFactory filter.
- internetFactory.expectRequestAdds(1);
- internetFactory.assertRequestCountEquals(1);
-
- NetworkCapabilities oemPaidFilter = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_OEM_PAID)
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
- .removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- final MockNetworkFactory oemPaidFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "oemPaidFactory", oemPaidFilter, mCsHandlerThread);
- oemPaidFactory.setScoreFilter(40);
- oemPaidFactory.register();
- oemPaidFactory.expectRequestAdd(); // Because nobody satisfies the request
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- // A network connected that satisfies the default internet request. For the OEM_PAID
- // preference, this is not as good as an OEM_PAID network, so even if the score of
- // the network is better than the factory announced, it still should try to bring up
- // the network.
- expectNoRequestChanged(oemPaidFactory);
- oemPaidFactory.assertRequestCountEquals(1);
- // The internet factory however is outscored, and should lose its requests.
- internetFactory.expectRequestRemove();
- internetFactory.assertRequestCountEquals(0);
-
- final NetworkCapabilities oemPaidNc = new NetworkCapabilities();
- oemPaidNc.addCapability(NET_CAPABILITY_OEM_PAID);
- oemPaidNc.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- final TestNetworkAgentWrapper oemPaidAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR,
- new LinkProperties(), oemPaidNc);
- oemPaidAgent.connect(true);
-
- // The oemPaidAgent has score 50/cell transport, so it beats what the oemPaidFactory can
- // provide, therefore it loses the request.
- oemPaidFactory.expectRequestRemove();
- oemPaidFactory.assertRequestCountEquals(0);
- expectNoRequestChanged(internetFactory);
- internetFactory.assertRequestCountEquals(0);
-
- oemPaidAgent.setScore(new NetworkScore.Builder().setLegacyInt(20).setExiting(true).build());
- // Now the that the agent is weak, the oemPaidFactory can beat the existing network for the
- // OEM_PAID request. The internet factory however can't beat a network that has OEM_PAID
- // for the preference request, so it doesn't see the request.
- oemPaidFactory.expectRequestAdd();
- oemPaidFactory.assertRequestCountEquals(1);
- expectNoRequestChanged(internetFactory);
- internetFactory.assertRequestCountEquals(0);
-
- mCellNetworkAgent.disconnect();
- // The network satisfying the default internet request has disconnected, so the
- // internetFactory sees the default request again. However there is a network with OEM_PAID
- // connected, so the 2nd OEM_PAID req is already satisfied, so the oemPaidFactory doesn't
- // care about networks that don't have OEM_PAID.
- expectNoRequestChanged(oemPaidFactory);
- oemPaidFactory.assertRequestCountEquals(1);
- internetFactory.expectRequestAdd();
- internetFactory.assertRequestCountEquals(1);
-
- // Cell connects again, still with score 50. Back to the previous state.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- expectNoRequestChanged(oemPaidFactory);
- oemPaidFactory.assertRequestCountEquals(1);
- internetFactory.expectRequestRemove();
- internetFactory.assertRequestCountEquals(0);
-
- // Create a request that holds the upcoming wifi network.
- final TestNetworkCallback wifiCallback = new TestNetworkCallback();
- mCm.requestNetwork(new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build(),
- wifiCallback);
-
- // Now WiFi connects and it's unmetered, but it's weaker than cell.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
- mWiFiNetworkAgent.setScore(new NetworkScore.Builder().setLegacyInt(30).setExiting(true)
- .build()); // Not the best Internet network, but unmetered
- mWiFiNetworkAgent.connect(true);
-
- // The OEM_PAID preference prefers an unmetered network to an OEM_PAID network, so
- // the oemPaidFactory can't beat wifi no matter how high its score.
- oemPaidFactory.expectRequestRemove();
- expectNoRequestChanged(internetFactory);
-
- mCellNetworkAgent.disconnect();
- // Now that the best internet network (cell, with its 50 score compared to 30 for WiFi
- // at this point), the default internet request is satisfied by a network worse than
- // the internetFactory announced, so it gets the request. However, there is still an
- // unmetered network, so the oemPaidNetworkFactory still can't beat this.
- expectNoRequestChanged(oemPaidFactory);
- internetFactory.expectRequestAdd();
- mCm.unregisterNetworkCallback(wifiCallback);
- }
-
- /**
- * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK in the following order:
- * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID
- */
- @Test
- public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPaidNoFallbackCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
- final int expectedDefaultRequestSize = 2;
- final int expectedOemPrefRequestSize = 2;
- registerDefaultNetworkCallbacks();
-
- // The fallback as well as the OEM preference should now be tracked.
- assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size());
-
- // Test lowest to highest priority requests.
- // Bring up metered cellular. This will satisfy the fallback network but not the pref.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mService.mNoServiceNetwork.network());
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mWiFiNetworkAgent.getNetwork(),
- mWiFiNetworkAgent.getNetwork());
-
- // Disconnecting unmetered Wi-Fi will put the OEM pref on OEM_PAID and fallback on cellular.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Disconnecting cellular should keep OEM network on OEM_PAID and fallback will be null.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mEthernetNetworkAgent.getNetwork());
-
- // Disconnecting OEM_PAID puts the fallback on null and the pref on the disconnected net.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mService.mNoServiceNetwork.network());
-
- // default callbacks will be unregistered in tearDown
- }
-
- /**
- * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY in the following order:
- * NET_CAPABILITY_OEM_PAID
- * This preference should only apply to OEM_PAID networks.
- */
- @Test
- public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPaidOnlyCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
- final int expectedDefaultRequestSize = 2;
- final int expectedOemPrefRequestSize = 1;
- registerDefaultNetworkCallbacks();
-
- // The fallback as well as the OEM preference should now be tracked.
- assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size());
-
- // Test lowest to highest priority requests.
- // Bring up metered cellular. This will satisfy the fallback network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mService.mNoServiceNetwork.network());
-
- // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Bring up unmetered Wi-Fi. The OEM network shouldn't change, the fallback will take Wi-Fi.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mWiFiNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Disconnecting unmetered Wi-Fi shouldn't change the OEM network with fallback on cellular.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Disconnecting OEM_PAID will keep the fallback on cellular and nothing for OEM_PAID.
- // OEM_PAID_ONLY not supporting a fallback now uses the disconnected network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mService.mNoServiceNetwork.network());
-
- // Disconnecting cellular will put the fallback on null and the pref on disconnected.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mService.mNoServiceNetwork.network());
-
- // default callbacks will be unregistered in tearDown
- }
-
- /**
- * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY in the following order:
- * NET_CAPABILITY_OEM_PRIVATE
- * This preference should only apply to OEM_PRIVATE networks.
- */
- @Test
- public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPrivateOnlyCorrectly()
- throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
- setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
- final int expectedDefaultRequestSize = 2;
- final int expectedOemPrefRequestSize = 1;
- registerDefaultNetworkCallbacks();
-
- // The fallback as well as the OEM preference should now be tracked.
- assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size());
-
- // Test lowest to highest priority requests.
- // Bring up metered cellular. This will satisfy the fallback network.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mService.mNoServiceNetwork.network());
-
- // Bring up ethernet with OEM_PRIVATE. This will satisfy NET_CAPABILITY_OEM_PRIVATE.
- startOemManagedNetwork(false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Bring up unmetered Wi-Fi. The OEM network shouldn't change, the fallback will take Wi-Fi.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mWiFiNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Disconnecting unmetered Wi-Fi shouldn't change the OEM network with fallback on cellular.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mEthernetNetworkAgent.getNetwork());
-
- // Disconnecting OEM_PRIVATE will keep the fallback on cellular.
- // OEM_PRIVATE_ONLY not supporting a fallback now uses to the disconnected network.
- stopOemManagedNetwork();
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- mCellNetworkAgent.getNetwork(),
- mService.mNoServiceNetwork.network());
-
- // Disconnecting cellular will put the fallback on null and pref on disconnected.
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
- verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
- null,
- mService.mNoServiceNetwork.network());
-
- // default callbacks will be unregistered in tearDown
- }
-
- @Test
- public void testCapabilityWithOemNetworkPreference() throws Exception {
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
- setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(networkPref);
- registerDefaultNetworkCallbacks();
-
- setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
-
- mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-
- mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
- mSystemDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc ->
- nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
- mDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc ->
- nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
-
- // default callbacks will be unregistered in tearDown
- }
-
- @Test
- public void testSetOemNetworkPreferenceLogsRequest() throws Exception {
- mServiceContext.setPermission(DUMP, PERMISSION_GRANTED);
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PAID;
- final StringWriter stringWriter = new StringWriter();
- final String logIdentifier = "UPDATE INITIATED: OemNetworkPreferences";
- final Pattern pattern = Pattern.compile(logIdentifier);
-
- final int expectedNumLogs = 2;
- final UidRangeParcel[] uidRanges =
- toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
-
- // Call twice to generate two logs.
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
- setupSetOemNetworkPreferenceForPreferenceTest(networkPref, uidRanges, TEST_PACKAGE_NAME);
- mService.dump(new FileDescriptor(), new PrintWriter(stringWriter), new String[0]);
-
- final String dumpOutput = stringWriter.toString();
- final Matcher matcher = pattern.matcher(dumpOutput);
- int count = 0;
- while (matcher.find()) {
- count++;
- }
- assertEquals(expectedNumLogs, count);
- }
-
- @Test
- public void testGetAllNetworkStateSnapshots() throws Exception {
- verifyNoNetwork();
-
- // Setup test cellular network with specified LinkProperties and NetworkCapabilities,
- // verify the content of the snapshot matches.
- final LinkProperties cellLp = new LinkProperties();
- final LinkAddress myIpv4Addr = new LinkAddress(InetAddress.getByName("192.0.2.129"), 25);
- final LinkAddress myIpv6Addr = new LinkAddress(InetAddress.getByName("2001:db8::1"), 64);
- cellLp.setInterfaceName("test01");
- cellLp.addLinkAddress(myIpv4Addr);
- cellLp.addLinkAddress(myIpv6Addr);
- cellLp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
- cellLp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
- cellLp.addRoute(new RouteInfo(myIpv4Addr, null));
- cellLp.addRoute(new RouteInfo(myIpv6Addr, null));
- final NetworkCapabilities cellNcTemplate = new NetworkCapabilities.Builder()
- .addTransportType(TRANSPORT_CELLULAR).addCapability(NET_CAPABILITY_MMS).build();
-
- final TestNetworkCallback cellCb = new TestNetworkCallback();
- mCm.requestNetwork(new NetworkRequest.Builder().addCapability(NET_CAPABILITY_MMS).build(),
- cellCb);
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp, cellNcTemplate);
- mCellNetworkAgent.connect(true);
- cellCb.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
- List<NetworkStateSnapshot> snapshots = mCm.getAllNetworkStateSnapshots();
- assertLength(1, snapshots);
-
- // Compose the expected cellular snapshot for verification.
- final NetworkCapabilities cellNc =
- mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork());
- final NetworkStateSnapshot cellSnapshot = new NetworkStateSnapshot(
- mCellNetworkAgent.getNetwork(), cellNc, cellLp,
- null, ConnectivityManager.TYPE_MOBILE);
- assertEquals(cellSnapshot, snapshots.get(0));
-
- // Connect wifi and verify the snapshots.
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- waitForIdle();
- // Compose the expected wifi snapshot for verification.
- final NetworkCapabilities wifiNc =
- mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork());
- final NetworkStateSnapshot wifiSnapshot = new NetworkStateSnapshot(
- mWiFiNetworkAgent.getNetwork(), wifiNc, new LinkProperties(), null,
- ConnectivityManager.TYPE_WIFI);
-
- snapshots = mCm.getAllNetworkStateSnapshots();
- assertLength(2, snapshots);
- assertContainsAll(snapshots, cellSnapshot, wifiSnapshot);
-
- // Set cellular as suspended, verify the snapshots will not contain suspended networks.
- // TODO: Consider include SUSPENDED networks, which should be considered as
- // temporary shortage of connectivity of a connected network.
- mCellNetworkAgent.suspend();
- waitForIdle();
- snapshots = mCm.getAllNetworkStateSnapshots();
- assertLength(1, snapshots);
- assertEquals(wifiSnapshot, snapshots.get(0));
-
- // Disconnect wifi, verify the snapshots contain nothing.
- mWiFiNetworkAgent.disconnect();
- waitForIdle();
- snapshots = mCm.getAllNetworkStateSnapshots();
- assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertLength(0, snapshots);
-
- mCellNetworkAgent.resume();
- waitForIdle();
- snapshots = mCm.getAllNetworkStateSnapshots();
- assertLength(1, snapshots);
- assertEquals(cellSnapshot, snapshots.get(0));
-
- mCellNetworkAgent.disconnect();
- waitForIdle();
- verifyNoNetwork();
- mCm.unregisterNetworkCallback(cellCb);
- }
-
- // Cannot be part of MockNetworkFactory since it requires method of the test.
- private void expectNoRequestChanged(@NonNull MockNetworkFactory factory) {
- waitForIdle();
- factory.assertNoRequestChanged();
- }
-
- @Test
- public void testRegisterBestMatchingNetworkCallback_noIssueToFactory() throws Exception {
- // Prepare mock mms factory.
- final HandlerThread handlerThread = new HandlerThread("MockCellularFactory");
- handlerThread.start();
- NetworkCapabilities filter = new NetworkCapabilities()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_MMS);
- final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
- mServiceContext, "testFactory", filter, mCsHandlerThread);
- testFactory.setScoreFilter(40);
-
- try {
- // Register the factory. It doesn't see the default request because its filter does
- // not include INTERNET.
- testFactory.register();
- expectNoRequestChanged(testFactory);
- testFactory.assertRequestCountEquals(0);
- // The factory won't try to start the network since the default request doesn't
- // match the filter (no INTERNET capability).
- assertFalse(testFactory.getMyStartRequested());
-
- // Register callback for listening best matching network. Verify that the request won't
- // be sent to factory.
- final TestNetworkCallback bestMatchingCb = new TestNetworkCallback();
- mCm.registerBestMatchingNetworkCallback(
- new NetworkRequest.Builder().addCapability(NET_CAPABILITY_MMS).build(),
- bestMatchingCb, mCsHandlerThread.getThreadHandler());
- bestMatchingCb.assertNoCallback();
- expectNoRequestChanged(testFactory);
- testFactory.assertRequestCountEquals(0);
- assertFalse(testFactory.getMyStartRequested());
-
- // Fire a normal mms request, verify the factory will only see the request.
- final TestNetworkCallback mmsNetworkCallback = new TestNetworkCallback();
- final NetworkRequest mmsRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_MMS).build();
- mCm.requestNetwork(mmsRequest, mmsNetworkCallback);
- testFactory.expectRequestAdd();
- testFactory.assertRequestCountEquals(1);
- assertTrue(testFactory.getMyStartRequested());
-
- // Unregister best matching callback, verify factory see no change.
- mCm.unregisterNetworkCallback(bestMatchingCb);
- expectNoRequestChanged(testFactory);
- testFactory.assertRequestCountEquals(1);
- assertTrue(testFactory.getMyStartRequested());
- } finally {
- testFactory.terminate();
- }
- }
-
- @Test
- public void testRegisterBestMatchingNetworkCallback_trackBestNetwork() throws Exception {
- final TestNetworkCallback bestMatchingCb = new TestNetworkCallback();
- mCm.registerBestMatchingNetworkCallback(
- new NetworkRequest.Builder().addCapability(NET_CAPABILITY_TRUSTED).build(),
- bestMatchingCb, mCsHandlerThread.getThreadHandler());
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- bestMatchingCb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-
- mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- mWiFiNetworkAgent.connect(true);
- bestMatchingCb.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
-
- // Change something on cellular to trigger capabilities changed, since the callback
- // only cares about the best network, verify it received nothing from cellular.
- mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
- bestMatchingCb.assertNoCallback();
-
- // Make cellular the best network again, verify the callback now tracks cellular.
- mWiFiNetworkAgent.adjustScore(-50);
- bestMatchingCb.expectAvailableCallbacksValidated(mCellNetworkAgent);
-
- // Make cellular temporary non-trusted, which will not satisfying the request.
- // Verify the callback switch from/to the other network accordingly.
- mCellNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
- bestMatchingCb.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- mCellNetworkAgent.addCapability(NET_CAPABILITY_TRUSTED);
- bestMatchingCb.expectAvailableDoubleValidatedCallbacks(mCellNetworkAgent);
-
- // Verify the callback doesn't care about wifi disconnect.
- mWiFiNetworkAgent.disconnect();
- bestMatchingCb.assertNoCallback();
- mCellNetworkAgent.disconnect();
- bestMatchingCb.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- }
-
- private UidRangeParcel[] uidRangeFor(final UserHandle handle) {
- UidRange range = UidRange.createForUser(handle);
- return new UidRangeParcel[] { new UidRangeParcel(range.start, range.stop) };
- }
-
- private static class TestOnCompleteListener implements Runnable {
- final class OnComplete {}
- final ArrayTrackRecord<OnComplete>.ReadHead mHistory =
- new ArrayTrackRecord<OnComplete>().newReadHead();
-
- @Override
- public void run() {
- mHistory.add(new OnComplete());
- }
-
- public void expectOnComplete() {
- assertNotNull(mHistory.poll(TIMEOUT_MS, it -> true));
- }
- }
-
- private TestNetworkAgentWrapper makeEnterpriseNetworkAgent() throws Exception {
- final NetworkCapabilities workNc = new NetworkCapabilities();
- workNc.addCapability(NET_CAPABILITY_ENTERPRISE);
- workNc.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- return new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, new LinkProperties(), workNc);
- }
-
- private TestNetworkCallback mEnterpriseCallback;
- private UserHandle setupEnterpriseNetwork() {
- final UserHandle userHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
- mServiceContext.setWorkProfile(userHandle, true);
-
- // File a request to avoid the enterprise network being disconnected as soon as the default
- // request goes away – it would make impossible to test that networkRemoveUidRanges
- // is called, as the network would disconnect first for lack of a request.
- mEnterpriseCallback = new TestNetworkCallback();
- final NetworkRequest keepUpRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_ENTERPRISE)
- .build();
- mCm.requestNetwork(keepUpRequest, mEnterpriseCallback);
- return userHandle;
- }
-
- private void maybeTearDownEnterpriseNetwork() {
- if (null != mEnterpriseCallback) {
- mCm.unregisterNetworkCallback(mEnterpriseCallback);
- }
- }
-
- /**
- * Make sure per-profile networking preference behaves as expected when the enterprise network
- * goes up and down while the preference is active. Make sure they behave as expected whether
- * there is a general default network or not.
- */
- @Test
- public void testPreferenceForUserNetworkUpDown() throws Exception {
- final InOrder inOrder = inOrder(mMockNetd);
- final UserHandle testHandle = setupEnterpriseNetwork();
- registerDefaultNetworkCallbacks();
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
-
-
- final TestOnCompleteListener listener = new TestOnCompleteListener();
- mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- r -> r.run(), listener);
- listener.expectOnComplete();
-
- // Setting a network preference for this user will create a new set of routing rules for
- // the UID range that corresponds to this user, so as to define the default network
- // for these apps separately. This is true because the multi-layer request relevant to
- // this UID range contains a TRACK_DEFAULT, so the range will be moved through UID-specific
- // rules to the correct network – in this case the system default network. The case where
- // the default network for the profile happens to be the same as the system default
- // is not handled specially, the rules are always active as long as a preference is set.
- inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
- uidRangeFor(testHandle));
-
- // The enterprise network is not ready yet.
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
- mProfileDefaultNetworkCallback);
-
- final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent();
- workAgent.connect(false);
-
- mProfileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent);
- mSystemDefaultNetworkCallback.assertNoCallback();
- mDefaultNetworkCallback.assertNoCallback();
- inOrder.verify(mMockNetd).networkCreate(
- nativeNetworkConfigPhysical(workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM));
- inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle));
- inOrder.verify(mMockNetd).networkRemoveUidRanges(mCellNetworkAgent.getNetwork().netId,
- uidRangeFor(testHandle));
-
- // Make sure changes to the work agent send callbacks to the app in the work profile, but
- // not to the other apps.
- workAgent.setNetworkValid(true /* isStrictMode */);
- workAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
- mProfileDefaultNetworkCallback.expectCapabilitiesThat(workAgent,
- nc -> nc.hasCapability(NET_CAPABILITY_VALIDATED)
- && nc.hasCapability(NET_CAPABILITY_ENTERPRISE));
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
-
- workAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
- mProfileDefaultNetworkCallback.expectCapabilitiesThat(workAgent, nc ->
- nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
-
- // Conversely, change a capability on the system-wide default network and make sure
- // that only the apps outside of the work profile receive the callbacks.
- mCellNetworkAgent.addCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED);
- mSystemDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc ->
- nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
- mDefaultNetworkCallback.expectCapabilitiesThat(mCellNetworkAgent, nc ->
- nc.hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
- mProfileDefaultNetworkCallback.assertNoCallback();
-
- // Disconnect and reconnect the system-wide default network and make sure that the
- // apps on this network see the appropriate callbacks, and the app on the work profile
- // doesn't because it continues to use the enterprise network.
- mCellNetworkAgent.disconnect();
- mSystemDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- mProfileDefaultNetworkCallback.assertNoCallback();
- inOrder.verify(mMockNetd).networkDestroy(mCellNetworkAgent.getNetwork().netId);
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
- mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mProfileDefaultNetworkCallback.assertNoCallback();
- inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
-
- // When the agent disconnects, test that the app on the work profile falls back to the
- // default network.
- workAgent.disconnect();
- mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, workAgent);
- mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
- inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
- uidRangeFor(testHandle));
- inOrder.verify(mMockNetd).networkDestroy(workAgent.getNetwork().netId);
-
- mCellNetworkAgent.disconnect();
- mSystemDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- mDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
-
- // Waiting for the handler to be idle before checking for networkDestroy is necessary
- // here because ConnectivityService calls onLost before the network is fully torn down.
- waitForIdle();
- inOrder.verify(mMockNetd).networkDestroy(mCellNetworkAgent.getNetwork().netId);
-
- // If the control comes here, callbacks seem to behave correctly in the presence of
- // a default network when the enterprise network goes up and down. Now, make sure they
- // also behave correctly in the absence of a system-wide default network.
- final TestNetworkAgentWrapper workAgent2 = makeEnterpriseNetworkAgent();
- workAgent2.connect(false);
-
- mProfileDefaultNetworkCallback.expectAvailableCallbacksUnvalidated(workAgent2);
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
- inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- workAgent2.getNetwork().netId, INetd.PERMISSION_SYSTEM));
- inOrder.verify(mMockNetd).networkAddUidRanges(workAgent2.getNetwork().netId,
- uidRangeFor(testHandle));
-
- workAgent2.setNetworkValid(true /* isStrictMode */);
- workAgent2.mNetworkMonitor.forceReevaluation(Process.myUid());
- mProfileDefaultNetworkCallback.expectCapabilitiesThat(workAgent2,
- nc -> nc.hasCapability(NET_CAPABILITY_ENTERPRISE)
- && !nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
- inOrder.verify(mMockNetd, never()).networkAddUidRanges(anyInt(), any());
-
- // When the agent disconnects, test that the app on the work profile falls back to the
- // default network.
- workAgent2.disconnect();
- mProfileDefaultNetworkCallback.expectCallback(CallbackEntry.LOST, workAgent2);
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
- inOrder.verify(mMockNetd).networkDestroy(workAgent2.getNetwork().netId);
-
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
- mProfileDefaultNetworkCallback);
-
- // Callbacks will be unregistered by tearDown()
- }
-
- /**
- * Test that, in a given networking context, calling setPreferenceForUser to set per-profile
- * defaults on then off works as expected.
- */
- @Test
- public void testSetPreferenceForUserOnOff() throws Exception {
- final InOrder inOrder = inOrder(mMockNetd);
- final UserHandle testHandle = setupEnterpriseNetwork();
-
- // Connect both a regular cell agent and an enterprise network first.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent();
- workAgent.connect(true);
-
- final TestOnCompleteListener listener = new TestOnCompleteListener();
- mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- r -> r.run(), listener);
- listener.expectOnComplete();
- inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
- inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle));
-
- registerDefaultNetworkCallbacks();
-
- mSystemDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(workAgent);
-
- mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_DEFAULT,
- r -> r.run(), listener);
- listener.expectOnComplete();
-
- mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback);
- inOrder.verify(mMockNetd).networkRemoveUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle));
-
- workAgent.disconnect();
- mCellNetworkAgent.disconnect();
-
- // Callbacks will be unregistered by tearDown()
- }
-
- /**
- * Test per-profile default networks for two different profiles concurrently.
- */
- @Test
- public void testSetPreferenceForTwoProfiles() throws Exception {
- final InOrder inOrder = inOrder(mMockNetd);
- final UserHandle testHandle2 = setupEnterpriseNetwork();
- final UserHandle testHandle4 = UserHandle.of(TEST_WORK_PROFILE_USER_ID + 2);
- mServiceContext.setWorkProfile(testHandle4, true);
- registerDefaultNetworkCallbacks();
-
- final TestNetworkCallback app4Cb = new TestNetworkCallback();
- final int testWorkProfileAppUid4 =
- UserHandle.getUid(testHandle4.getIdentifier(), TEST_APP_ID);
- registerDefaultNetworkCallbackAsUid(app4Cb, testWorkProfileAppUid4);
-
- // Connect both a regular cell agent and an enterprise network first.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- final TestNetworkAgentWrapper workAgent = makeEnterpriseNetworkAgent();
- workAgent.connect(true);
-
- mSystemDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- mProfileDefaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- app4Cb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
- inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- workAgent.getNetwork().netId, INetd.PERMISSION_SYSTEM));
-
- final TestOnCompleteListener listener = new TestOnCompleteListener();
- mCm.setProfileNetworkPreference(testHandle2, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- r -> r.run(), listener);
- listener.expectOnComplete();
- inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle2));
-
- mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(workAgent);
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
- app4Cb);
-
- mCm.setProfileNetworkPreference(testHandle4, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- r -> r.run(), listener);
- listener.expectOnComplete();
- inOrder.verify(mMockNetd).networkAddUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle4));
-
- app4Cb.expectAvailableCallbacksValidated(workAgent);
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
- mProfileDefaultNetworkCallback);
-
- mCm.setProfileNetworkPreference(testHandle2, PROFILE_NETWORK_PREFERENCE_DEFAULT,
- r -> r.run(), listener);
- listener.expectOnComplete();
- inOrder.verify(mMockNetd).networkRemoveUidRanges(workAgent.getNetwork().netId,
- uidRangeFor(testHandle2));
-
- mProfileDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- assertNoCallbacks(mSystemDefaultNetworkCallback, mDefaultNetworkCallback,
- app4Cb);
-
- workAgent.disconnect();
- mCellNetworkAgent.disconnect();
-
- mCm.unregisterNetworkCallback(app4Cb);
- // Other callbacks will be unregistered by tearDown()
- }
-
- @Test
- public void testProfilePreferenceRemovedUponUserRemoved() throws Exception {
- final InOrder inOrder = inOrder(mMockNetd);
- final UserHandle testHandle = setupEnterpriseNetwork();
-
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- mCellNetworkAgent.connect(true);
-
- final TestOnCompleteListener listener = new TestOnCompleteListener();
- mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- r -> r.run(), listener);
- listener.expectOnComplete();
- inOrder.verify(mMockNetd).networkCreate(nativeNetworkConfigPhysical(
- mCellNetworkAgent.getNetwork().netId, INetd.PERMISSION_NONE));
- inOrder.verify(mMockNetd).networkAddUidRanges(mCellNetworkAgent.getNetwork().netId,
- uidRangeFor(testHandle));
-
- final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
- removedIntent.putExtra(Intent.EXTRA_USER, testHandle);
- processBroadcast(removedIntent);
-
- inOrder.verify(mMockNetd).networkRemoveUidRanges(mCellNetworkAgent.getNetwork().netId,
- uidRangeFor(testHandle));
- }
-
- /**
- * Make sure that OEM preference and per-profile preference can't be used at the same
- * time and throw ISE if tried
- */
- @Test
- public void testOemPreferenceAndProfilePreferenceExclusive() throws Exception {
- final UserHandle testHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
- mServiceContext.setWorkProfile(testHandle, true);
- final TestOnCompleteListener listener = new TestOnCompleteListener();
-
- setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(
- OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY);
- assertThrows("Should not be able to set per-profile pref while OEM prefs present",
- IllegalStateException.class, () ->
- mCm.setProfileNetworkPreference(testHandle,
- PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- r -> r.run(), listener));
-
- // Empty the OEM prefs
- final TestOemListenerCallback oemPrefListener = new TestOemListenerCallback();
- final OemNetworkPreferences emptyOemPref = new OemNetworkPreferences.Builder().build();
- mService.setOemNetworkPreference(emptyOemPref, oemPrefListener);
- oemPrefListener.expectOnComplete();
-
- mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- r -> r.run(), listener);
- listener.expectOnComplete();
- assertThrows("Should not be able to set OEM prefs while per-profile pref is on",
- IllegalStateException.class , () ->
- mService.setOemNetworkPreference(emptyOemPref, oemPrefListener));
- }
-
- /**
- * Make sure wrong preferences for per-profile default networking are rejected.
- */
- @Test
- public void testProfileNetworkPrefWrongPreference() throws Exception {
- final UserHandle testHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
- mServiceContext.setWorkProfile(testHandle, true);
- assertThrows("Should not be able to set an illegal preference",
- IllegalArgumentException.class,
- () -> mCm.setProfileNetworkPreference(testHandle,
- PROFILE_NETWORK_PREFERENCE_ENTERPRISE + 1, null, null));
- }
-
- /**
- * Make sure requests for per-profile default networking for a non-work profile are
- * rejected
- */
- @Test
- public void testProfileNetworkPrefWrongProfile() throws Exception {
- final UserHandle testHandle = UserHandle.of(TEST_WORK_PROFILE_USER_ID);
- mServiceContext.setWorkProfile(testHandle, false);
- assertThrows("Should not be able to set a user pref for a non-work profile",
- IllegalArgumentException.class , () ->
- mCm.setProfileNetworkPreference(testHandle,
- PROFILE_NETWORK_PREFERENCE_ENTERPRISE, null, null));
- }
-
- @Test
- public void testSubIdsClearedWithoutNetworkFactoryPermission() throws Exception {
- mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);
- final NetworkCapabilities nc = new NetworkCapabilities();
- nc.setSubscriptionIds(Collections.singleton(Process.myUid()));
-
- final NetworkCapabilities result =
- mService.networkCapabilitiesRestrictedForCallerPermissions(
- nc, Process.myPid(), Process.myUid());
- assertTrue(result.getSubscriptionIds().isEmpty());
- }
-
- @Test
- public void testSubIdsExistWithNetworkFactoryPermission() throws Exception {
- mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
-
- final Set<Integer> subIds = Collections.singleton(Process.myUid());
- final NetworkCapabilities nc = new NetworkCapabilities();
- nc.setSubscriptionIds(subIds);
-
- final NetworkCapabilities result =
- mService.networkCapabilitiesRestrictedForCallerPermissions(
- nc, Process.myPid(), Process.myUid());
- assertEquals(subIds, result.getSubscriptionIds());
- }
-
- private NetworkRequest getRequestWithSubIds() {
- return new NetworkRequest.Builder()
- .setSubscriptionIds(Collections.singleton(Process.myUid()))
- .build();
- }
-
- @Test
- public void testNetworkRequestWithSubIdsWithNetworkFactoryPermission() throws Exception {
- mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
- final PendingIntent pendingIntent = PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
- final NetworkCallback networkCallback1 = new NetworkCallback();
- final NetworkCallback networkCallback2 = new NetworkCallback();
-
- mCm.requestNetwork(getRequestWithSubIds(), networkCallback1);
- mCm.requestNetwork(getRequestWithSubIds(), pendingIntent);
- mCm.registerNetworkCallback(getRequestWithSubIds(), networkCallback2);
-
- mCm.unregisterNetworkCallback(networkCallback1);
- mCm.releaseNetworkRequest(pendingIntent);
- mCm.unregisterNetworkCallback(networkCallback2);
- }
-
- @Test
- public void testNetworkRequestWithSubIdsWithoutNetworkFactoryPermission() throws Exception {
- mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);
- final PendingIntent pendingIntent = PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
-
- final Class<SecurityException> expected = SecurityException.class;
- assertThrows(
- expected, () -> mCm.requestNetwork(getRequestWithSubIds(), new NetworkCallback()));
- assertThrows(expected, () -> mCm.requestNetwork(getRequestWithSubIds(), pendingIntent));
- assertThrows(
- expected,
- () -> mCm.registerNetworkCallback(getRequestWithSubIds(), new NetworkCallback()));
- }
-
- /**
- * Validate request counts are counted accurately on setProfileNetworkPreference on set/replace.
- */
- @Test
- public void testProfileNetworkPrefCountsRequestsCorrectlyOnSet() throws Exception {
- final UserHandle testHandle = setupEnterpriseNetwork();
- testRequestCountLimits(() -> {
- // Set initially to test the limit prior to having existing requests.
- final TestOnCompleteListener listener = new TestOnCompleteListener();
- mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- Runnable::run, listener);
- listener.expectOnComplete();
-
- // re-set so as to test the limit as part of replacing existing requests.
- mCm.setProfileNetworkPreference(testHandle, PROFILE_NETWORK_PREFERENCE_ENTERPRISE,
- Runnable::run, listener);
- listener.expectOnComplete();
- });
- }
-
- /**
- * Validate request counts are counted accurately on setOemNetworkPreference on set/replace.
- */
- @Test
- public void testSetOemNetworkPreferenceCountsRequestsCorrectlyOnSet() throws Exception {
- mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
- @OemNetworkPreferences.OemNetworkPreference final int networkPref =
- OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY;
- testRequestCountLimits(() -> {
- // Set initially to test the limit prior to having existing requests.
- final TestOemListenerCallback listener = new TestOemListenerCallback();
- mService.setOemNetworkPreference(
- createDefaultOemNetworkPreferences(networkPref), listener);
- listener.expectOnComplete();
-
- // re-set so as to test the limit as part of replacing existing requests.
- mService.setOemNetworkPreference(
- createDefaultOemNetworkPreferences(networkPref), listener);
- listener.expectOnComplete();
- });
- }
-
- private void testRequestCountLimits(@NonNull final Runnable r) throws Exception {
- final ArraySet<TestNetworkCallback> callbacks = new ArraySet<>();
- try {
- final int requestCount = mService.mSystemNetworkRequestCounter
- .mUidToNetworkRequestCount.get(Process.myUid());
- // The limit is hit when total requests <= limit.
- final int maxCount =
- ConnectivityService.MAX_NETWORK_REQUESTS_PER_SYSTEM_UID - requestCount;
- // Need permission so registerDefaultNetworkCallback uses mSystemNetworkRequestCounter
- withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () -> {
- for (int i = 1; i < maxCount - 1; i++) {
- final TestNetworkCallback cb = new TestNetworkCallback();
- mCm.registerDefaultNetworkCallback(cb);
- callbacks.add(cb);
- }
-
- // Code to run to check if it triggers a max request count limit error.
- r.run();
- });
- } finally {
- for (final TestNetworkCallback cb : callbacks) {
- mCm.unregisterNetworkCallback(cb);
- }
- }
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java b/packages/Connectivity/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java
deleted file mode 100644
index cf2c9c7..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java
+++ /dev/null
@@ -1,1004 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static android.content.pm.PackageManager.PERMISSION_DENIED;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.INetd.IF_STATE_DOWN;
-import static android.net.INetd.IF_STATE_UP;
-import static android.net.IpSecManager.DIRECTION_FWD;
-import static android.net.IpSecManager.DIRECTION_IN;
-import static android.net.IpSecManager.DIRECTION_OUT;
-import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.AppOpsManager;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
-import android.net.INetd;
-import android.net.InetAddresses;
-import android.net.InterfaceConfigurationParcel;
-import android.net.IpSecAlgorithm;
-import android.net.IpSecConfig;
-import android.net.IpSecManager;
-import android.net.IpSecSpiResponse;
-import android.net.IpSecTransform;
-import android.net.IpSecTransformResponse;
-import android.net.IpSecTunnelInterfaceResponse;
-import android.net.IpSecUdpEncapResponse;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.os.Binder;
-import android.os.ParcelFileDescriptor;
-import android.system.Os;
-import android.test.mock.MockContext;
-import android.util.ArraySet;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.server.IpSecService.TunnelInterfaceRecord;
-
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.net.Inet4Address;
-import java.net.Socket;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Set;
-
-/** Unit tests for {@link IpSecService}. */
-@SmallTest
-@RunWith(Parameterized.class)
-public class IpSecServiceParameterizedTest {
-
- private static final int TEST_SPI = 0xD1201D;
-
- private final String mSourceAddr;
- private final String mDestinationAddr;
- private final LinkAddress mLocalInnerAddress;
- private final int mFamily;
-
- private static final int[] ADDRESS_FAMILIES =
- new int[] {AF_INET, AF_INET6};
-
- @Parameterized.Parameters
- public static Collection ipSecConfigs() {
- return Arrays.asList(
- new Object[][] {
- {"1.2.3.4", "8.8.4.4", "10.0.1.1/24", AF_INET},
- {"2601::2", "2601::10", "2001:db8::1/64", AF_INET6}
- });
- }
-
- private static final byte[] AEAD_KEY = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
- 0x73, 0x61, 0x6C, 0x74
- };
- private static final byte[] CRYPT_KEY = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
- };
- private static final byte[] AUTH_KEY = {
- 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
- 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
- };
-
- AppOpsManager mMockAppOps = mock(AppOpsManager.class);
- ConnectivityManager mMockConnectivityMgr = mock(ConnectivityManager.class);
-
- TestContext mTestContext = new TestContext();
-
- private class TestContext extends MockContext {
- private Set<String> mAllowedPermissions = new ArraySet<>(Arrays.asList(
- android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
- android.Manifest.permission.NETWORK_STACK,
- PERMISSION_MAINLINE_NETWORK_STACK));
-
- private void setAllowedPermissions(String... permissions) {
- mAllowedPermissions = new ArraySet<>(permissions);
- }
-
- @Override
- public Object getSystemService(String name) {
- switch(name) {
- case Context.APP_OPS_SERVICE:
- return mMockAppOps;
- case Context.CONNECTIVITY_SERVICE:
- return mMockConnectivityMgr;
- default:
- return null;
- }
- }
-
- @Override
- public String getSystemServiceName(Class<?> serviceClass) {
- if (ConnectivityManager.class == serviceClass) {
- return Context.CONNECTIVITY_SERVICE;
- }
- return null;
- }
-
- @Override
- public PackageManager getPackageManager() {
- return mMockPkgMgr;
- }
-
- @Override
- public void enforceCallingOrSelfPermission(String permission, String message) {
- if (mAllowedPermissions.contains(permission)) {
- return;
- } else {
- throw new SecurityException("Unavailable permission requested");
- }
- }
-
- @Override
- public int checkCallingOrSelfPermission(String permission) {
- if (mAllowedPermissions.contains(permission)) {
- return PERMISSION_GRANTED;
- } else {
- return PERMISSION_DENIED;
- }
- }
- }
-
- INetd mMockNetd;
- PackageManager mMockPkgMgr;
- IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
- IpSecService mIpSecService;
- Network fakeNetwork = new Network(0xAB);
- int mUid = Os.getuid();
-
- private static final IpSecAlgorithm AUTH_ALGO =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
- private static final IpSecAlgorithm CRYPT_ALGO =
- new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- private static final IpSecAlgorithm AEAD_ALGO =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
- private static final int REMOTE_ENCAP_PORT = 4500;
-
- private static final String BLESSED_PACKAGE = "blessedPackage";
- private static final String SYSTEM_PACKAGE = "systemPackage";
- private static final String BAD_PACKAGE = "badPackage";
-
- public IpSecServiceParameterizedTest(
- String sourceAddr, String destAddr, String localInnerAddr, int family) {
- mSourceAddr = sourceAddr;
- mDestinationAddr = destAddr;
- mLocalInnerAddress = new LinkAddress(localInnerAddr);
- mFamily = family;
- }
-
- @Before
- public void setUp() throws Exception {
- mMockNetd = mock(INetd.class);
- mMockPkgMgr = mock(PackageManager.class);
- mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
- mIpSecService = new IpSecService(mTestContext, mMockIpSecSrvConfig);
-
- // Injecting mock netd
- when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
-
- // PackageManager should always return true (feature flag tests in IpSecServiceTest)
- when(mMockPkgMgr.hasSystemFeature(anyString())).thenReturn(true);
-
- // A package granted the AppOp for MANAGE_IPSEC_TUNNELS will be MODE_ALLOWED.
- when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(BLESSED_PACKAGE)))
- .thenReturn(AppOpsManager.MODE_ALLOWED);
- // A system package will not be granted the app op, so this should fall back to
- // a permissions check, which should pass.
- when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(SYSTEM_PACKAGE)))
- .thenReturn(AppOpsManager.MODE_DEFAULT);
- // A mismatch between the package name and the UID will return MODE_IGNORED.
- when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(BAD_PACKAGE)))
- .thenReturn(AppOpsManager.MODE_IGNORED);
- }
-
- //TODO: Add a test to verify SPI.
-
- @Test
- public void testIpSecServiceReserveSpi() throws Exception {
- when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
- .thenReturn(TEST_SPI);
-
- IpSecSpiResponse spiResp =
- mIpSecService.allocateSecurityParameterIndex(
- mDestinationAddr, TEST_SPI, new Binder());
- assertEquals(IpSecManager.Status.OK, spiResp.status);
- assertEquals(TEST_SPI, spiResp.spi);
- }
-
- @Test
- public void testReleaseSecurityParameterIndex() throws Exception {
- when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
- .thenReturn(TEST_SPI);
-
- IpSecSpiResponse spiResp =
- mIpSecService.allocateSecurityParameterIndex(
- mDestinationAddr, TEST_SPI, new Binder());
-
- mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
-
- verify(mMockNetd)
- .ipSecDeleteSecurityAssociation(
- eq(mUid),
- anyString(),
- anyString(),
- eq(TEST_SPI),
- anyInt(),
- anyInt(),
- anyInt());
-
- // Verify quota and RefcountedResource objects cleaned up
- IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
- try {
- userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
- fail("Expected IllegalArgumentException on attempt to access deleted resource");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testSecurityParameterIndexBinderDeath() throws Exception {
- when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
- .thenReturn(TEST_SPI);
-
- IpSecSpiResponse spiResp =
- mIpSecService.allocateSecurityParameterIndex(
- mDestinationAddr, TEST_SPI, new Binder());
-
- IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- IpSecService.RefcountedResource refcountedRecord =
- userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
-
- refcountedRecord.binderDied();
-
- verify(mMockNetd)
- .ipSecDeleteSecurityAssociation(
- eq(mUid),
- anyString(),
- anyString(),
- eq(TEST_SPI),
- anyInt(),
- anyInt(),
- anyInt());
-
- // Verify quota and RefcountedResource objects cleaned up
- assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
- try {
- userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
- fail("Expected IllegalArgumentException on attempt to access deleted resource");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- private int getNewSpiResourceId(String remoteAddress, int returnSpi) throws Exception {
- when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), anyString(), anyInt()))
- .thenReturn(returnSpi);
-
- IpSecSpiResponse spi =
- mIpSecService.allocateSecurityParameterIndex(
- InetAddresses.parseNumericAddress(remoteAddress).getHostAddress(),
- IpSecManager.INVALID_SECURITY_PARAMETER_INDEX,
- new Binder());
- return spi.resourceId;
- }
-
- private void addDefaultSpisAndRemoteAddrToIpSecConfig(IpSecConfig config) throws Exception {
- config.setSpiResourceId(getNewSpiResourceId(mDestinationAddr, TEST_SPI));
- config.setSourceAddress(mSourceAddr);
- config.setDestinationAddress(mDestinationAddr);
- }
-
- private void addAuthAndCryptToIpSecConfig(IpSecConfig config) throws Exception {
- config.setEncryption(CRYPT_ALGO);
- config.setAuthentication(AUTH_ALGO);
- }
-
- private void addEncapSocketToIpSecConfig(int resourceId, IpSecConfig config) throws Exception {
- config.setEncapType(IpSecTransform.ENCAP_ESPINUDP);
- config.setEncapSocketResourceId(resourceId);
- config.setEncapRemotePort(REMOTE_ENCAP_PORT);
- }
-
- private void verifyTransformNetdCalledForCreatingSA(
- IpSecConfig config, IpSecTransformResponse resp) throws Exception {
- verifyTransformNetdCalledForCreatingSA(config, resp, 0);
- }
-
- private void verifyTransformNetdCalledForCreatingSA(
- IpSecConfig config, IpSecTransformResponse resp, int encapSocketPort) throws Exception {
- IpSecAlgorithm auth = config.getAuthentication();
- IpSecAlgorithm crypt = config.getEncryption();
- IpSecAlgorithm authCrypt = config.getAuthenticatedEncryption();
-
- verify(mMockNetd, times(1))
- .ipSecAddSecurityAssociation(
- eq(mUid),
- eq(config.getMode()),
- eq(config.getSourceAddress()),
- eq(config.getDestinationAddress()),
- eq((config.getNetwork() != null) ? config.getNetwork().netId : 0),
- eq(TEST_SPI),
- eq(0),
- eq(0),
- eq((auth != null) ? auth.getName() : ""),
- eq((auth != null) ? auth.getKey() : new byte[] {}),
- eq((auth != null) ? auth.getTruncationLengthBits() : 0),
- eq((crypt != null) ? crypt.getName() : ""),
- eq((crypt != null) ? crypt.getKey() : new byte[] {}),
- eq((crypt != null) ? crypt.getTruncationLengthBits() : 0),
- eq((authCrypt != null) ? authCrypt.getName() : ""),
- eq((authCrypt != null) ? authCrypt.getKey() : new byte[] {}),
- eq((authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0),
- eq(config.getEncapType()),
- eq(encapSocketPort),
- eq(config.getEncapRemotePort()),
- eq(config.getXfrmInterfaceId()));
- }
-
- @Test
- public void testCreateTransform() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
- assertEquals(IpSecManager.Status.OK, createTransformResp.status);
-
- verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
- }
-
- @Test
- public void testCreateTransformAead() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
-
- ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
- assertEquals(IpSecManager.Status.OK, createTransformResp.status);
-
- verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
- }
-
- @Test
- public void testCreateTransportModeTransformWithEncap() throws Exception {
- IpSecUdpEncapResponse udpSock = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
-
- IpSecConfig ipSecConfig = new IpSecConfig();
- ipSecConfig.setMode(IpSecTransform.MODE_TRANSPORT);
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
- addEncapSocketToIpSecConfig(udpSock.resourceId, ipSecConfig);
-
- if (mFamily == AF_INET) {
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
- assertEquals(IpSecManager.Status.OK, createTransformResp.status);
-
- verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
- } else {
- try {
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
- fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
- } catch (IllegalArgumentException expected) {
- }
- }
- }
-
- @Test
- public void testCreateTunnelModeTransformWithEncap() throws Exception {
- IpSecUdpEncapResponse udpSock = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
-
- IpSecConfig ipSecConfig = new IpSecConfig();
- ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
- addEncapSocketToIpSecConfig(udpSock.resourceId, ipSecConfig);
-
- if (mFamily == AF_INET) {
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
- assertEquals(IpSecManager.Status.OK, createTransformResp.status);
-
- verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
- } else {
- try {
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
- fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
- } catch (IllegalArgumentException expected) {
- }
- }
- }
-
- @Test
- public void testCreateTwoTransformsWithSameSpis() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
- assertEquals(IpSecManager.Status.OK, createTransformResp.status);
-
- // Attempting to create transform a second time with the same SPIs should throw an error...
- try {
- mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
- fail("IpSecService should have thrown an error for reuse of SPI");
- } catch (IllegalStateException expected) {
- }
-
- // ... even if the transform is deleted
- mIpSecService.deleteTransform(createTransformResp.resourceId);
- try {
- mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
- fail("IpSecService should have thrown an error for reuse of SPI");
- } catch (IllegalStateException expected) {
- }
- }
-
- @Test
- public void testReleaseOwnedSpi() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
- IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
- mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
- verify(mMockNetd, times(0))
- .ipSecDeleteSecurityAssociation(
- eq(mUid),
- anyString(),
- anyString(),
- eq(TEST_SPI),
- anyInt(),
- anyInt(),
- anyInt());
- // quota is not released until the SPI is released by the Transform
- assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
- }
-
- @Test
- public void testDeleteTransform() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
- mIpSecService.deleteTransform(createTransformResp.resourceId);
-
- verify(mMockNetd, times(1))
- .ipSecDeleteSecurityAssociation(
- eq(mUid),
- anyString(),
- anyString(),
- eq(TEST_SPI),
- anyInt(),
- anyInt(),
- anyInt());
-
- // Verify quota and RefcountedResource objects cleaned up
- IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
- assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
-
- mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
- // Verify that ipSecDeleteSa was not called when the SPI was released because the
- // ownedByTransform property should prevent it; (note, the called count is cumulative).
- verify(mMockNetd, times(1))
- .ipSecDeleteSecurityAssociation(
- anyInt(),
- anyString(),
- anyString(),
- anyInt(),
- anyInt(),
- anyInt(),
- anyInt());
- assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
-
- try {
- userRecord.mTransformRecords.getRefcountedResourceOrThrow(
- createTransformResp.resourceId);
- fail("Expected IllegalArgumentException on attempt to access deleted resource");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testTransportModeTransformBinderDeath() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
-
- IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- IpSecService.RefcountedResource refcountedRecord =
- userRecord.mTransformRecords.getRefcountedResourceOrThrow(
- createTransformResp.resourceId);
-
- refcountedRecord.binderDied();
-
- verify(mMockNetd)
- .ipSecDeleteSecurityAssociation(
- eq(mUid),
- anyString(),
- anyString(),
- eq(TEST_SPI),
- anyInt(),
- anyInt(),
- anyInt());
-
- // Verify quota and RefcountedResource objects cleaned up
- assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
- try {
- userRecord.mTransformRecords.getRefcountedResourceOrThrow(
- createTransformResp.resourceId);
- fail("Expected IllegalArgumentException on attempt to access deleted resource");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testApplyTransportModeTransform() throws Exception {
- verifyApplyTransportModeTransformCommon(false);
- }
-
- @Test
- public void testApplyTransportModeTransformReleasedSpi() throws Exception {
- verifyApplyTransportModeTransformCommon(true);
- }
-
- public void verifyApplyTransportModeTransformCommon(
- boolean closeSpiBeforeApply) throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
-
- if (closeSpiBeforeApply) {
- mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
- }
-
- Socket socket = new Socket();
- socket.bind(null);
- ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
-
- int resourceId = createTransformResp.resourceId;
- mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
-
- verify(mMockNetd)
- .ipSecApplyTransportModeTransform(
- eq(pfd),
- eq(mUid),
- eq(IpSecManager.DIRECTION_OUT),
- anyString(),
- anyString(),
- eq(TEST_SPI));
- }
-
- @Test
- public void testApplyTransportModeTransformWithClosedSpi() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
-
- // Close SPI record
- mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
-
- Socket socket = new Socket();
- socket.bind(null);
- ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
-
- int resourceId = createTransformResp.resourceId;
- mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
-
- verify(mMockNetd)
- .ipSecApplyTransportModeTransform(
- eq(pfd),
- eq(mUid),
- eq(IpSecManager.DIRECTION_OUT),
- anyString(),
- anyString(),
- eq(TEST_SPI));
- }
-
- @Test
- public void testRemoveTransportModeTransform() throws Exception {
- Socket socket = new Socket();
- socket.bind(null);
- ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
- mIpSecService.removeTransportModeTransforms(pfd);
-
- verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd);
- }
-
- private IpSecTunnelInterfaceResponse createAndValidateTunnel(
- String localAddr, String remoteAddr, String pkgName) throws Exception {
- final InterfaceConfigurationParcel config = new InterfaceConfigurationParcel();
- config.flags = new String[] {IF_STATE_DOWN};
- when(mMockNetd.interfaceGetCfg(anyString())).thenReturn(config);
- IpSecTunnelInterfaceResponse createTunnelResp =
- mIpSecService.createTunnelInterface(
- mSourceAddr, mDestinationAddr, fakeNetwork, new Binder(), pkgName);
-
- assertNotNull(createTunnelResp);
- assertEquals(IpSecManager.Status.OK, createTunnelResp.status);
- for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT, DIRECTION_FWD}) {
- for (int selAddrFamily : ADDRESS_FAMILIES) {
- verify(mMockNetd).ipSecAddSecurityPolicy(
- eq(mUid),
- eq(selAddrFamily),
- eq(direction),
- anyString(),
- anyString(),
- eq(0),
- anyInt(), // iKey/oKey
- anyInt(), // mask
- eq(createTunnelResp.resourceId));
- }
- }
-
- return createTunnelResp;
- }
-
- @Test
- public void testCreateTunnelInterface() throws Exception {
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
-
- // Check that we have stored the tracking object, and retrieve it
- IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- IpSecService.RefcountedResource refcountedRecord =
- userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
- createTunnelResp.resourceId);
-
- assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
- verify(mMockNetd)
- .ipSecAddTunnelInterface(
- eq(createTunnelResp.interfaceName),
- eq(mSourceAddr),
- eq(mDestinationAddr),
- anyInt(),
- anyInt(),
- anyInt());
- verify(mMockNetd).interfaceSetCfg(argThat(
- config -> Arrays.asList(config.flags).contains(IF_STATE_UP)));
- }
-
- @Test
- public void testDeleteTunnelInterface() throws Exception {
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
-
- IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
-
- mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, BLESSED_PACKAGE);
-
- // Verify quota and RefcountedResource objects cleaned up
- assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
- verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
- try {
- userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
- createTunnelResp.resourceId);
- fail("Expected IllegalArgumentException on attempt to access deleted resource");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- private Network createFakeUnderlyingNetwork(String interfaceName) {
- final Network fakeNetwork = new Network(1000);
- final LinkProperties fakeLp = new LinkProperties();
- fakeLp.setInterfaceName(interfaceName);
- when(mMockConnectivityMgr.getLinkProperties(eq(fakeNetwork))).thenReturn(fakeLp);
- return fakeNetwork;
- }
-
- @Test
- public void testSetNetworkForTunnelInterface() throws Exception {
- final IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
- final Network newFakeNetwork = createFakeUnderlyingNetwork("newFakeNetworkInterface");
- final int tunnelIfaceResourceId = createTunnelResp.resourceId;
- mIpSecService.setNetworkForTunnelInterface(
- tunnelIfaceResourceId, newFakeNetwork, BLESSED_PACKAGE);
-
- final IpSecService.UserRecord userRecord =
- mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
-
- final TunnelInterfaceRecord tunnelInterfaceInfo =
- userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelIfaceResourceId);
- assertEquals(newFakeNetwork, tunnelInterfaceInfo.getUnderlyingNetwork());
- }
-
- @Test
- public void testSetNetworkForTunnelInterfaceFailsForInvalidResourceId() throws Exception {
- final IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
- final Network newFakeNetwork = new Network(1000);
-
- try {
- mIpSecService.setNetworkForTunnelInterface(
- IpSecManager.INVALID_RESOURCE_ID, newFakeNetwork, BLESSED_PACKAGE);
- fail("Expected an IllegalArgumentException for invalid resource ID.");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testSetNetworkForTunnelInterfaceFailsWhenSettingTunnelNetwork() throws Exception {
- final IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
- final int tunnelIfaceResourceId = createTunnelResp.resourceId;
- final IpSecService.UserRecord userRecord =
- mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- final TunnelInterfaceRecord tunnelInterfaceInfo =
- userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelIfaceResourceId);
-
- final Network newFakeNetwork =
- createFakeUnderlyingNetwork(tunnelInterfaceInfo.getInterfaceName());
-
- try {
- mIpSecService.setNetworkForTunnelInterface(
- tunnelIfaceResourceId, newFakeNetwork, BLESSED_PACKAGE);
- fail(
- "Expected an IllegalArgumentException because the underlying network is the"
- + " network being exposed by this tunnel.");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testTunnelInterfaceBinderDeath() throws Exception {
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
-
- IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- IpSecService.RefcountedResource refcountedRecord =
- userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
- createTunnelResp.resourceId);
-
- refcountedRecord.binderDied();
-
- // Verify quota and RefcountedResource objects cleaned up
- assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
- verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
- try {
- userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
- createTunnelResp.resourceId);
- fail("Expected IllegalArgumentException on attempt to access deleted resource");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testApplyTunnelModeTransformOutbound() throws Exception {
- verifyApplyTunnelModeTransformCommon(false /* closeSpiBeforeApply */, DIRECTION_OUT);
- }
-
- @Test
- public void testApplyTunnelModeTransformOutboundNonNetworkStack() throws Exception {
- mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS);
- verifyApplyTunnelModeTransformCommon(false /* closeSpiBeforeApply */, DIRECTION_OUT);
- }
-
- @Test
- public void testApplyTunnelModeTransformOutboundReleasedSpi() throws Exception {
- verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_OUT);
- }
-
- @Test
- public void testApplyTunnelModeTransformInbound() throws Exception {
- verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_IN);
- }
-
- @Test
- public void testApplyTunnelModeTransformInboundNonNetworkStack() throws Exception {
- mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS);
- verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_IN);
- }
-
- @Test
- public void testApplyTunnelModeTransformForward() throws Exception {
- verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_FWD);
- }
-
- @Test
- public void testApplyTunnelModeTransformForwardNonNetworkStack() throws Exception {
- mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS);
-
- try {
- verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_FWD);
- fail("Expected security exception due to use of forward policies without NETWORK_STACK"
- + " or MAINLINE_NETWORK_STACK permission");
- } catch (SecurityException expected) {
- }
- }
-
- public void verifyApplyTunnelModeTransformCommon(boolean closeSpiBeforeApply, int direction)
- throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
-
- if (closeSpiBeforeApply) {
- mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
- }
-
- int transformResourceId = createTransformResp.resourceId;
- int tunnelResourceId = createTunnelResp.resourceId;
- mIpSecService.applyTunnelModeTransform(
- tunnelResourceId, direction, transformResourceId, BLESSED_PACKAGE);
-
- for (int selAddrFamily : ADDRESS_FAMILIES) {
- verify(mMockNetd)
- .ipSecUpdateSecurityPolicy(
- eq(mUid),
- eq(selAddrFamily),
- eq(direction),
- anyString(),
- anyString(),
- eq(direction == DIRECTION_OUT ? TEST_SPI : 0),
- anyInt(), // iKey/oKey
- anyInt(), // mask
- eq(tunnelResourceId));
- }
-
- ipSecConfig.setXfrmInterfaceId(tunnelResourceId);
- verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
- }
-
-
- @Test
- public void testApplyTunnelModeTransformWithClosedSpi() throws Exception {
- IpSecConfig ipSecConfig = new IpSecConfig();
- ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
- addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
- addAuthAndCryptToIpSecConfig(ipSecConfig);
-
- IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
-
- // Close SPI record
- mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
-
- int transformResourceId = createTransformResp.resourceId;
- int tunnelResourceId = createTunnelResp.resourceId;
- mIpSecService.applyTunnelModeTransform(
- tunnelResourceId, IpSecManager.DIRECTION_OUT, transformResourceId, BLESSED_PACKAGE);
-
- for (int selAddrFamily : ADDRESS_FAMILIES) {
- verify(mMockNetd)
- .ipSecUpdateSecurityPolicy(
- eq(mUid),
- eq(selAddrFamily),
- eq(IpSecManager.DIRECTION_OUT),
- anyString(),
- anyString(),
- eq(TEST_SPI),
- anyInt(), // iKey/oKey
- anyInt(), // mask
- eq(tunnelResourceId));
- }
-
- ipSecConfig.setXfrmInterfaceId(tunnelResourceId);
- verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
- }
-
- @Test
- public void testAddRemoveAddressFromTunnelInterface() throws Exception {
- for (String pkgName : new String[] {BLESSED_PACKAGE, SYSTEM_PACKAGE}) {
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, pkgName);
- mIpSecService.addAddressToTunnelInterface(
- createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
- verify(mMockNetd, times(1))
- .interfaceAddAddress(
- eq(createTunnelResp.interfaceName),
- eq(mLocalInnerAddress.getAddress().getHostAddress()),
- eq(mLocalInnerAddress.getPrefixLength()));
- mIpSecService.removeAddressFromTunnelInterface(
- createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
- verify(mMockNetd, times(1))
- .interfaceDelAddress(
- eq(createTunnelResp.interfaceName),
- eq(mLocalInnerAddress.getAddress().getHostAddress()),
- eq(mLocalInnerAddress.getPrefixLength()));
- mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, pkgName);
- }
- }
-
- @Ignore
- @Test
- public void testAddTunnelFailsForBadPackageName() throws Exception {
- try {
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, BAD_PACKAGE);
- fail("Expected a SecurityException for badPackage.");
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void testFeatureFlagVerification() throws Exception {
- when(mMockPkgMgr.hasSystemFeature(eq(PackageManager.FEATURE_IPSEC_TUNNELS)))
- .thenReturn(false);
-
- try {
- String addr = Inet4Address.getLoopbackAddress().getHostAddress();
- mIpSecService.createTunnelInterface(
- addr, addr, new Network(0), new Binder(), BLESSED_PACKAGE);
- fail("Expected UnsupportedOperationException for disabled feature");
- } catch (UnsupportedOperationException expected) {
- }
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/IpSecServiceRefcountedResourceTest.java b/packages/Connectivity/tests/unit/java/com/android/server/IpSecServiceRefcountedResourceTest.java
deleted file mode 100644
index 22a2c94..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/IpSecServiceRefcountedResourceTest.java
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyObject;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.IpSecService.IResource;
-import com.android.server.IpSecService.RefcountedResource;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ThreadLocalRandom;
-
-/** Unit tests for {@link IpSecService.RefcountedResource}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class IpSecServiceRefcountedResourceTest {
- Context mMockContext;
- IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
- IpSecService mIpSecService;
-
- @Before
- public void setUp() throws Exception {
- mMockContext = mock(Context.class);
- mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
- mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
- }
-
- private void assertResourceState(
- RefcountedResource<IResource> resource,
- int refCount,
- int userReleaseCallCount,
- int releaseReferenceCallCount,
- int invalidateCallCount,
- int freeUnderlyingResourcesCallCount)
- throws RemoteException {
- // Check refcount on RefcountedResource
- assertEquals(refCount, resource.mRefCount);
-
- // Check call count of RefcountedResource
- verify(resource, times(userReleaseCallCount)).userRelease();
- verify(resource, times(releaseReferenceCallCount)).releaseReference();
-
- // Check call count of IResource
- verify(resource.getResource(), times(invalidateCallCount)).invalidate();
- verify(resource.getResource(), times(freeUnderlyingResourcesCallCount))
- .freeUnderlyingResources();
- }
-
- /** Adds mockito instrumentation */
- private RefcountedResource<IResource> getTestRefcountedResource(
- RefcountedResource... children) {
- return getTestRefcountedResource(new Binder(), children);
- }
-
- /** Adds mockito instrumentation with provided binder */
- private RefcountedResource<IResource> getTestRefcountedResource(
- IBinder binder, RefcountedResource... children) {
- return spy(
- mIpSecService
- .new RefcountedResource<IResource>(mock(IResource.class), binder, children));
- }
-
- @Test
- public void testConstructor() throws RemoteException {
- IBinder binderMock = mock(IBinder.class);
- RefcountedResource<IResource> resource = getTestRefcountedResource(binderMock);
-
- // Verify resource's refcount starts at 1 (for user-reference)
- assertResourceState(resource, 1, 0, 0, 0, 0);
-
- // Verify linking to binder death
- verify(binderMock).linkToDeath(anyObject(), anyInt());
- }
-
- @Test
- public void testConstructorWithChildren() throws RemoteException {
- IBinder binderMockChild = mock(IBinder.class);
- IBinder binderMockParent = mock(IBinder.class);
- RefcountedResource<IResource> childResource = getTestRefcountedResource(binderMockChild);
- RefcountedResource<IResource> parentResource =
- getTestRefcountedResource(binderMockParent, childResource);
-
- // Verify parent's refcount starts at 1 (for user-reference)
- assertResourceState(parentResource, 1, 0, 0, 0, 0);
-
- // Verify child's refcounts were incremented
- assertResourceState(childResource, 2, 0, 0, 0, 0);
-
- // Verify linking to binder death
- verify(binderMockChild).linkToDeath(anyObject(), anyInt());
- verify(binderMockParent).linkToDeath(anyObject(), anyInt());
- }
-
- @Test
- public void testFailLinkToDeath() throws RemoteException {
- IBinder binderMock = mock(IBinder.class);
- doThrow(new RemoteException()).when(binderMock).linkToDeath(anyObject(), anyInt());
-
- try {
- getTestRefcountedResource(binderMock);
- fail("Expected exception to propogate when binder fails to link to death");
- } catch (RuntimeException expected) {
- }
- }
-
- @Test
- public void testCleanupAndRelease() throws RemoteException {
- IBinder binderMock = mock(IBinder.class);
- RefcountedResource<IResource> refcountedResource = getTestRefcountedResource(binderMock);
-
- // Verify user-initiated cleanup path decrements refcount and calls full cleanup flow
- refcountedResource.userRelease();
- assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
-
- // Verify user-initated cleanup path unlinks from binder
- verify(binderMock).unlinkToDeath(eq(refcountedResource), eq(0));
- assertNull(refcountedResource.mBinder);
- }
-
- @Test
- public void testMultipleCallsToCleanupAndRelease() throws RemoteException {
- RefcountedResource<IResource> refcountedResource = getTestRefcountedResource();
-
- // Verify calling userRelease multiple times does not trigger any other cleanup
- // methods
- refcountedResource.userRelease();
- assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
-
- refcountedResource.userRelease();
- refcountedResource.userRelease();
- assertResourceState(refcountedResource, -1, 3, 1, 1, 1);
- }
-
- @Test
- public void testBinderDeathAfterCleanupAndReleaseDoesNothing() throws RemoteException {
- RefcountedResource<IResource> refcountedResource = getTestRefcountedResource();
-
- refcountedResource.userRelease();
- assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
-
- // Verify binder death call does not trigger any other cleanup methods if called after
- // userRelease()
- refcountedResource.binderDied();
- assertResourceState(refcountedResource, -1, 2, 1, 1, 1);
- }
-
- @Test
- public void testBinderDeath() throws RemoteException {
- RefcountedResource<IResource> refcountedResource = getTestRefcountedResource();
-
- // Verify binder death caused cleanup
- refcountedResource.binderDied();
- verify(refcountedResource, times(1)).binderDied();
- assertResourceState(refcountedResource, -1, 1, 1, 1, 1);
- assertNull(refcountedResource.mBinder);
- }
-
- @Test
- public void testCleanupParentDecrementsChildRefcount() throws RemoteException {
- RefcountedResource<IResource> childResource = getTestRefcountedResource();
- RefcountedResource<IResource> parentResource = getTestRefcountedResource(childResource);
-
- parentResource.userRelease();
-
- // Verify parent gets cleaned up properly, and triggers releaseReference on
- // child
- assertResourceState(childResource, 1, 0, 1, 0, 0);
- assertResourceState(parentResource, -1, 1, 1, 1, 1);
- }
-
- @Test
- public void testCleanupReferencedChildDoesNotTriggerRelease() throws RemoteException {
- RefcountedResource<IResource> childResource = getTestRefcountedResource();
- RefcountedResource<IResource> parentResource = getTestRefcountedResource(childResource);
-
- childResource.userRelease();
-
- // Verify that child does not clean up kernel resources and quota.
- assertResourceState(childResource, 1, 1, 1, 1, 0);
- assertResourceState(parentResource, 1, 0, 0, 0, 0);
- }
-
- @Test
- public void testTwoParents() throws RemoteException {
- RefcountedResource<IResource> childResource = getTestRefcountedResource();
- RefcountedResource<IResource> parentResource1 = getTestRefcountedResource(childResource);
- RefcountedResource<IResource> parentResource2 = getTestRefcountedResource(childResource);
-
- // Verify that child does not cleanup kernel resources and quota until all references
- // have been released. Assumption: parents release correctly based on
- // testCleanupParentDecrementsChildRefcount()
- childResource.userRelease();
- assertResourceState(childResource, 2, 1, 1, 1, 0);
-
- parentResource1.userRelease();
- assertResourceState(childResource, 1, 1, 2, 1, 0);
-
- parentResource2.userRelease();
- assertResourceState(childResource, -1, 1, 3, 1, 1);
- }
-
- @Test
- public void testTwoChildren() throws RemoteException {
- RefcountedResource<IResource> childResource1 = getTestRefcountedResource();
- RefcountedResource<IResource> childResource2 = getTestRefcountedResource();
- RefcountedResource<IResource> parentResource =
- getTestRefcountedResource(childResource1, childResource2);
-
- childResource1.userRelease();
- assertResourceState(childResource1, 1, 1, 1, 1, 0);
- assertResourceState(childResource2, 2, 0, 0, 0, 0);
-
- parentResource.userRelease();
- assertResourceState(childResource1, -1, 1, 2, 1, 1);
- assertResourceState(childResource2, 1, 0, 1, 0, 0);
-
- childResource2.userRelease();
- assertResourceState(childResource1, -1, 1, 2, 1, 1);
- assertResourceState(childResource2, -1, 1, 2, 1, 1);
- }
-
- @Test
- public void testSampleUdpEncapTranform() throws RemoteException {
- RefcountedResource<IResource> spi1 = getTestRefcountedResource();
- RefcountedResource<IResource> spi2 = getTestRefcountedResource();
- RefcountedResource<IResource> udpEncapSocket = getTestRefcountedResource();
- RefcountedResource<IResource> transform =
- getTestRefcountedResource(spi1, spi2, udpEncapSocket);
-
- // Pretend one SPI goes out of reference (releaseManagedResource -> userRelease)
- spi1.userRelease();
-
- // User called releaseManagedResource on udpEncap socket
- udpEncapSocket.userRelease();
-
- // User dies, and binder kills the rest
- spi2.binderDied();
- transform.binderDied();
-
- // Check resource states
- assertResourceState(spi1, -1, 1, 2, 1, 1);
- assertResourceState(spi2, -1, 1, 2, 1, 1);
- assertResourceState(udpEncapSocket, -1, 1, 2, 1, 1);
- assertResourceState(transform, -1, 1, 1, 1, 1);
- }
-
- @Test
- public void testSampleDualTransformEncapSocket() throws RemoteException {
- RefcountedResource<IResource> spi1 = getTestRefcountedResource();
- RefcountedResource<IResource> spi2 = getTestRefcountedResource();
- RefcountedResource<IResource> spi3 = getTestRefcountedResource();
- RefcountedResource<IResource> spi4 = getTestRefcountedResource();
- RefcountedResource<IResource> udpEncapSocket = getTestRefcountedResource();
- RefcountedResource<IResource> transform1 =
- getTestRefcountedResource(spi1, spi2, udpEncapSocket);
- RefcountedResource<IResource> transform2 =
- getTestRefcountedResource(spi3, spi4, udpEncapSocket);
-
- // Pretend one SPIs goes out of reference (releaseManagedResource -> userRelease)
- spi1.userRelease();
-
- // User called releaseManagedResource on udpEncap socket and spi4
- udpEncapSocket.userRelease();
- spi4.userRelease();
-
- // User dies, and binder kills the rest
- spi2.binderDied();
- spi3.binderDied();
- transform2.binderDied();
- transform1.binderDied();
-
- // Check resource states
- assertResourceState(spi1, -1, 1, 2, 1, 1);
- assertResourceState(spi2, -1, 1, 2, 1, 1);
- assertResourceState(spi3, -1, 1, 2, 1, 1);
- assertResourceState(spi4, -1, 1, 2, 1, 1);
- assertResourceState(udpEncapSocket, -1, 1, 3, 1, 1);
- assertResourceState(transform1, -1, 1, 1, 1, 1);
- assertResourceState(transform2, -1, 1, 1, 1, 1);
- }
-
- @Test
- public void fuzzTest() throws RemoteException {
- List<RefcountedResource<IResource>> resources = new ArrayList<>();
-
- // Build a tree of resources
- for (int i = 0; i < 100; i++) {
- // Choose a random number of children from the existing list
- int numChildren = ThreadLocalRandom.current().nextInt(0, resources.size() + 1);
-
- // Build a (random) list of children
- Set<RefcountedResource<IResource>> children = new HashSet<>();
- for (int j = 0; j < numChildren; j++) {
- int childIndex = ThreadLocalRandom.current().nextInt(0, resources.size());
- children.add(resources.get(childIndex));
- }
-
- RefcountedResource<IResource> newRefcountedResource =
- getTestRefcountedResource(
- children.toArray(new RefcountedResource[children.size()]));
- resources.add(newRefcountedResource);
- }
-
- // Cleanup all resources in a random order
- List<RefcountedResource<IResource>> clonedResources =
- new ArrayList<>(resources); // shallow copy
- while (!clonedResources.isEmpty()) {
- int index = ThreadLocalRandom.current().nextInt(0, clonedResources.size());
- RefcountedResource<IResource> refcountedResource = clonedResources.get(index);
- refcountedResource.userRelease();
- clonedResources.remove(index);
- }
-
- // Verify all resources were cleaned up properly
- for (RefcountedResource<IResource> refcountedResource : resources) {
- assertEquals(-1, refcountedResource.mRefCount);
- }
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/IpSecServiceTest.java b/packages/Connectivity/tests/unit/java/com/android/server/IpSecServiceTest.java
deleted file mode 100644
index 6232423..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/IpSecServiceTest.java
+++ /dev/null
@@ -1,670 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.EADDRINUSE;
-import static android.system.OsConstants.IPPROTO_UDP;
-import static android.system.OsConstants.SOCK_DGRAM;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.INetd;
-import android.net.IpSecAlgorithm;
-import android.net.IpSecConfig;
-import android.net.IpSecManager;
-import android.net.IpSecSpiResponse;
-import android.net.IpSecUdpEncapResponse;
-import android.os.Binder;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.StructStat;
-import android.util.Range;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import dalvik.system.SocketTagger;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
-
-import java.io.FileDescriptor;
-import java.net.InetAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.List;
-
-/** Unit tests for {@link IpSecService}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class IpSecServiceTest {
-
- private static final int DROID_SPI = 0xD1201D;
- private static final int MAX_NUM_ENCAP_SOCKETS = 100;
- private static final int MAX_NUM_SPIS = 100;
- private static final int TEST_UDP_ENCAP_INVALID_PORT = 100;
- private static final int TEST_UDP_ENCAP_PORT_OUT_RANGE = 100000;
-
- private static final InetAddress INADDR_ANY;
-
- private static final byte[] AEAD_KEY = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
- 0x73, 0x61, 0x6C, 0x74
- };
- private static final byte[] CRYPT_KEY = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
- };
- private static final byte[] AUTH_KEY = {
- 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
- 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
- };
-
- private static final IpSecAlgorithm AUTH_ALGO =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
- private static final IpSecAlgorithm CRYPT_ALGO =
- new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
- private static final IpSecAlgorithm AEAD_ALGO =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
-
- static {
- try {
- INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0});
- } catch (UnknownHostException e) {
- throw new RuntimeException(e);
- }
- }
-
- Context mMockContext;
- INetd mMockNetd;
- IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
- IpSecService mIpSecService;
-
- @Before
- public void setUp() throws Exception {
- mMockContext = mock(Context.class);
- mMockNetd = mock(INetd.class);
- mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
- mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
-
- // Injecting mock netd
- when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
- }
-
- @Test
- public void testIpSecServiceCreate() throws InterruptedException {
- IpSecService ipSecSrv = IpSecService.create(mMockContext);
- assertNotNull(ipSecSrv);
- }
-
- @Test
- public void testReleaseInvalidSecurityParameterIndex() throws Exception {
- try {
- mIpSecService.releaseSecurityParameterIndex(1);
- fail("IllegalArgumentException not thrown");
- } catch (IllegalArgumentException e) {
- }
- }
-
- /** This function finds an available port */
- int findUnusedPort() throws Exception {
- // Get an available port.
- ServerSocket s = new ServerSocket(0);
- int port = s.getLocalPort();
- s.close();
- return port;
- }
-
- @Test
- public void testOpenAndCloseUdpEncapsulationSocket() throws Exception {
- int localport = -1;
- IpSecUdpEncapResponse udpEncapResp = null;
-
- for (int i = 0; i < IpSecService.MAX_PORT_BIND_ATTEMPTS; i++) {
- localport = findUnusedPort();
-
- udpEncapResp = mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
- assertNotNull(udpEncapResp);
- if (udpEncapResp.status == IpSecManager.Status.OK) {
- break;
- }
-
- // Else retry to reduce possibility for port-bind failures.
- }
-
- assertNotNull(udpEncapResp);
- assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- assertEquals(localport, udpEncapResp.port);
-
- mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
- udpEncapResp.fileDescriptor.close();
-
- // Verify quota and RefcountedResource objects cleaned up
- IpSecService.UserRecord userRecord =
- mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
- assertEquals(0, userRecord.mSocketQuotaTracker.mCurrent);
- try {
- userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(udpEncapResp.resourceId);
- fail("Expected IllegalArgumentException on attempt to access deleted resource");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testUdpEncapsulationSocketBinderDeath() throws Exception {
- IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(0, new Binder());
-
- IpSecService.UserRecord userRecord =
- mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
- IpSecService.RefcountedResource refcountedRecord =
- userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(
- udpEncapResp.resourceId);
-
- refcountedRecord.binderDied();
-
- // Verify quota and RefcountedResource objects cleaned up
- assertEquals(0, userRecord.mSocketQuotaTracker.mCurrent);
- try {
- userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(udpEncapResp.resourceId);
- fail("Expected IllegalArgumentException on attempt to access deleted resource");
- } catch (IllegalArgumentException expected) {
-
- }
- }
-
- @Test
- public void testOpenUdpEncapsulationSocketAfterClose() throws Exception {
- IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(0, new Binder());
- assertNotNull(udpEncapResp);
- assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- int localport = udpEncapResp.port;
-
- mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
- udpEncapResp.fileDescriptor.close();
-
- /** Check if localport is available. */
- FileDescriptor newSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- Os.bind(newSocket, INADDR_ANY, localport);
- Os.close(newSocket);
- }
-
- /**
- * This function checks if the IpSecService holds the reserved port. If
- * closeUdpEncapsulationSocket is not called, the socket cleanup should not be complete.
- */
- @Test
- public void testUdpEncapPortNotReleased() throws Exception {
- IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(0, new Binder());
- assertNotNull(udpEncapResp);
- assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- int localport = udpEncapResp.port;
-
- udpEncapResp.fileDescriptor.close();
-
- FileDescriptor newSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- try {
- Os.bind(newSocket, INADDR_ANY, localport);
- fail("ErrnoException not thrown");
- } catch (ErrnoException e) {
- assertEquals(EADDRINUSE, e.errno);
- }
- mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
- }
-
- @Test
- public void testOpenUdpEncapsulationSocketOnRandomPort() throws Exception {
- IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(0, new Binder());
- assertNotNull(udpEncapResp);
- assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- assertNotEquals(0, udpEncapResp.port);
- mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
- udpEncapResp.fileDescriptor.close();
- }
-
- @Test
- public void testOpenUdpEncapsulationSocketPortRange() throws Exception {
- try {
- mIpSecService.openUdpEncapsulationSocket(TEST_UDP_ENCAP_INVALID_PORT, new Binder());
- fail("IllegalArgumentException not thrown");
- } catch (IllegalArgumentException e) {
- }
-
- try {
- mIpSecService.openUdpEncapsulationSocket(TEST_UDP_ENCAP_PORT_OUT_RANGE, new Binder());
- fail("IllegalArgumentException not thrown");
- } catch (IllegalArgumentException e) {
- }
- }
-
- @Test
- public void testOpenUdpEncapsulationSocketTwice() throws Exception {
- IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(0, new Binder());
- assertNotNull(udpEncapResp);
- assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- int localport = udpEncapResp.port;
-
- IpSecUdpEncapResponse testUdpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
- assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, testUdpEncapResp.status);
-
- mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
- udpEncapResp.fileDescriptor.close();
- }
-
- @Test
- public void testCloseInvalidUdpEncapsulationSocket() throws Exception {
- try {
- mIpSecService.closeUdpEncapsulationSocket(1);
- fail("IllegalArgumentException not thrown");
- } catch (IllegalArgumentException e) {
- }
- }
-
- @Test
- public void testValidateAlgorithmsAuth() {
- // Validate that correct algorithm type succeeds
- IpSecConfig config = new IpSecConfig();
- config.setAuthentication(AUTH_ALGO);
- mIpSecService.validateAlgorithms(config);
-
- // Validate that incorrect algorithm types fails
- for (IpSecAlgorithm algo : new IpSecAlgorithm[] {CRYPT_ALGO, AEAD_ALGO}) {
- try {
- config = new IpSecConfig();
- config.setAuthentication(algo);
- mIpSecService.validateAlgorithms(config);
- fail("Did not throw exception on invalid algorithm type");
- } catch (IllegalArgumentException expected) {
- }
- }
- }
-
- @Test
- public void testValidateAlgorithmsCrypt() {
- // Validate that correct algorithm type succeeds
- IpSecConfig config = new IpSecConfig();
- config.setEncryption(CRYPT_ALGO);
- mIpSecService.validateAlgorithms(config);
-
- // Validate that incorrect algorithm types fails
- for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, AEAD_ALGO}) {
- try {
- config = new IpSecConfig();
- config.setEncryption(algo);
- mIpSecService.validateAlgorithms(config);
- fail("Did not throw exception on invalid algorithm type");
- } catch (IllegalArgumentException expected) {
- }
- }
- }
-
- @Test
- public void testValidateAlgorithmsAead() {
- // Validate that correct algorithm type succeeds
- IpSecConfig config = new IpSecConfig();
- config.setAuthenticatedEncryption(AEAD_ALGO);
- mIpSecService.validateAlgorithms(config);
-
- // Validate that incorrect algorithm types fails
- for (IpSecAlgorithm algo : new IpSecAlgorithm[] {AUTH_ALGO, CRYPT_ALGO}) {
- try {
- config = new IpSecConfig();
- config.setAuthenticatedEncryption(algo);
- mIpSecService.validateAlgorithms(config);
- fail("Did not throw exception on invalid algorithm type");
- } catch (IllegalArgumentException expected) {
- }
- }
- }
-
- @Test
- public void testValidateAlgorithmsAuthCrypt() {
- // Validate that correct algorithm type succeeds
- IpSecConfig config = new IpSecConfig();
- config.setAuthentication(AUTH_ALGO);
- config.setEncryption(CRYPT_ALGO);
- mIpSecService.validateAlgorithms(config);
- }
-
- @Test
- public void testValidateAlgorithmsNoAlgorithms() {
- IpSecConfig config = new IpSecConfig();
- try {
- mIpSecService.validateAlgorithms(config);
- fail("Expected exception; no algorithms specified");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testValidateAlgorithmsAeadWithAuth() {
- IpSecConfig config = new IpSecConfig();
- config.setAuthenticatedEncryption(AEAD_ALGO);
- config.setAuthentication(AUTH_ALGO);
- try {
- mIpSecService.validateAlgorithms(config);
- fail("Expected exception; both AEAD and auth algorithm specified");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testValidateAlgorithmsAeadWithCrypt() {
- IpSecConfig config = new IpSecConfig();
- config.setAuthenticatedEncryption(AEAD_ALGO);
- config.setEncryption(CRYPT_ALGO);
- try {
- mIpSecService.validateAlgorithms(config);
- fail("Expected exception; both AEAD and crypt algorithm specified");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testValidateAlgorithmsAeadWithAuthAndCrypt() {
- IpSecConfig config = new IpSecConfig();
- config.setAuthenticatedEncryption(AEAD_ALGO);
- config.setAuthentication(AUTH_ALGO);
- config.setEncryption(CRYPT_ALGO);
- try {
- mIpSecService.validateAlgorithms(config);
- fail("Expected exception; AEAD, auth and crypt algorithm specified");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testDeleteInvalidTransform() throws Exception {
- try {
- mIpSecService.deleteTransform(1);
- fail("IllegalArgumentException not thrown");
- } catch (IllegalArgumentException e) {
- }
- }
-
- @Test
- public void testRemoveTransportModeTransform() throws Exception {
- Socket socket = new Socket();
- socket.bind(null);
- ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
- mIpSecService.removeTransportModeTransforms(pfd);
-
- verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd);
- }
-
- @Test
- public void testValidateIpAddresses() throws Exception {
- String[] invalidAddresses =
- new String[] {"www.google.com", "::", "2001::/64", "0.0.0.0", ""};
- for (String address : invalidAddresses) {
- try {
- IpSecSpiResponse spiResp =
- mIpSecService.allocateSecurityParameterIndex(
- address, DROID_SPI, new Binder());
- fail("Invalid address was passed through IpSecService validation: " + address);
- } catch (IllegalArgumentException e) {
- } catch (Exception e) {
- fail(
- "Invalid InetAddress was not caught in validation: "
- + address
- + ", Exception: "
- + e);
- }
- }
- }
-
- /**
- * This function checks if the number of encap UDP socket that one UID can reserve has a
- * reasonable limit.
- */
- @Test
- public void testSocketResourceTrackerLimitation() throws Exception {
- List<IpSecUdpEncapResponse> openUdpEncapSockets = new ArrayList<IpSecUdpEncapResponse>();
- // Reserve sockets until it fails.
- for (int i = 0; i < MAX_NUM_ENCAP_SOCKETS; i++) {
- IpSecUdpEncapResponse newUdpEncapSocket =
- mIpSecService.openUdpEncapsulationSocket(0, new Binder());
- assertNotNull(newUdpEncapSocket);
- if (IpSecManager.Status.OK != newUdpEncapSocket.status) {
- break;
- }
- openUdpEncapSockets.add(newUdpEncapSocket);
- }
- // Assert that the total sockets quota has a reasonable limit.
- assertTrue("No UDP encap socket was open", !openUdpEncapSockets.isEmpty());
- assertTrue(
- "Number of open UDP encap sockets is out of bound",
- openUdpEncapSockets.size() < MAX_NUM_ENCAP_SOCKETS);
-
- // Try to reserve one more UDP encapsulation socket, and should fail.
- IpSecUdpEncapResponse extraUdpEncapSocket =
- mIpSecService.openUdpEncapsulationSocket(0, new Binder());
- assertNotNull(extraUdpEncapSocket);
- assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraUdpEncapSocket.status);
-
- // Close one of the open UDP encapsulation sockets.
- mIpSecService.closeUdpEncapsulationSocket(openUdpEncapSockets.get(0).resourceId);
- openUdpEncapSockets.get(0).fileDescriptor.close();
- openUdpEncapSockets.remove(0);
-
- // Try to reserve one more UDP encapsulation socket, and should be successful.
- extraUdpEncapSocket = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
- assertNotNull(extraUdpEncapSocket);
- assertEquals(IpSecManager.Status.OK, extraUdpEncapSocket.status);
- openUdpEncapSockets.add(extraUdpEncapSocket);
-
- // Close open UDP sockets.
- for (IpSecUdpEncapResponse openSocket : openUdpEncapSockets) {
- mIpSecService.closeUdpEncapsulationSocket(openSocket.resourceId);
- openSocket.fileDescriptor.close();
- }
- }
-
- /**
- * This function checks if the number of SPI that one UID can reserve has a reasonable limit.
- * This test does not test for both address families or duplicate SPIs because resource tracking
- * code does not depend on them.
- */
- @Test
- public void testSpiResourceTrackerLimitation() throws Exception {
- List<IpSecSpiResponse> reservedSpis = new ArrayList<IpSecSpiResponse>();
- // Return the same SPI for all SPI allocation since IpSecService only
- // tracks the resource ID.
- when(mMockNetd.ipSecAllocateSpi(
- anyInt(),
- anyString(),
- eq(InetAddress.getLoopbackAddress().getHostAddress()),
- anyInt()))
- .thenReturn(DROID_SPI);
- // Reserve spis until it fails.
- for (int i = 0; i < MAX_NUM_SPIS; i++) {
- IpSecSpiResponse newSpi =
- mIpSecService.allocateSecurityParameterIndex(
- InetAddress.getLoopbackAddress().getHostAddress(),
- DROID_SPI + i,
- new Binder());
- assertNotNull(newSpi);
- if (IpSecManager.Status.OK != newSpi.status) {
- break;
- }
- reservedSpis.add(newSpi);
- }
- // Assert that the SPI quota has a reasonable limit.
- assertTrue(reservedSpis.size() > 0 && reservedSpis.size() < MAX_NUM_SPIS);
-
- // Try to reserve one more SPI, and should fail.
- IpSecSpiResponse extraSpi =
- mIpSecService.allocateSecurityParameterIndex(
- InetAddress.getLoopbackAddress().getHostAddress(),
- DROID_SPI + MAX_NUM_SPIS,
- new Binder());
- assertNotNull(extraSpi);
- assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraSpi.status);
-
- // Release one reserved spi.
- mIpSecService.releaseSecurityParameterIndex(reservedSpis.get(0).resourceId);
- reservedSpis.remove(0);
-
- // Should successfully reserve one more spi.
- extraSpi =
- mIpSecService.allocateSecurityParameterIndex(
- InetAddress.getLoopbackAddress().getHostAddress(),
- DROID_SPI + MAX_NUM_SPIS,
- new Binder());
- assertNotNull(extraSpi);
- assertEquals(IpSecManager.Status.OK, extraSpi.status);
-
- // Release reserved SPIs.
- for (IpSecSpiResponse spiResp : reservedSpis) {
- mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
- }
- }
-
- @Test
- public void testUidFdtagger() throws Exception {
- SocketTagger actualSocketTagger = SocketTagger.get();
-
- try {
- FileDescriptor sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-
- // Has to be done after socket creation because BlockGuardOS calls tag on new sockets
- SocketTagger mockSocketTagger = mock(SocketTagger.class);
- SocketTagger.set(mockSocketTagger);
-
- mIpSecService.mUidFdTagger.tag(sockFd, Process.LAST_APPLICATION_UID);
- verify(mockSocketTagger).tag(eq(sockFd));
- } finally {
- SocketTagger.set(actualSocketTagger);
- }
- }
-
- /**
- * Checks if two file descriptors point to the same file.
- *
- * <p>According to stat.h documentation, the correct way to check for equivalent or duplicated
- * file descriptors is to check their inode and device. These two entries uniquely identify any
- * file.
- */
- private boolean fileDescriptorsEqual(FileDescriptor fd1, FileDescriptor fd2) {
- try {
- StructStat fd1Stat = Os.fstat(fd1);
- StructStat fd2Stat = Os.fstat(fd2);
-
- return fd1Stat.st_ino == fd2Stat.st_ino && fd1Stat.st_dev == fd2Stat.st_dev;
- } catch (ErrnoException e) {
- return false;
- }
- }
-
- @Test
- public void testOpenUdpEncapSocketTagsSocket() throws Exception {
- IpSecService.UidFdTagger mockTagger = mock(IpSecService.UidFdTagger.class);
- IpSecService testIpSecService = new IpSecService(
- mMockContext, mMockIpSecSrvConfig, mockTagger);
-
- IpSecUdpEncapResponse udpEncapResp =
- testIpSecService.openUdpEncapsulationSocket(0, new Binder());
- assertNotNull(udpEncapResp);
- assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
-
- FileDescriptor sockFd = udpEncapResp.fileDescriptor.getFileDescriptor();
- ArgumentMatcher<FileDescriptor> fdMatcher =
- (argFd) -> {
- return fileDescriptorsEqual(sockFd, argFd);
- };
- verify(mockTagger).tag(argThat(fdMatcher), eq(Os.getuid()));
-
- testIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
- udpEncapResp.fileDescriptor.close();
- }
-
- @Test
- public void testOpenUdpEncapsulationSocketCallsSetEncapSocketOwner() throws Exception {
- IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(0, new Binder());
-
- FileDescriptor sockFd = udpEncapResp.fileDescriptor.getFileDescriptor();
- ArgumentMatcher<ParcelFileDescriptor> fdMatcher = (arg) -> {
- try {
- StructStat sockStat = Os.fstat(sockFd);
- StructStat argStat = Os.fstat(arg.getFileDescriptor());
-
- return sockStat.st_ino == argStat.st_ino
- && sockStat.st_dev == argStat.st_dev;
- } catch (ErrnoException e) {
- return false;
- }
- };
-
- verify(mMockNetd).ipSecSetEncapSocketOwner(argThat(fdMatcher), eq(Os.getuid()));
- mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
- }
-
- @Test
- public void testReserveNetId() {
- final Range<Integer> netIdRange = ConnectivityManager.getIpSecNetIdRange();
- for (int netId = netIdRange.getLower(); netId <= netIdRange.getUpper(); netId++) {
- assertEquals(netId, mIpSecService.reserveNetId());
- }
-
- // Check that resource exhaustion triggers an exception
- try {
- mIpSecService.reserveNetId();
- fail("Did not throw error for all netIds reserved");
- } catch (IllegalStateException expected) {
- }
-
- // Now release one and try again
- int releasedNetId =
- netIdRange.getLower() + (netIdRange.getUpper() - netIdRange.getLower()) / 2;
- mIpSecService.releaseNetId(releasedNetId);
- assertEquals(releasedNetId, mIpSecService.reserveNetId());
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/LegacyTypeTrackerTest.kt b/packages/Connectivity/tests/unit/java/com/android/server/LegacyTypeTrackerTest.kt
deleted file mode 100644
index 5ec1119..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/LegacyTypeTrackerTest.kt
+++ /dev/null
@@ -1,197 +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.
- */
-
-// Don't warn about deprecated types anywhere in this test, because LegacyTypeTracker's very reason
-// for existence is to power deprecated APIs. The annotation has to apply to the whole file because
-// otherwise warnings will be generated by the imports of deprecated constants like TYPE_xxx.
-@file:Suppress("DEPRECATION")
-
-package com.android.server
-
-import android.content.Context
-import android.content.pm.PackageManager
-import android.content.pm.PackageManager.FEATURE_WIFI
-import android.content.pm.PackageManager.FEATURE_WIFI_DIRECT
-import android.net.ConnectivityManager.TYPE_ETHERNET
-import android.net.ConnectivityManager.TYPE_MOBILE
-import android.net.ConnectivityManager.TYPE_MOBILE_CBS
-import android.net.ConnectivityManager.TYPE_MOBILE_DUN
-import android.net.ConnectivityManager.TYPE_MOBILE_EMERGENCY
-import android.net.ConnectivityManager.TYPE_MOBILE_FOTA
-import android.net.ConnectivityManager.TYPE_MOBILE_HIPRI
-import android.net.ConnectivityManager.TYPE_MOBILE_IA
-import android.net.ConnectivityManager.TYPE_MOBILE_IMS
-import android.net.ConnectivityManager.TYPE_MOBILE_MMS
-import android.net.ConnectivityManager.TYPE_MOBILE_SUPL
-import android.net.ConnectivityManager.TYPE_VPN
-import android.net.ConnectivityManager.TYPE_WIFI
-import android.net.ConnectivityManager.TYPE_WIFI_P2P
-import android.net.ConnectivityManager.TYPE_WIMAX
-import android.net.EthernetManager
-import android.net.NetworkInfo.DetailedState.CONNECTED
-import android.net.NetworkInfo.DetailedState.DISCONNECTED
-import android.telephony.TelephonyManager
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.server.ConnectivityService.LegacyTypeTracker
-import com.android.server.connectivity.NetworkAgentInfo
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertNull
-import org.junit.Assert.assertSame
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.Mockito.doReturn
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.reset
-import org.mockito.Mockito.verify
-
-const val UNSUPPORTED_TYPE = TYPE_WIMAX
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class LegacyTypeTrackerTest {
- private val supportedTypes = arrayOf(TYPE_WIFI, TYPE_WIFI_P2P, TYPE_ETHERNET, TYPE_MOBILE,
- TYPE_MOBILE_SUPL, TYPE_MOBILE_MMS, TYPE_MOBILE_SUPL, TYPE_MOBILE_DUN, TYPE_MOBILE_HIPRI,
- TYPE_MOBILE_FOTA, TYPE_MOBILE_IMS, TYPE_MOBILE_CBS, TYPE_MOBILE_IA,
- TYPE_MOBILE_EMERGENCY, TYPE_VPN)
-
- private val mMockService = mock(ConnectivityService::class.java).apply {
- doReturn(false).`when`(this).isDefaultNetwork(any())
- }
- private val mPm = mock(PackageManager::class.java)
- private val mContext = mock(Context::class.java).apply {
- doReturn(true).`when`(mPm).hasSystemFeature(FEATURE_WIFI)
- doReturn(true).`when`(mPm).hasSystemFeature(FEATURE_WIFI_DIRECT)
- doReturn(mPm).`when`(this).packageManager
- doReturn(mock(EthernetManager::class.java)).`when`(this).getSystemService(
- Context.ETHERNET_SERVICE)
- }
- private val mTm = mock(TelephonyManager::class.java).apply {
- doReturn(true).`when`(this).isDataCapable
- }
-
- private fun makeTracker() = LegacyTypeTracker(mMockService).apply {
- loadSupportedTypes(mContext, mTm)
- }
-
- @Test
- fun testSupportedTypes() {
- val tracker = makeTracker()
- supportedTypes.forEach {
- assertTrue(tracker.isTypeSupported(it))
- }
- assertFalse(tracker.isTypeSupported(UNSUPPORTED_TYPE))
- }
-
- @Test
- fun testSupportedTypes_NoEthernet() {
- doReturn(null).`when`(mContext).getSystemService(Context.ETHERNET_SERVICE)
- assertFalse(makeTracker().isTypeSupported(TYPE_ETHERNET))
- }
-
- @Test
- fun testSupportedTypes_NoTelephony() {
- doReturn(false).`when`(mTm).isDataCapable
- val tracker = makeTracker()
- val nonMobileTypes = arrayOf(TYPE_WIFI, TYPE_WIFI_P2P, TYPE_ETHERNET, TYPE_VPN)
- nonMobileTypes.forEach {
- assertTrue(tracker.isTypeSupported(it))
- }
- supportedTypes.toSet().minus(nonMobileTypes).forEach {
- assertFalse(tracker.isTypeSupported(it))
- }
- }
-
- @Test
- fun testSupportedTypes_NoWifiDirect() {
- doReturn(false).`when`(mPm).hasSystemFeature(FEATURE_WIFI_DIRECT)
- val tracker = makeTracker()
- assertFalse(tracker.isTypeSupported(TYPE_WIFI_P2P))
- supportedTypes.toSet().minus(TYPE_WIFI_P2P).forEach {
- assertTrue(tracker.isTypeSupported(it))
- }
- }
-
- @Test
- fun testSupl() {
- val tracker = makeTracker()
- val mobileNai = mock(NetworkAgentInfo::class.java)
- tracker.add(TYPE_MOBILE, mobileNai)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE)
- reset(mMockService)
- tracker.add(TYPE_MOBILE_SUPL, mobileNai)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
- reset(mMockService)
- tracker.remove(TYPE_MOBILE_SUPL, mobileNai, false /* wasDefault */)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
- reset(mMockService)
- tracker.add(TYPE_MOBILE_SUPL, mobileNai)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, CONNECTED, TYPE_MOBILE_SUPL)
- reset(mMockService)
- tracker.remove(mobileNai, false)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE_SUPL)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai, DISCONNECTED, TYPE_MOBILE)
- }
-
- @Test
- fun testAddNetwork() {
- val tracker = makeTracker()
- val mobileNai = mock(NetworkAgentInfo::class.java)
- val wifiNai = mock(NetworkAgentInfo::class.java)
- tracker.add(TYPE_MOBILE, mobileNai)
- tracker.add(TYPE_WIFI, wifiNai)
- assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
- assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
- // Make sure adding a second NAI does not change the results.
- val secondMobileNai = mock(NetworkAgentInfo::class.java)
- tracker.add(TYPE_MOBILE, secondMobileNai)
- assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
- assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
- // Make sure removing a network that wasn't added for this type is a no-op.
- tracker.remove(TYPE_MOBILE, wifiNai, false /* wasDefault */)
- assertSame(tracker.getNetworkForType(TYPE_MOBILE), mobileNai)
- assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
- // Remove the top network for mobile and make sure the second one becomes the network
- // of record for this type.
- tracker.remove(TYPE_MOBILE, mobileNai, false /* wasDefault */)
- assertSame(tracker.getNetworkForType(TYPE_MOBILE), secondMobileNai)
- assertSame(tracker.getNetworkForType(TYPE_WIFI), wifiNai)
- // Make sure adding a network for an unsupported type does not register it.
- tracker.add(UNSUPPORTED_TYPE, mobileNai)
- assertNull(tracker.getNetworkForType(UNSUPPORTED_TYPE))
- }
-
- @Test
- fun testBroadcastOnDisconnect() {
- val tracker = makeTracker()
- val mobileNai1 = mock(NetworkAgentInfo::class.java)
- val mobileNai2 = mock(NetworkAgentInfo::class.java)
- doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai1)
- tracker.add(TYPE_MOBILE, mobileNai1)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, CONNECTED, TYPE_MOBILE)
- reset(mMockService)
- doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai2)
- tracker.add(TYPE_MOBILE, mobileNai2)
- verify(mMockService, never()).sendLegacyNetworkBroadcast(any(), any(), anyInt())
- tracker.remove(TYPE_MOBILE, mobileNai1, false /* wasDefault */)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, DISCONNECTED, TYPE_MOBILE)
- verify(mMockService).sendLegacyNetworkBroadcast(mobileNai2, CONNECTED, TYPE_MOBILE)
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/NetIdManagerTest.kt b/packages/Connectivity/tests/unit/java/com/android/server/NetIdManagerTest.kt
deleted file mode 100644
index 6f5e740..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/NetIdManagerTest.kt
+++ /dev/null
@@ -1,53 +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.server
-
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.server.NetIdManager.MIN_NET_ID
-import com.android.testutils.assertThrows
-import com.android.testutils.ExceptionUtils.ThrowingRunnable
-import org.junit.Test
-import org.junit.runner.RunWith
-import kotlin.test.assertEquals
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class NetIdManagerTest {
- @Test
- fun testReserveReleaseNetId() {
- val manager = NetIdManager(MIN_NET_ID + 4)
- assertEquals(MIN_NET_ID, manager.reserveNetId())
- assertEquals(MIN_NET_ID + 1, manager.reserveNetId())
- assertEquals(MIN_NET_ID + 2, manager.reserveNetId())
- assertEquals(MIN_NET_ID + 3, manager.reserveNetId())
-
- manager.releaseNetId(MIN_NET_ID + 1)
- manager.releaseNetId(MIN_NET_ID + 3)
- // IDs only loop once there is no higher ID available
- assertEquals(MIN_NET_ID + 4, manager.reserveNetId())
- assertEquals(MIN_NET_ID + 1, manager.reserveNetId())
- assertEquals(MIN_NET_ID + 3, manager.reserveNetId())
- assertThrows(IllegalStateException::class.java, ThrowingRunnable { manager.reserveNetId() })
- manager.releaseNetId(MIN_NET_ID + 5)
- // Still no ID available: MIN_NET_ID + 5 was not reserved
- assertThrows(IllegalStateException::class.java, ThrowingRunnable { manager.reserveNetId() })
- manager.releaseNetId(MIN_NET_ID + 2)
- // Throwing an exception still leaves the manager in a working state
- assertEquals(MIN_NET_ID + 2, manager.reserveNetId())
- }
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/NetworkManagementServiceTest.java b/packages/Connectivity/tests/unit/java/com/android/server/NetworkManagementServiceTest.java
deleted file mode 100644
index 13516d7..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/NetworkManagementServiceTest.java
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static android.util.DebugUtils.valueToString;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.net.INetd;
-import android.net.INetdUnsolicitedEventListener;
-import android.net.LinkAddress;
-import android.net.NetworkPolicyManager;
-import android.os.BatteryStats;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteException;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.ArrayMap;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.app.IBatteryStats;
-import com.android.server.NetworkManagementService.Dependencies;
-import com.android.server.net.BaseNetworkObserver;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.function.BiFunction;
-
-/**
- * Tests for {@link NetworkManagementService}.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkManagementServiceTest {
- private NetworkManagementService mNMService;
- @Mock private Context mContext;
- @Mock private IBatteryStats.Stub mBatteryStatsService;
- @Mock private INetd.Stub mNetdService;
-
- private static final int TEST_UID = 111;
-
- @NonNull
- @Captor
- private ArgumentCaptor<INetdUnsolicitedEventListener> mUnsolListenerCaptor;
-
- private final MockDependencies mDeps = new MockDependencies();
-
- private final class MockDependencies extends Dependencies {
- @Override
- public IBinder getService(String name) {
- switch (name) {
- case BatteryStats.SERVICE_NAME:
- return mBatteryStatsService;
- default:
- throw new UnsupportedOperationException("Unknown service " + name);
- }
- }
-
- @Override
- public void registerLocalService(NetworkManagementInternal nmi) {
- }
-
- @Override
- public INetd getNetd() {
- return mNetdService;
- }
-
- @Override
- public int getCallingUid() {
- return Process.SYSTEM_UID;
- }
- }
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- doNothing().when(mNetdService)
- .registerUnsolicitedEventListener(mUnsolListenerCaptor.capture());
- // Start the service and wait until it connects to our socket.
- mNMService = NetworkManagementService.create(mContext, mDeps);
- }
-
- @After
- public void tearDown() throws Exception {
- mNMService.shutdown();
- }
-
- private static <T> T expectSoon(T mock) {
- return verify(mock, timeout(200));
- }
-
- /**
- * Tests that network observers work properly.
- */
- @Test
- public void testNetworkObservers() throws Exception {
- BaseNetworkObserver observer = mock(BaseNetworkObserver.class);
- doReturn(new Binder()).when(observer).asBinder(); // Used by registerObserver.
- mNMService.registerObserver(observer);
-
- // Forget everything that happened to the mock so far, so we can explicitly verify
- // everything that happens and does not happen to it from now on.
-
- INetdUnsolicitedEventListener unsolListener = mUnsolListenerCaptor.getValue();
- reset(observer);
- // Now call unsolListener methods and ensure that the observer methods are
- // called. After every method we expect a callback soon after; to ensure that
- // invalid messages don't cause any callbacks, we call verifyNoMoreInteractions at the end.
-
- /**
- * Interface changes.
- */
- unsolListener.onInterfaceAdded("rmnet12");
- expectSoon(observer).interfaceAdded("rmnet12");
-
- unsolListener.onInterfaceRemoved("eth1");
- expectSoon(observer).interfaceRemoved("eth1");
-
- unsolListener.onInterfaceChanged("clat4", true);
- expectSoon(observer).interfaceStatusChanged("clat4", true);
-
- unsolListener.onInterfaceLinkStateChanged("rmnet0", false);
- expectSoon(observer).interfaceLinkStateChanged("rmnet0", false);
-
- /**
- * Bandwidth control events.
- */
- unsolListener.onQuotaLimitReached("data", "rmnet_usb0");
- expectSoon(observer).limitReached("data", "rmnet_usb0");
-
- /**
- * Interface class activity.
- */
- unsolListener.onInterfaceClassActivityChanged(true, 1, 1234, TEST_UID);
- expectSoon(observer).interfaceClassDataActivityChanged(1, true, 1234, TEST_UID);
-
- unsolListener.onInterfaceClassActivityChanged(false, 9, 5678, TEST_UID);
- expectSoon(observer).interfaceClassDataActivityChanged(9, false, 5678, TEST_UID);
-
- unsolListener.onInterfaceClassActivityChanged(false, 9, 4321, TEST_UID);
- expectSoon(observer).interfaceClassDataActivityChanged(9, false, 4321, TEST_UID);
-
- /**
- * IP address changes.
- */
- unsolListener.onInterfaceAddressUpdated("fe80::1/64", "wlan0", 128, 253);
- expectSoon(observer).addressUpdated("wlan0", new LinkAddress("fe80::1/64", 128, 253));
-
- unsolListener.onInterfaceAddressRemoved("fe80::1/64", "wlan0", 128, 253);
- expectSoon(observer).addressRemoved("wlan0", new LinkAddress("fe80::1/64", 128, 253));
-
- unsolListener.onInterfaceAddressRemoved("2001:db8::1/64", "wlan0", 1, 0);
- expectSoon(observer).addressRemoved("wlan0", new LinkAddress("2001:db8::1/64", 1, 0));
-
- /**
- * DNS information broadcasts.
- */
- unsolListener.onInterfaceDnsServerInfo("rmnet_usb0", 3600, new String[]{"2001:db8::1"});
- expectSoon(observer).interfaceDnsServerInfo("rmnet_usb0", 3600,
- new String[]{"2001:db8::1"});
-
- unsolListener.onInterfaceDnsServerInfo("wlan0", 14400,
- new String[]{"2001:db8::1", "2001:db8::2"});
- expectSoon(observer).interfaceDnsServerInfo("wlan0", 14400,
- new String[]{"2001:db8::1", "2001:db8::2"});
-
- // We don't check for negative lifetimes, only for parse errors.
- unsolListener.onInterfaceDnsServerInfo("wlan0", -3600, new String[]{"::1"});
- expectSoon(observer).interfaceDnsServerInfo("wlan0", -3600,
- new String[]{"::1"});
-
- // No syntax checking on the addresses.
- unsolListener.onInterfaceDnsServerInfo("wlan0", 600,
- new String[]{"", "::", "", "foo", "::1"});
- expectSoon(observer).interfaceDnsServerInfo("wlan0", 600,
- new String[]{"", "::", "", "foo", "::1"});
-
- // Make sure nothing else was called.
- verifyNoMoreInteractions(observer);
- }
-
- @Test
- public void testFirewallEnabled() {
- mNMService.setFirewallEnabled(true);
- assertTrue(mNMService.isFirewallEnabled());
-
- mNMService.setFirewallEnabled(false);
- assertFalse(mNMService.isFirewallEnabled());
- }
-
- @Test
- public void testNetworkRestrictedDefault() {
- assertFalse(mNMService.isNetworkRestricted(TEST_UID));
- }
-
- @Test
- public void testMeteredNetworkRestrictions() throws RemoteException {
- // Make sure the mocked netd method returns true.
- doReturn(true).when(mNetdService).bandwidthEnableDataSaver(anyBoolean());
-
- // Restrict usage of mobile data in background
- mNMService.setUidOnMeteredNetworkDenylist(TEST_UID, true);
- assertTrue("Should be true since mobile data usage is restricted",
- mNMService.isNetworkRestricted(TEST_UID));
-
- mNMService.setDataSaverModeEnabled(true);
- verify(mNetdService).bandwidthEnableDataSaver(true);
-
- mNMService.setUidOnMeteredNetworkDenylist(TEST_UID, false);
- assertTrue("Should be true since data saver is on and the uid is not allowlisted",
- mNMService.isNetworkRestricted(TEST_UID));
-
- mNMService.setUidOnMeteredNetworkAllowlist(TEST_UID, true);
- assertFalse("Should be false since data saver is on and the uid is allowlisted",
- mNMService.isNetworkRestricted(TEST_UID));
-
- // remove uid from allowlist and turn datasaver off again
- mNMService.setUidOnMeteredNetworkAllowlist(TEST_UID, false);
- mNMService.setDataSaverModeEnabled(false);
- verify(mNetdService).bandwidthEnableDataSaver(false);
- assertFalse("Network should not be restricted when data saver is off",
- mNMService.isNetworkRestricted(TEST_UID));
- }
-
- @Test
- public void testFirewallChains() {
- final ArrayMap<Integer, ArrayMap<Integer, Boolean>> expected = new ArrayMap<>();
- // Dozable chain
- final ArrayMap<Integer, Boolean> isRestrictedForDozable = new ArrayMap<>();
- isRestrictedForDozable.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
- isRestrictedForDozable.put(INetd.FIREWALL_RULE_ALLOW, false);
- isRestrictedForDozable.put(INetd.FIREWALL_RULE_DENY, true);
- expected.put(INetd.FIREWALL_CHAIN_DOZABLE, isRestrictedForDozable);
- // Powersaver chain
- final ArrayMap<Integer, Boolean> isRestrictedForPowerSave = new ArrayMap<>();
- isRestrictedForPowerSave.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
- isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_ALLOW, false);
- isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_DENY, true);
- expected.put(INetd.FIREWALL_CHAIN_POWERSAVE, isRestrictedForPowerSave);
- // Standby chain
- final ArrayMap<Integer, Boolean> isRestrictedForStandby = new ArrayMap<>();
- isRestrictedForStandby.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, false);
- isRestrictedForStandby.put(INetd.FIREWALL_RULE_ALLOW, false);
- isRestrictedForStandby.put(INetd.FIREWALL_RULE_DENY, true);
- expected.put(INetd.FIREWALL_CHAIN_STANDBY, isRestrictedForStandby);
- // Restricted mode chain
- final ArrayMap<Integer, Boolean> isRestrictedForRestrictedMode = new ArrayMap<>();
- isRestrictedForRestrictedMode.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
- isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_ALLOW, false);
- isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_DENY, true);
- expected.put(INetd.FIREWALL_CHAIN_RESTRICTED, isRestrictedForRestrictedMode);
-
- final int[] chains = {
- INetd.FIREWALL_CHAIN_STANDBY,
- INetd.FIREWALL_CHAIN_POWERSAVE,
- INetd.FIREWALL_CHAIN_DOZABLE,
- INetd.FIREWALL_CHAIN_RESTRICTED
- };
- final int[] states = {
- INetd.FIREWALL_RULE_ALLOW,
- INetd.FIREWALL_RULE_DENY,
- NetworkPolicyManager.FIREWALL_RULE_DEFAULT
- };
- BiFunction<Integer, Integer, String> errorMsg = (chain, state) -> {
- return String.format("Unexpected value for chain: %s and state: %s",
- valueToString(INetd.class, "FIREWALL_CHAIN_", chain),
- valueToString(INetd.class, "FIREWALL_RULE_", state));
- };
- for (int chain : chains) {
- final ArrayMap<Integer, Boolean> expectedValues = expected.get(chain);
- mNMService.setFirewallChainEnabled(chain, true);
- for (int state : states) {
- mNMService.setFirewallUidRule(chain, TEST_UID, state);
- assertEquals(errorMsg.apply(chain, state),
- expectedValues.get(state), mNMService.isNetworkRestricted(TEST_UID));
- }
- mNMService.setFirewallChainEnabled(chain, false);
- }
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/NsdServiceTest.java b/packages/Connectivity/tests/unit/java/com/android/server/NsdServiceTest.java
deleted file mode 100644
index a90fa68..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/NsdServiceTest.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.net.nsd.NsdManager;
-import android.net.nsd.NsdServiceInfo;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.NsdService.DaemonConnection;
-import com.android.server.NsdService.DaemonConnectionSupplier;
-import com.android.server.NsdService.NativeCallbackReceiver;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-// TODOs:
-// - test client can send requests and receive replies
-// - test NSD_ON ENABLE/DISABLED listening
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NsdServiceTest {
-
- static final int PROTOCOL = NsdManager.PROTOCOL_DNS_SD;
-
- long mTimeoutMs = 100; // non-final so that tests can adjust the value.
-
- @Mock Context mContext;
- @Mock ContentResolver mResolver;
- @Mock NsdService.NsdSettings mSettings;
- @Mock DaemonConnection mDaemon;
- NativeCallbackReceiver mDaemonCallback;
- HandlerThread mThread;
- TestHandler mHandler;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- mThread = new HandlerThread("mock-service-handler");
- mThread.start();
- mHandler = new TestHandler(mThread.getLooper());
- when(mContext.getContentResolver()).thenReturn(mResolver);
- }
-
- @After
- public void tearDown() throws Exception {
- if (mThread != null) {
- mThread.quit();
- mThread = null;
- }
- }
-
- @Test
- public void testClientsCanConnectAndDisconnect() {
- when(mSettings.isEnabled()).thenReturn(true);
-
- NsdService service = makeService();
-
- NsdManager client1 = connectClient(service);
- verify(mDaemon, timeout(100).times(1)).start();
-
- NsdManager client2 = connectClient(service);
-
- client1.disconnect();
- client2.disconnect();
-
- verify(mDaemon, timeout(mTimeoutMs).times(1)).stop();
-
- client1.disconnect();
- client2.disconnect();
- }
-
- @Test
- public void testClientRequestsAreGCedAtDisconnection() {
- when(mSettings.isEnabled()).thenReturn(true);
- when(mDaemon.execute(any())).thenReturn(true);
-
- NsdService service = makeService();
- NsdManager client = connectClient(service);
-
- verify(mDaemon, timeout(100).times(1)).start();
-
- NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
- request.setPort(2201);
-
- // Client registration request
- NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
- client.registerService(request, PROTOCOL, listener1);
- verifyDaemonCommand("register 2 a_name a_type 2201");
-
- // Client discovery request
- NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
- client.discoverServices("a_type", PROTOCOL, listener2);
- verifyDaemonCommand("discover 3 a_type");
-
- // Client resolve request
- NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
- client.resolveService(request, listener3);
- verifyDaemonCommand("resolve 4 a_name a_type local.");
-
- // Client disconnects
- client.disconnect();
- verify(mDaemon, timeout(mTimeoutMs).times(1)).stop();
-
- // checks that request are cleaned
- verifyDaemonCommands("stop-register 2", "stop-discover 3", "stop-resolve 4");
-
- client.disconnect();
- }
-
- NsdService makeService() {
- DaemonConnectionSupplier supplier = (callback) -> {
- mDaemonCallback = callback;
- return mDaemon;
- };
- NsdService service = new NsdService(mContext, mSettings, mHandler, supplier);
- verify(mDaemon, never()).execute(any(String.class));
- return service;
- }
-
- NsdManager connectClient(NsdService service) {
- return new NsdManager(mContext, service);
- }
-
- void verifyDaemonCommands(String... wants) {
- verifyDaemonCommand(String.join(" ", wants), wants.length);
- }
-
- void verifyDaemonCommand(String want) {
- verifyDaemonCommand(want, 1);
- }
-
- void verifyDaemonCommand(String want, int n) {
- ArgumentCaptor<Object> argumentsCaptor = ArgumentCaptor.forClass(Object.class);
- verify(mDaemon, timeout(mTimeoutMs).times(n)).execute(argumentsCaptor.capture());
- String got = "";
- for (Object o : argumentsCaptor.getAllValues()) {
- got += o + " ";
- }
- assertEquals(want, got.trim());
- // rearm deamon for next command verification
- reset(mDaemon);
- when(mDaemon.execute(any())).thenReturn(true);
- }
-
- public static class TestHandler extends Handler {
- public Message lastMessage;
-
- TestHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- lastMessage = obtainMessage();
- lastMessage.copyFrom(msg);
- }
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java
deleted file mode 100644
index 0ffeec9..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * Copyright (C) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_DEFAULT_MODE;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
-import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_SPECIFIER;
-import static android.net.NetworkCapabilities.MAX_TRANSPORT;
-import static android.net.NetworkCapabilities.MIN_TRANSPORT;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE;
-import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS;
-
-import static com.android.testutils.MiscAsserts.assertContainsExactly;
-import static com.android.testutils.MiscAsserts.assertContainsStringsExactly;
-import static com.android.testutils.MiscAsserts.assertFieldCountEquals;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.net.ConnectivitySettingsManager;
-import android.net.IDnsResolver;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.ResolverOptionsParcel;
-import android.net.ResolverParamsParcel;
-import android.net.RouteInfo;
-import android.net.shared.PrivateDnsConfig;
-import android.provider.Settings;
-import android.test.mock.MockContentResolver;
-import android.util.SparseArray;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.MessageUtils;
-import com.android.internal.util.test.FakeSettingsProvider;
-
-import libcore.net.InetAddressUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.net.InetAddress;
-import java.util.Arrays;
-
-/**
- * Tests for {@link DnsManager}.
- *
- * Build, install and run with:
- * runtest frameworks-net -c com.android.server.connectivity.DnsManagerTest
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class DnsManagerTest {
- static final String TEST_IFACENAME = "test_wlan0";
- static final int TEST_NETID = 100;
- static final int TEST_NETID_ALTERNATE = 101;
- static final int TEST_NETID_UNTRACKED = 102;
- static final int TEST_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800;
- static final int TEST_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25;
- static final int TEST_DEFAULT_MIN_SAMPLES = 8;
- static final int TEST_DEFAULT_MAX_SAMPLES = 64;
- static final int[] TEST_TRANSPORT_TYPES = {TRANSPORT_WIFI, TRANSPORT_VPN};
-
- DnsManager mDnsManager;
- MockContentResolver mContentResolver;
-
- @Mock Context mCtx;
- @Mock IDnsResolver mMockDnsResolver;
-
- private void assertResolverOptionsEquals(
- @NonNull ResolverOptionsParcel actual,
- @NonNull ResolverOptionsParcel expected) {
- assertEquals(actual.hosts, expected.hosts);
- assertEquals(actual.tcMode, expected.tcMode);
- assertEquals(actual.enforceDnsUid, expected.enforceDnsUid);
- assertFieldCountEquals(3, ResolverOptionsParcel.class);
- }
-
- private void assertResolverParamsEquals(@NonNull ResolverParamsParcel actual,
- @NonNull ResolverParamsParcel expected) {
- assertEquals(actual.netId, expected.netId);
- assertEquals(actual.sampleValiditySeconds, expected.sampleValiditySeconds);
- assertEquals(actual.successThreshold, expected.successThreshold);
- assertEquals(actual.minSamples, expected.minSamples);
- assertEquals(actual.maxSamples, expected.maxSamples);
- assertEquals(actual.baseTimeoutMsec, expected.baseTimeoutMsec);
- assertEquals(actual.retryCount, expected.retryCount);
- assertContainsStringsExactly(actual.servers, expected.servers);
- assertContainsStringsExactly(actual.domains, expected.domains);
- assertEquals(actual.tlsName, expected.tlsName);
- assertContainsStringsExactly(actual.tlsServers, expected.tlsServers);
- assertContainsStringsExactly(actual.tlsFingerprints, expected.tlsFingerprints);
- assertEquals(actual.caCertificate, expected.caCertificate);
- assertEquals(actual.tlsConnectTimeoutMs, expected.tlsConnectTimeoutMs);
- assertResolverOptionsEquals(actual.resolverOptions, expected.resolverOptions);
- assertContainsExactly(actual.transportTypes, expected.transportTypes);
- assertFieldCountEquals(16, ResolverParamsParcel.class);
- }
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- mContentResolver = new MockContentResolver();
- mContentResolver.addProvider(Settings.AUTHORITY,
- new FakeSettingsProvider());
- when(mCtx.getContentResolver()).thenReturn(mContentResolver);
- mDnsManager = new DnsManager(mCtx, mMockDnsResolver);
-
- // Clear the private DNS settings
- Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "");
- Settings.Global.putString(mContentResolver, PRIVATE_DNS_MODE, "");
- Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "");
- }
-
- @Test
- public void testTrackedValidationUpdates() throws Exception {
- mDnsManager.updatePrivateDns(new Network(TEST_NETID),
- mDnsManager.getPrivateDnsConfig());
- mDnsManager.updatePrivateDns(new Network(TEST_NETID_ALTERNATE),
- mDnsManager.getPrivateDnsConfig());
- LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(TEST_IFACENAME);
- lp.addDnsServer(InetAddress.getByName("3.3.3.3"));
- lp.addDnsServer(InetAddress.getByName("4.4.4.4"));
-
- // Send a validation event that is tracked on the alternate netId
- mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
- mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.flushVmDnsCache();
- mDnsManager.updateTransportsForNetwork(TEST_NETID_ALTERNATE, TEST_TRANSPORT_TYPES);
- mDnsManager.noteDnsServersForNetwork(TEST_NETID_ALTERNATE, lp);
- mDnsManager.flushVmDnsCache();
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_ALTERNATE,
- InetAddress.parseNumericAddress("4.4.4.4"), "",
- VALIDATION_RESULT_SUCCESS));
- LinkProperties fixedLp = new LinkProperties(lp);
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
- assertFalse(fixedLp.isPrivateDnsActive());
- assertNull(fixedLp.getPrivateDnsServerName());
- fixedLp = new LinkProperties(lp);
- mDnsManager.updatePrivateDnsStatus(TEST_NETID_ALTERNATE, fixedLp);
- assertTrue(fixedLp.isPrivateDnsActive());
- assertNull(fixedLp.getPrivateDnsServerName());
- assertEquals(Arrays.asList(InetAddress.getByName("4.4.4.4")),
- fixedLp.getValidatedPrivateDnsServers());
-
- // Set up addresses for strict mode and switch to it.
- lp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
- lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
- TEST_IFACENAME));
- lp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
- lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
- TEST_IFACENAME));
-
- ConnectivitySettingsManager.setPrivateDnsMode(mCtx, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
- ConnectivitySettingsManager.setPrivateDnsHostname(mCtx, "strictmode.com");
- mDnsManager.updatePrivateDns(new Network(TEST_NETID),
- new PrivateDnsConfig("strictmode.com", new InetAddress[] {
- InetAddress.parseNumericAddress("6.6.6.6"),
- InetAddress.parseNumericAddress("2001:db8:66:66::1")
- }));
- mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
- mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.flushVmDnsCache();
- fixedLp = new LinkProperties(lp);
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
- assertTrue(fixedLp.isPrivateDnsActive());
- assertEquals("strictmode.com", fixedLp.getPrivateDnsServerName());
- // No validation events yet.
- assertEquals(Arrays.asList(new InetAddress[0]), fixedLp.getValidatedPrivateDnsServers());
- // Validate one.
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
- InetAddress.parseNumericAddress("6.6.6.6"), "strictmode.com",
- VALIDATION_RESULT_SUCCESS));
- fixedLp = new LinkProperties(lp);
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
- assertEquals(Arrays.asList(InetAddress.parseNumericAddress("6.6.6.6")),
- fixedLp.getValidatedPrivateDnsServers());
- // Validate the 2nd one.
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
- InetAddress.parseNumericAddress("2001:db8:66:66::1"), "strictmode.com",
- VALIDATION_RESULT_SUCCESS));
- fixedLp = new LinkProperties(lp);
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
- assertEquals(Arrays.asList(
- InetAddress.parseNumericAddress("2001:db8:66:66::1"),
- InetAddress.parseNumericAddress("6.6.6.6")),
- fixedLp.getValidatedPrivateDnsServers());
- }
-
- @Test
- public void testIgnoreUntrackedValidationUpdates() throws Exception {
- // The PrivateDnsConfig map is empty, so no validation events will
- // be tracked.
- LinkProperties lp = new LinkProperties();
- lp.addDnsServer(InetAddress.getByName("3.3.3.3"));
- mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
- mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.flushVmDnsCache();
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
- InetAddress.parseNumericAddress("3.3.3.3"), "",
- VALIDATION_RESULT_SUCCESS));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- assertFalse(lp.isPrivateDnsActive());
- assertNull(lp.getPrivateDnsServerName());
-
- // Validation event has untracked netId
- mDnsManager.updatePrivateDns(new Network(TEST_NETID),
- mDnsManager.getPrivateDnsConfig());
- mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
- mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.flushVmDnsCache();
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_UNTRACKED,
- InetAddress.parseNumericAddress("3.3.3.3"), "",
- VALIDATION_RESULT_SUCCESS));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- assertFalse(lp.isPrivateDnsActive());
- assertNull(lp.getPrivateDnsServerName());
-
- // Validation event has untracked ipAddress
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
- InetAddress.parseNumericAddress("4.4.4.4"), "",
- VALIDATION_RESULT_SUCCESS));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- assertFalse(lp.isPrivateDnsActive());
- assertNull(lp.getPrivateDnsServerName());
-
- // Validation event has untracked hostname
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
- InetAddress.parseNumericAddress("3.3.3.3"), "hostname",
- VALIDATION_RESULT_SUCCESS));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- assertFalse(lp.isPrivateDnsActive());
- assertNull(lp.getPrivateDnsServerName());
-
- // Validation event failed
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
- InetAddress.parseNumericAddress("3.3.3.3"), "",
- VALIDATION_RESULT_FAILURE));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- assertFalse(lp.isPrivateDnsActive());
- assertNull(lp.getPrivateDnsServerName());
-
- // Network removed
- mDnsManager.removeNetwork(new Network(TEST_NETID));
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
- InetAddress.parseNumericAddress("3.3.3.3"), "", VALIDATION_RESULT_SUCCESS));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- assertFalse(lp.isPrivateDnsActive());
- assertNull(lp.getPrivateDnsServerName());
-
- // Turn private DNS mode off
- ConnectivitySettingsManager.setPrivateDnsMode(mCtx, PRIVATE_DNS_MODE_OFF);
- mDnsManager.updatePrivateDns(new Network(TEST_NETID),
- mDnsManager.getPrivateDnsConfig());
- mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
- mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.flushVmDnsCache();
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
- InetAddress.parseNumericAddress("3.3.3.3"), "",
- VALIDATION_RESULT_SUCCESS));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- assertFalse(lp.isPrivateDnsActive());
- assertNull(lp.getPrivateDnsServerName());
- }
-
- @Test
- public void testOverrideDefaultMode() throws Exception {
- // Hard-coded default is opportunistic mode.
- final PrivateDnsConfig cfgAuto = DnsManager.getPrivateDnsConfig(mCtx);
- assertTrue(cfgAuto.useTls);
- assertEquals("", cfgAuto.hostname);
- assertEquals(new InetAddress[0], cfgAuto.ips);
-
- // Pretend a gservices push sets the default to "off".
- ConnectivitySettingsManager.setPrivateDnsDefaultMode(mCtx, PRIVATE_DNS_MODE_OFF);
- final PrivateDnsConfig cfgOff = DnsManager.getPrivateDnsConfig(mCtx);
- assertFalse(cfgOff.useTls);
- assertEquals("", cfgOff.hostname);
- assertEquals(new InetAddress[0], cfgOff.ips);
-
- // Strict mode still works.
- ConnectivitySettingsManager.setPrivateDnsMode(mCtx, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
- ConnectivitySettingsManager.setPrivateDnsHostname(mCtx, "strictmode.com");
- final PrivateDnsConfig cfgStrict = DnsManager.getPrivateDnsConfig(mCtx);
- assertTrue(cfgStrict.useTls);
- assertEquals("strictmode.com", cfgStrict.hostname);
- assertEquals(new InetAddress[0], cfgStrict.ips);
- }
-
- @Test
- public void testSendDnsConfiguration() throws Exception {
- reset(mMockDnsResolver);
- mDnsManager.updatePrivateDns(new Network(TEST_NETID),
- mDnsManager.getPrivateDnsConfig());
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(TEST_IFACENAME);
- lp.addDnsServer(InetAddress.getByName("3.3.3.3"));
- lp.addDnsServer(InetAddress.getByName("4.4.4.4"));
- mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
- mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.flushVmDnsCache();
-
- final ArgumentCaptor<ResolverParamsParcel> resolverParamsParcelCaptor =
- ArgumentCaptor.forClass(ResolverParamsParcel.class);
- verify(mMockDnsResolver, times(1)).setResolverConfiguration(
- resolverParamsParcelCaptor.capture());
- final ResolverParamsParcel actualParams = resolverParamsParcelCaptor.getValue();
- final ResolverParamsParcel expectedParams = new ResolverParamsParcel();
- expectedParams.netId = TEST_NETID;
- expectedParams.sampleValiditySeconds = TEST_DEFAULT_SAMPLE_VALIDITY_SECONDS;
- expectedParams.successThreshold = TEST_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
- expectedParams.minSamples = TEST_DEFAULT_MIN_SAMPLES;
- expectedParams.maxSamples = TEST_DEFAULT_MAX_SAMPLES;
- expectedParams.servers = new String[]{"3.3.3.3", "4.4.4.4"};
- expectedParams.domains = new String[]{};
- expectedParams.tlsName = "";
- expectedParams.tlsServers = new String[]{"3.3.3.3", "4.4.4.4"};
- expectedParams.transportTypes = TEST_TRANSPORT_TYPES;
- expectedParams.resolverOptions = new ResolverOptionsParcel();
- assertResolverParamsEquals(actualParams, expectedParams);
- }
-
- @Test
- public void testTransportTypesEqual() throws Exception {
- SparseArray<String> ncTransTypes = MessageUtils.findMessageNames(
- new Class[] { NetworkCapabilities.class }, new String[]{ "TRANSPORT_" });
- SparseArray<String> dnsTransTypes = MessageUtils.findMessageNames(
- new Class[] { IDnsResolver.class }, new String[]{ "TRANSPORT_" });
- assertEquals(0, MIN_TRANSPORT);
- assertEquals(MAX_TRANSPORT + 1, ncTransTypes.size());
- // TRANSPORT_UNKNOWN in IDnsResolver is defined to -1 and only for resolver.
- assertEquals("TRANSPORT_UNKNOWN", dnsTransTypes.get(-1));
- assertEquals(ncTransTypes.size(), dnsTransTypes.size() - 1);
- for (int i = MIN_TRANSPORT; i < MAX_TRANSPORT; i++) {
- String name = ncTransTypes.get(i, null);
- assertNotNull("Could not find NetworkCapabilies.TRANSPORT_* constant equal to "
- + i, name);
- assertEquals(name, dnsTransTypes.get(i));
- }
- }
-
- @Test
- public void testGetPrivateDnsConfigForNetwork() throws Exception {
- final Network network = new Network(TEST_NETID);
- final InetAddress dnsAddr = InetAddressUtils.parseNumericAddress("3.3.3.3");
- final InetAddress[] tlsAddrs = new InetAddress[]{
- InetAddressUtils.parseNumericAddress("6.6.6.6"),
- InetAddressUtils.parseNumericAddress("2001:db8:66:66::1")
- };
- final String tlsName = "strictmode.com";
- LinkProperties lp = new LinkProperties();
- lp.addDnsServer(dnsAddr);
-
- // The PrivateDnsConfig map is empty, so the default PRIVATE_DNS_OFF is returned.
- PrivateDnsConfig privateDnsCfg = mDnsManager.getPrivateDnsConfig(network);
- assertFalse(privateDnsCfg.useTls);
- assertEquals("", privateDnsCfg.hostname);
- assertEquals(new InetAddress[0], privateDnsCfg.ips);
-
- // An entry with default PrivateDnsConfig is added to the PrivateDnsConfig map.
- mDnsManager.updatePrivateDns(network, mDnsManager.getPrivateDnsConfig());
- mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.updatePrivateDnsValidation(
- new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, dnsAddr, "",
- VALIDATION_RESULT_SUCCESS));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- privateDnsCfg = mDnsManager.getPrivateDnsConfig(network);
- assertTrue(privateDnsCfg.useTls);
- assertEquals("", privateDnsCfg.hostname);
- assertEquals(new InetAddress[0], privateDnsCfg.ips);
-
- // The original entry is overwritten by a new PrivateDnsConfig.
- mDnsManager.updatePrivateDns(network, new PrivateDnsConfig(tlsName, tlsAddrs));
- mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
- privateDnsCfg = mDnsManager.getPrivateDnsConfig(network);
- assertTrue(privateDnsCfg.useTls);
- assertEquals(tlsName, privateDnsCfg.hostname);
- assertEquals(tlsAddrs, privateDnsCfg.ips);
-
- // The network is removed, so the PrivateDnsConfig map becomes empty again.
- mDnsManager.removeNetwork(network);
- privateDnsCfg = mDnsManager.getPrivateDnsConfig(network);
- assertFalse(privateDnsCfg.useTls);
- assertEquals("", privateDnsCfg.hostname);
- assertEquals(new InetAddress[0], privateDnsCfg.ips);
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt
deleted file mode 100644
index 45b575a..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/FullScoreTest.kt
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity
-
-import android.net.NetworkAgentConfig
-import android.net.NetworkCapabilities
-import android.net.NetworkScore.KEEP_CONNECTED_NONE
-import android.text.TextUtils
-import android.util.ArraySet
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.server.connectivity.FullScore.MAX_CS_MANAGED_POLICY
-import com.android.server.connectivity.FullScore.POLICY_ACCEPT_UNVALIDATED
-import com.android.server.connectivity.FullScore.POLICY_EVER_USER_SELECTED
-import com.android.server.connectivity.FullScore.POLICY_IS_VALIDATED
-import com.android.server.connectivity.FullScore.POLICY_IS_VPN
-import org.junit.Test
-import org.junit.runner.RunWith
-import kotlin.collections.minOfOrNull
-import kotlin.collections.maxOfOrNull
-import kotlin.reflect.full.staticProperties
-import kotlin.test.assertEquals
-import kotlin.test.assertFailsWith
-import kotlin.test.assertFalse
-import kotlin.test.assertTrue
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class FullScoreTest {
- // Convenience methods
- fun FullScore.withPolicies(
- validated: Boolean = false,
- vpn: Boolean = false,
- onceChosen: Boolean = false,
- acceptUnvalidated: Boolean = false
- ): FullScore {
- val nac = NetworkAgentConfig.Builder().apply {
- setUnvalidatedConnectivityAcceptable(acceptUnvalidated)
- setExplicitlySelected(onceChosen)
- }.build()
- val nc = NetworkCapabilities.Builder().apply {
- if (vpn) addTransportType(NetworkCapabilities.TRANSPORT_VPN)
- if (validated) addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
- }.build()
- return mixInScore(nc, nac, validated, false /* yieldToBadWifi */)
- }
-
- @Test
- fun testGetLegacyInt() {
- val ns = FullScore(50, 0L /* policy */, KEEP_CONNECTED_NONE)
- assertEquals(10, ns.legacyInt) // -40 penalty for not being validated
- assertEquals(50, ns.legacyIntAsValidated)
-
- val vpnNs = FullScore(101, 0L /* policy */, KEEP_CONNECTED_NONE).withPolicies(vpn = true)
- assertEquals(101, vpnNs.legacyInt) // VPNs are not subject to unvalidation penalty
- assertEquals(101, vpnNs.legacyIntAsValidated)
- assertEquals(101, vpnNs.withPolicies(validated = true).legacyInt)
- assertEquals(101, vpnNs.withPolicies(validated = true).legacyIntAsValidated)
-
- val validatedNs = ns.withPolicies(validated = true)
- assertEquals(50, validatedNs.legacyInt) // No penalty, this is validated
- assertEquals(50, validatedNs.legacyIntAsValidated)
-
- val chosenNs = ns.withPolicies(onceChosen = true)
- assertEquals(10, chosenNs.legacyInt)
- assertEquals(100, chosenNs.legacyIntAsValidated)
- assertEquals(10, chosenNs.withPolicies(acceptUnvalidated = true).legacyInt)
- assertEquals(50, chosenNs.withPolicies(acceptUnvalidated = true).legacyIntAsValidated)
- }
-
- @Test
- fun testToString() {
- val string = FullScore(10, 0L /* policy */, KEEP_CONNECTED_NONE)
- .withPolicies(vpn = true, acceptUnvalidated = true).toString()
- assertTrue(string.contains("Score(10"), string)
- assertTrue(string.contains("ACCEPT_UNVALIDATED"), string)
- assertTrue(string.contains("IS_VPN"), string)
- assertFalse(string.contains("IS_VALIDATED"), string)
- val foundNames = ArraySet<String>()
- getAllPolicies().forEach {
- val name = FullScore.policyNameOf(it.get() as Int)
- assertFalse(TextUtils.isEmpty(name))
- assertFalse(foundNames.contains(name))
- foundNames.add(name)
- }
- assertFailsWith<IllegalArgumentException> {
- FullScore.policyNameOf(MAX_CS_MANAGED_POLICY + 1)
- }
- }
-
- fun getAllPolicies() = Regex("POLICY_.*").let { nameRegex ->
- FullScore::class.staticProperties.filter { it.name.matches(nameRegex) }
- }
-
- @Test
- fun testHasPolicy() {
- val ns = FullScore(50, 0L /* policy */, KEEP_CONNECTED_NONE)
- assertFalse(ns.hasPolicy(POLICY_IS_VALIDATED))
- assertFalse(ns.hasPolicy(POLICY_IS_VPN))
- assertFalse(ns.hasPolicy(POLICY_EVER_USER_SELECTED))
- assertFalse(ns.hasPolicy(POLICY_ACCEPT_UNVALIDATED))
- assertTrue(ns.withPolicies(validated = true).hasPolicy(POLICY_IS_VALIDATED))
- assertTrue(ns.withPolicies(vpn = true).hasPolicy(POLICY_IS_VPN))
- assertTrue(ns.withPolicies(onceChosen = true).hasPolicy(POLICY_EVER_USER_SELECTED))
- assertTrue(ns.withPolicies(acceptUnvalidated = true).hasPolicy(POLICY_ACCEPT_UNVALIDATED))
- }
-
- @Test
- fun testMinMaxPolicyConstants() {
- val policies = getAllPolicies()
-
- policies.forEach { policy ->
- assertTrue(policy.get() as Int >= FullScore.MIN_CS_MANAGED_POLICY)
- assertTrue(policy.get() as Int <= FullScore.MAX_CS_MANAGED_POLICY)
- }
- assertEquals(FullScore.MIN_CS_MANAGED_POLICY,
- policies.minOfOrNull { it.get() as Int })
- assertEquals(FullScore.MAX_CS_MANAGED_POLICY,
- policies.maxOfOrNull { it.get() as Int })
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
deleted file mode 100644
index 70495cc..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
+++ /dev/null
@@ -1,561 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static com.android.server.connectivity.MetricsTestUtil.aLong;
-import static com.android.server.connectivity.MetricsTestUtil.aString;
-import static com.android.server.connectivity.MetricsTestUtil.aType;
-import static com.android.server.connectivity.MetricsTestUtil.anInt;
-import static com.android.server.connectivity.MetricsTestUtil.describeIpEvent;
-import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.BLUETOOTH;
-import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.CELLULAR;
-import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
-import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.MULTIPLE;
-import static com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.WIFI;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.net.ConnectivityMetricsEvent;
-import android.net.metrics.ApfProgramEvent;
-import android.net.metrics.ApfStats;
-import android.net.metrics.DefaultNetworkEvent;
-import android.net.metrics.DhcpClientEvent;
-import android.net.metrics.DhcpErrorEvent;
-import android.net.metrics.IpManagerEvent;
-import android.net.metrics.IpReachabilityEvent;
-import android.net.metrics.NetworkEvent;
-import android.net.metrics.RaEvent;
-import android.net.metrics.ValidationProbeEvent;
-import android.net.metrics.WakeupStats;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-import java.util.List;
-
-// TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpConnectivityEventBuilderTest {
-
- @Test
- public void testLinkLayerInferrence() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(IpReachabilityEvent.class),
- anInt(IpReachabilityEvent.NUD_FAILED));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "version: 2\n");
- verifySerialization(want, ev);
-
- ev.netId = 123;
- ev.transports = 3; // transports have priority for inferrence of link layer
- ev.ifname = "wlan0";
- want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- String.format(" link_layer: %d", MULTIPLE),
- " network_id: 123",
- " time_ms: 1",
- " transports: 3",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "version: 2\n");
- verifySerialization(want, ev);
-
- ev.transports = 1;
- ev.ifname = null;
- want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- String.format(" link_layer: %d", CELLULAR),
- " network_id: 123",
- " time_ms: 1",
- " transports: 1",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "version: 2\n");
- verifySerialization(want, ev);
-
- ev.transports = 0;
- ev.ifname = "not_inferred";
- want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"not_inferred\"",
- " link_layer: 0",
- " network_id: 123",
- " time_ms: 1",
- " transports: 0",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "version: 2\n");
- verifySerialization(want, ev);
-
- ev.ifname = "bt-pan";
- want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- String.format(" link_layer: %d", BLUETOOTH),
- " network_id: 123",
- " time_ms: 1",
- " transports: 0",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "version: 2\n");
- verifySerialization(want, ev);
-
- ev.ifname = "rmnet_ipa0";
- want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- String.format(" link_layer: %d", CELLULAR),
- " network_id: 123",
- " time_ms: 1",
- " transports: 0",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "version: 2\n");
- verifySerialization(want, ev);
-
- ev.ifname = "wlan0";
- want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- String.format(" link_layer: %d", WIFI),
- " network_id: 123",
- " time_ms: 1",
- " transports: 0",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "version: 2\n");
- verifySerialization(want, ev);
- }
-
- @Test
- public void testDefaultNetworkEventSerialization() {
- DefaultNetworkEvent ev = new DefaultNetworkEvent(1001);
- ev.netId = 102;
- ev.transports = 2;
- ev.previousTransports = 4;
- ev.ipv4 = true;
- ev.initialScore = 20;
- ev.finalScore = 60;
- ev.durationMs = 54;
- ev.validatedMs = 27;
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 102",
- " time_ms: 0",
- " transports: 2",
- " default_network_event <",
- " default_network_duration_ms: 54",
- " final_score: 60",
- " initial_score: 20",
- " ip_support: 1",
- " no_default_network_duration_ms: 0",
- " previous_default_network_link_layer: 1",
- " previous_network_ip_support: 0",
- " validation_duration_ms: 27",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, IpConnectivityEventBuilder.toProto(ev));
- }
-
- @Test
- public void testDhcpClientEventSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(DhcpClientEvent.class),
- aString("SomeState"),
- anInt(192));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " dhcp_event <",
- " duration_ms: 192",
- " if_name: \"\"",
- " state_transition: \"SomeState\"",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testDhcpErrorEventSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(DhcpErrorEvent.class),
- anInt(DhcpErrorEvent.L4_NOT_UDP));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " dhcp_event <",
- " duration_ms: 0",
- " if_name: \"\"",
- " error_code: 50397184",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testIpManagerEventSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(IpManagerEvent.class),
- anInt(IpManagerEvent.PROVISIONING_OK),
- aLong(5678));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " ip_provisioning_event <",
- " event_type: 1",
- " if_name: \"\"",
- " latency_ms: 5678",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testIpReachabilityEventSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(IpReachabilityEvent.class),
- anInt(IpReachabilityEvent.NUD_FAILED));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testNetworkEventSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(NetworkEvent.class),
- anInt(5),
- aLong(20410));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " network_event <",
- " event_type: 5",
- " latency_ms: 20410",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testValidationProbeEventSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(ValidationProbeEvent.class),
- aLong(40730),
- anInt(ValidationProbeEvent.PROBE_HTTP),
- anInt(204));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " validation_probe_event <",
- " latency_ms: 40730",
- " probe_result: 204",
- " probe_type: 1",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testApfProgramEventSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(ApfProgramEvent.class),
- aLong(200),
- aLong(18),
- anInt(7),
- anInt(9),
- anInt(2048),
- anInt(3));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " apf_program_event <",
- " current_ras: 9",
- " drop_multicast: true",
- " effective_lifetime: 18",
- " filtered_ras: 7",
- " has_ipv4_addr: true",
- " lifetime: 200",
- " program_length: 2048",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testApfStatsSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(ApfStats.class),
- aLong(45000),
- anInt(10),
- anInt(2),
- anInt(2),
- anInt(1),
- anInt(2),
- anInt(4),
- anInt(7),
- anInt(3),
- anInt(2048));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " apf_statistics <",
- " dropped_ras: 2",
- " duration_ms: 45000",
- " matching_ras: 2",
- " max_program_size: 2048",
- " parse_errors: 2",
- " program_updates: 4",
- " program_updates_all: 7",
- " program_updates_allowing_multicast: 3",
- " received_ras: 10",
- " total_packet_dropped: 0",
- " total_packet_processed: 0",
- " zero_lifetime_ras: 1",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testRaEventSerialization() {
- ConnectivityMetricsEvent ev = describeIpEvent(
- aType(RaEvent.class),
- aLong(2000),
- aLong(400),
- aLong(300),
- aLong(-1),
- aLong(1000),
- aLong(-1));
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 0",
- " time_ms: 1",
- " transports: 0",
- " ra_event <",
- " dnssl_lifetime: -1",
- " prefix_preferred_lifetime: 300",
- " prefix_valid_lifetime: 400",
- " rdnss_lifetime: 1000",
- " route_info_lifetime: -1",
- " router_lifetime: 2000",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, ev);
- }
-
- @Test
- public void testWakeupStatsSerialization() {
- WakeupStats stats = new WakeupStats("wlan0");
- stats.totalWakeups = 14;
- stats.applicationWakeups = 5;
- stats.nonApplicationWakeups = 1;
- stats.rootWakeups = 2;
- stats.systemWakeups = 3;
- stats.noUidWakeups = 3;
- stats.l2UnicastCount = 5;
- stats.l2MulticastCount = 1;
- stats.l2BroadcastCount = 2;
- stats.ethertypes.put(0x800, 3);
- stats.ethertypes.put(0x86dd, 3);
- stats.ipNextHeaders.put(6, 5);
-
-
- IpConnectivityEvent got = IpConnectivityEventBuilder.toProto(stats);
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 0",
- " transports: 0",
- " wakeup_stats <",
- " application_wakeups: 5",
- " duration_sec: 0",
- " ethertype_counts <",
- " key: 2048",
- " value: 3",
- " >",
- " ethertype_counts <",
- " key: 34525",
- " value: 3",
- " >",
- " ip_next_header_counts <",
- " key: 6",
- " value: 5",
- " >",
- " l2_broadcast_count: 2",
- " l2_multicast_count: 1",
- " l2_unicast_count: 5",
- " no_uid_wakeups: 3",
- " non_application_wakeups: 1",
- " root_wakeups: 2",
- " system_wakeups: 3",
- " total_wakeups: 14",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, got);
- }
-
- static void verifySerialization(String want, ConnectivityMetricsEvent... input) {
- List<IpConnectivityEvent> protoInput =
- IpConnectivityEventBuilder.toProto(Arrays.asList(input));
- verifySerialization(want, protoInput.toArray(new IpConnectivityEvent[0]));
- }
-
- static void verifySerialization(String want, IpConnectivityEvent... input) {
- try {
- byte[] got = IpConnectivityEventBuilder.serialize(0, Arrays.asList(input));
- IpConnectivityLog log = IpConnectivityLog.parseFrom(got);
- assertEquals(want, log.toString());
- } catch (Exception e) {
- fail(e.toString());
- }
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
deleted file mode 100644
index 8b072c4..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ /dev/null
@@ -1,645 +0,0 @@
-/*
- * Copyright (C) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO;
-import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityMetricsEvent;
-import android.net.IIpConnectivityMetrics;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.RouteInfo;
-import android.net.metrics.ApfProgramEvent;
-import android.net.metrics.ApfStats;
-import android.net.metrics.DhcpClientEvent;
-import android.net.metrics.IpConnectivityLog;
-import android.net.metrics.IpManagerEvent;
-import android.net.metrics.IpReachabilityEvent;
-import android.net.metrics.RaEvent;
-import android.net.metrics.ValidationProbeEvent;
-import android.os.Parcelable;
-import android.system.OsConstants;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Base64;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.BitUtils;
-import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class IpConnectivityMetricsTest {
- static final IpReachabilityEvent FAKE_EV =
- new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED);
-
- private static final String EXAMPLE_IPV4 = "192.0.2.1";
- private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1";
-
- private static final byte[] MAC_ADDR =
- {(byte)0x84, (byte)0xc9, (byte)0xb2, (byte)0x6a, (byte)0xed, (byte)0x4b};
-
- @Mock Context mCtx;
- @Mock IIpConnectivityMetrics mMockService;
- @Mock ConnectivityManager mCm;
-
- IpConnectivityMetrics mService;
- NetdEventListenerService mNetdListener;
- private static final NetworkCapabilities CAPABILITIES_WIFI = new NetworkCapabilities.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .build();
- private static final NetworkCapabilities CAPABILITIES_CELL = new NetworkCapabilities.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .build();
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mService = new IpConnectivityMetrics(mCtx, (ctx) -> 2000);
- mNetdListener = new NetdEventListenerService(mCm);
- mService.mNetdListener = mNetdListener;
- }
-
- @Test
- public void testBufferFlushing() {
- String output1 = getdump("flush");
- assertEquals("", output1);
-
- new IpConnectivityLog(mService.impl).log(1, FAKE_EV);
- String output2 = getdump("flush");
- assertFalse("".equals(output2));
-
- String output3 = getdump("flush");
- assertEquals("", output3);
- }
-
- @Test
- public void testRateLimiting() {
- final IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
- final ApfProgramEvent ev = new ApfProgramEvent.Builder().build();
- final long fakeTimestamp = 1;
-
- int attempt = 100; // More than burst quota, but less than buffer size.
- for (int i = 0; i < attempt; i++) {
- logger.log(ev);
- }
-
- String output1 = getdump("flush");
- assertFalse("".equals(output1));
-
- for (int i = 0; i < attempt; i++) {
- assertFalse("expected event to be dropped", logger.log(fakeTimestamp, ev));
- }
-
- String output2 = getdump("flush");
- assertEquals("", output2);
- }
-
- private void logDefaultNetworkEvent(long timeMs, NetworkAgentInfo nai,
- NetworkAgentInfo oldNai) {
- final Network network = (nai != null) ? nai.network() : null;
- final int score = (nai != null) ? nai.getCurrentScore() : 0;
- final boolean validated = (nai != null) ? nai.lastValidated : false;
- final LinkProperties lp = (nai != null) ? nai.linkProperties : null;
- final NetworkCapabilities nc = (nai != null) ? nai.networkCapabilities : null;
-
- final Network prevNetwork = (oldNai != null) ? oldNai.network() : null;
- final int prevScore = (oldNai != null) ? oldNai.getCurrentScore() : 0;
- final LinkProperties prevLp = (oldNai != null) ? oldNai.linkProperties : null;
- final NetworkCapabilities prevNc = (oldNai != null) ? oldNai.networkCapabilities : null;
-
- mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs, network, score, validated,
- lp, nc, prevNetwork, prevScore, prevLp, prevNc);
- }
- @Test
- public void testDefaultNetworkEvents() throws Exception {
- final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
- final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
-
- NetworkAgentInfo[][] defaultNetworks = {
- // nothing -> cell
- {null, makeNai(100, 10, false, true, cell)},
- // cell -> wifi
- {makeNai(100, 50, true, true, cell), makeNai(101, 20, true, false, wifi)},
- // wifi -> nothing
- {makeNai(101, 60, true, false, wifi), null},
- // nothing -> cell
- {null, makeNai(102, 10, true, true, cell)},
- // cell -> wifi
- {makeNai(102, 50, true, true, cell), makeNai(103, 20, true, false, wifi)},
- };
-
- long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
- long durationMs = 1001;
- for (NetworkAgentInfo[] pair : defaultNetworks) {
- timeMs += durationMs;
- durationMs += durationMs;
- logDefaultNetworkEvent(timeMs, pair[1], pair[0]);
- }
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 5",
- " network_id: 0",
- " time_ms: 0",
- " transports: 0",
- " default_network_event <",
- " default_network_duration_ms: 1001",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " no_default_network_duration_ms: 0",
- " previous_default_network_link_layer: 0",
- " previous_network_ip_support: 0",
- " validation_duration_ms: 0",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 2",
- " network_id: 100",
- " time_ms: 0",
- " transports: 1",
- " default_network_event <",
- " default_network_duration_ms: 2002",
- " final_score: 50",
- " initial_score: 10",
- " ip_support: 3",
- " no_default_network_duration_ms: 0",
- " previous_default_network_link_layer: 0",
- " previous_network_ip_support: 0",
- " validation_duration_ms: 2002",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 101",
- " time_ms: 0",
- " transports: 2",
- " default_network_event <",
- " default_network_duration_ms: 4004",
- " final_score: 60",
- " initial_score: 20",
- " ip_support: 1",
- " no_default_network_duration_ms: 0",
- " previous_default_network_link_layer: 2",
- " previous_network_ip_support: 0",
- " validation_duration_ms: 4004",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 5",
- " network_id: 0",
- " time_ms: 0",
- " transports: 0",
- " default_network_event <",
- " default_network_duration_ms: 8008",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " no_default_network_duration_ms: 0",
- " previous_default_network_link_layer: 4",
- " previous_network_ip_support: 0",
- " validation_duration_ms: 0",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 2",
- " network_id: 102",
- " time_ms: 0",
- " transports: 1",
- " default_network_event <",
- " default_network_duration_ms: 16016",
- " final_score: 50",
- " initial_score: 10",
- " ip_support: 3",
- " no_default_network_duration_ms: 0",
- " previous_default_network_link_layer: 4",
- " previous_network_ip_support: 0",
- " validation_duration_ms: 16016",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, getdump("flush"));
- }
-
- @Test
- public void testEndToEndLogging() throws Exception {
- // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
- IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
-
- ApfStats apfStats = new ApfStats.Builder()
- .setDurationMs(45000)
- .setReceivedRas(10)
- .setMatchingRas(2)
- .setDroppedRas(2)
- .setParseErrors(2)
- .setZeroLifetimeRas(1)
- .setProgramUpdates(4)
- .setProgramUpdatesAll(7)
- .setProgramUpdatesAllowingMulticast(3)
- .setMaxProgramSize(2048)
- .build();
-
- final ValidationProbeEvent validationEv = new ValidationProbeEvent.Builder()
- .setDurationMs(40730)
- .setProbeType(ValidationProbeEvent.PROBE_HTTP, true)
- .setReturnCode(204)
- .build();
-
- final DhcpClientEvent event = new DhcpClientEvent.Builder()
- .setMsg("SomeState")
- .setDurationMs(192)
- .build();
- Parcelable[] events = {
- new IpReachabilityEvent(IpReachabilityEvent.NUD_FAILED), event,
- new IpManagerEvent(IpManagerEvent.PROVISIONING_OK, 5678),
- validationEv,
- apfStats,
- new RaEvent(2000, 400, 300, -1, 1000, -1)
- };
-
- for (int i = 0; i < events.length; i++) {
- ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
- ev.timestamp = 100 * (i + 1);
- ev.ifname = "wlan0";
- ev.data = events[i];
- logger.log(ev);
- }
-
- // netId, errno, latency, destination
- connectEvent(100, OsConstants.EALREADY, 0, EXAMPLE_IPV4);
- connectEvent(100, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6);
- connectEvent(100, 0, 110, EXAMPLE_IPV4);
- connectEvent(101, 0, 23, EXAMPLE_IPV4);
- connectEvent(101, 0, 45, EXAMPLE_IPV6);
- connectEvent(100, OsConstants.EAGAIN, 0, EXAMPLE_IPV4);
-
- // netId, type, return code, latency
- dnsEvent(100, EVENT_GETADDRINFO, 0, 3456);
- dnsEvent(100, EVENT_GETADDRINFO, 3, 45);
- dnsEvent(100, EVENT_GETHOSTBYNAME, 0, 638);
- dnsEvent(101, EVENT_GETADDRINFO, 0, 56);
- dnsEvent(101, EVENT_GETHOSTBYNAME, 0, 34);
-
- // iface, uid
- final byte[] mac = {0x48, 0x7c, 0x2b, 0x6a, 0x3e, 0x4b};
- final String srcIp = "192.168.2.1";
- final String dstIp = "192.168.2.23";
- final int sport = 2356;
- final int dport = 13489;
- final long now = 1001L;
- final int v4 = 0x800;
- final int tcp = 6;
- final int udp = 17;
- wakeupEvent("wlan0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
- wakeupEvent("wlan0", 10123, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
- wakeupEvent("wlan0", 1000, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
- wakeupEvent("wlan0", 10008, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
- wakeupEvent("wlan0", -1, v4, udp, mac, srcIp, dstIp, sport, dport, 1001L);
- wakeupEvent("wlan0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, 1001L);
-
- long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
- final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
- final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
- NetworkAgentInfo cellNai = makeNai(100, 50, false, true, cell);
- NetworkAgentInfo wifiNai = makeNai(101, 60, true, false, wifi);
- logDefaultNetworkEvent(timeMs + 200L, cellNai, null);
- logDefaultNetworkEvent(timeMs + 300L, wifiNai, cellNai);
-
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 100",
- " transports: 0",
- " ip_reachability_event <",
- " event_type: 512",
- " if_name: \"\"",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 200",
- " transports: 0",
- " dhcp_event <",
- " duration_ms: 192",
- " if_name: \"\"",
- " state_transition: \"SomeState\"",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 300",
- " transports: 0",
- " ip_provisioning_event <",
- " event_type: 1",
- " if_name: \"\"",
- " latency_ms: 5678",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 400",
- " transports: 0",
- " validation_probe_event <",
- " latency_ms: 40730",
- " probe_result: 204",
- " probe_type: 257",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 500",
- " transports: 0",
- " apf_statistics <",
- " dropped_ras: 2",
- " duration_ms: 45000",
- " matching_ras: 2",
- " max_program_size: 2048",
- " parse_errors: 2",
- " program_updates: 4",
- " program_updates_all: 7",
- " program_updates_allowing_multicast: 3",
- " received_ras: 10",
- " total_packet_dropped: 0",
- " total_packet_processed: 0",
- " zero_lifetime_ras: 1",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 600",
- " transports: 0",
- " ra_event <",
- " dnssl_lifetime: -1",
- " prefix_preferred_lifetime: 300",
- " prefix_valid_lifetime: 400",
- " rdnss_lifetime: 1000",
- " route_info_lifetime: -1",
- " router_lifetime: 2000",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 5",
- " network_id: 0",
- " time_ms: 0",
- " transports: 0",
- " default_network_event <",
- " default_network_duration_ms: 200",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " no_default_network_duration_ms: 0",
- " previous_default_network_link_layer: 0",
- " previous_network_ip_support: 0",
- " validation_duration_ms: 0",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 2",
- " network_id: 100",
- " time_ms: 0",
- " transports: 1",
- " default_network_event <",
- " default_network_duration_ms: 100",
- " final_score: 50",
- " initial_score: 50",
- " ip_support: 2",
- " no_default_network_duration_ms: 0",
- " previous_default_network_link_layer: 0",
- " previous_network_ip_support: 0",
- " validation_duration_ms: 100",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 100",
- " time_ms: 0",
- " transports: 2",
- " connect_statistics <",
- " connect_blocking_count: 1",
- " connect_count: 3",
- " errnos_counters <",
- " key: 11",
- " value: 1",
- " >",
- " ipv6_addr_count: 1",
- " latencies_ms: 110",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 2",
- " network_id: 101",
- " time_ms: 0",
- " transports: 1",
- " connect_statistics <",
- " connect_blocking_count: 2",
- " connect_count: 2",
- " ipv6_addr_count: 1",
- " latencies_ms: 23",
- " latencies_ms: 45",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 100",
- " time_ms: 0",
- " transports: 2",
- " dns_lookup_batch <",
- " event_types: 1",
- " event_types: 1",
- " event_types: 2",
- " getaddrinfo_error_count: 0",
- " getaddrinfo_query_count: 0",
- " gethostbyname_error_count: 0",
- " gethostbyname_query_count: 0",
- " latencies_ms: 3456",
- " latencies_ms: 45",
- " latencies_ms: 638",
- " return_codes: 0",
- " return_codes: 3",
- " return_codes: 0",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 2",
- " network_id: 101",
- " time_ms: 0",
- " transports: 1",
- " dns_lookup_batch <",
- " event_types: 1",
- " event_types: 2",
- " getaddrinfo_error_count: 0",
- " getaddrinfo_query_count: 0",
- " gethostbyname_error_count: 0",
- " gethostbyname_query_count: 0",
- " latencies_ms: 56",
- " latencies_ms: 34",
- " return_codes: 0",
- " return_codes: 0",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 0",
- " transports: 0",
- " wakeup_stats <",
- " application_wakeups: 3",
- " duration_sec: 0",
- " ethertype_counts <",
- " key: 2048",
- " value: 6",
- " >",
- " ip_next_header_counts <",
- " key: 6",
- " value: 3",
- " >",
- " ip_next_header_counts <",
- " key: 17",
- " value: 3",
- " >",
- " l2_broadcast_count: 0",
- " l2_multicast_count: 0",
- " l2_unicast_count: 6",
- " no_uid_wakeups: 1",
- " non_application_wakeups: 0",
- " root_wakeups: 0",
- " system_wakeups: 2",
- " total_wakeups: 6",
- " >",
- ">",
- "version: 2\n");
-
- verifySerialization(want, getdump("flush"));
- }
-
- String getdump(String ... command) {
- StringWriter buffer = new StringWriter();
- PrintWriter writer = new PrintWriter(buffer);
- mService.impl.dump(null, writer, command);
- return buffer.toString();
- }
-
- private void setCapabilities(int netId) {
- final ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallback =
- ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
- verify(mCm).registerNetworkCallback(any(), networkCallback.capture());
- networkCallback.getValue().onCapabilitiesChanged(new Network(netId),
- netId == 100 ? CAPABILITIES_WIFI : CAPABILITIES_CELL);
- }
-
- void connectEvent(int netId, int error, int latencyMs, String ipAddr) throws Exception {
- setCapabilities(netId);
- mNetdListener.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
- }
-
- void dnsEvent(int netId, int type, int result, int latency) throws Exception {
- setCapabilities(netId);
- mNetdListener.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
- }
-
- void wakeupEvent(String iface, int uid, int ether, int ip, byte[] mac, String srcIp,
- String dstIp, int sport, int dport, long now) throws Exception {
- String prefix = NetdEventListenerService.WAKEUP_EVENT_IFACE_PREFIX + iface;
- mNetdListener.onWakeupEvent(prefix, uid, ether, ip, mac, srcIp, dstIp, sport, dport, now);
- }
-
- NetworkAgentInfo makeNai(int netId, int score, boolean ipv4, boolean ipv6, long transports) {
- NetworkAgentInfo nai = mock(NetworkAgentInfo.class);
- when(nai.network()).thenReturn(new Network(netId));
- when(nai.getCurrentScore()).thenReturn(score);
- nai.linkProperties = new LinkProperties();
- nai.networkCapabilities = new NetworkCapabilities();
- nai.lastValidated = true;
- for (int t : BitUtils.unpackBits(transports)) {
- nai.networkCapabilities.addTransportType(t);
- }
- if (ipv4) {
- nai.linkProperties.addLinkAddress(new LinkAddress("192.0.2.12/24"));
- nai.linkProperties.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0")));
- }
- if (ipv6) {
- nai.linkProperties.addLinkAddress(new LinkAddress("2001:db8:dead:beef:f00::a0/64"));
- nai.linkProperties.addRoute(new RouteInfo(new IpPrefix("::/0")));
- }
- return nai;
- }
-
-
-
- static void verifySerialization(String want, String output) {
- try {
- byte[] got = Base64.decode(output, Base64.DEFAULT);
- IpConnectivityLogClass.IpConnectivityLog log =
- IpConnectivityLogClass.IpConnectivityLog.parseFrom(got);
- assertEquals(want, log.toString());
- } catch (Exception e) {
- fail(e.toString());
- }
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/LingerMonitorTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/LingerMonitorTest.java
deleted file mode 100644
index 36e229d..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/LingerMonitorTest.java
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * Copyright (C) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityResources;
-import android.net.IDnsResolver;
-import android.net.INetd;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkAgentConfig;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkProvider;
-import android.net.NetworkScore;
-import android.os.Binder;
-import android.text.format.DateUtils;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.connectivity.resources.R;
-import com.android.server.ConnectivityService;
-import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class LingerMonitorTest {
- static final String CELLULAR = "CELLULAR";
- static final String WIFI = "WIFI";
-
- static final long LOW_RATE_LIMIT = DateUtils.MINUTE_IN_MILLIS;
- static final long HIGH_RATE_LIMIT = 0;
-
- static final int LOW_DAILY_LIMIT = 2;
- static final int HIGH_DAILY_LIMIT = 1000;
-
- private static final int TEST_LINGER_DELAY_MS = 400;
-
- LingerMonitor mMonitor;
-
- @Mock ConnectivityService mConnService;
- @Mock IDnsResolver mDnsResolver;
- @Mock INetd mNetd;
- @Mock Context mCtx;
- @Mock NetworkNotificationManager mNotifier;
- @Mock Resources mResources;
- @Mock QosCallbackTracker mQosCallbackTracker;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mCtx.getResources()).thenReturn(mResources);
- when(mCtx.getPackageName()).thenReturn("com.android.server.connectivity");
- ConnectivityResources.setResourcesContextForTest(mCtx);
-
- mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, HIGH_RATE_LIMIT);
- }
-
- @After
- public void tearDown() {
- ConnectivityResources.setResourcesContextForTest(null);
- }
-
- @Test
- public void testTransitions() {
- setNotificationSwitch(transition(WIFI, CELLULAR));
- NetworkAgentInfo nai1 = wifiNai(100);
- NetworkAgentInfo nai2 = cellNai(101);
-
- assertTrue(mMonitor.isNotificationEnabled(nai1, nai2));
- assertFalse(mMonitor.isNotificationEnabled(nai2, nai1));
- }
-
- @Test
- public void testNotificationOnLinger() {
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNotification(from, to);
- }
-
- @Test
- public void testToastOnLinger() {
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyToast(from, to);
- }
-
- @Test
- public void testNotificationClearedAfterDisconnect() {
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNotification(from, to);
-
- mMonitor.noteDisconnect(to);
- verify(mNotifier, times(1)).clearNotification(100);
- }
-
- @Test
- public void testNotificationClearedAfterSwitchingBack() {
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNotification(from, to);
-
- mMonitor.noteLingerDefaultNetwork(to, from);
- verify(mNotifier, times(1)).clearNotification(100);
- }
-
- @Test
- public void testUniqueToast() {
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyToast(from, to);
-
- mMonitor.noteLingerDefaultNetwork(to, from);
- verify(mNotifier, times(1)).clearNotification(100);
-
- reset(mNotifier);
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNoNotifications();
- }
-
- @Test
- public void testMultipleNotifications() {
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
- NetworkAgentInfo wifi1 = wifiNai(100);
- NetworkAgentInfo wifi2 = wifiNai(101);
- NetworkAgentInfo cell = cellNai(102);
-
- mMonitor.noteLingerDefaultNetwork(wifi1, cell);
- verifyNotification(wifi1, cell);
-
- mMonitor.noteLingerDefaultNetwork(cell, wifi2);
- verify(mNotifier, times(1)).clearNotification(100);
-
- reset(mNotifier);
- mMonitor.noteLingerDefaultNetwork(wifi2, cell);
- verifyNotification(wifi2, cell);
- }
-
- @Test
- public void testRateLimiting() throws InterruptedException {
- mMonitor = new TestableLingerMonitor(mCtx, mNotifier, HIGH_DAILY_LIMIT, LOW_RATE_LIMIT);
-
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
- NetworkAgentInfo wifi1 = wifiNai(100);
- NetworkAgentInfo wifi2 = wifiNai(101);
- NetworkAgentInfo wifi3 = wifiNai(102);
- NetworkAgentInfo cell = cellNai(103);
-
- mMonitor.noteLingerDefaultNetwork(wifi1, cell);
- verifyNotification(wifi1, cell);
- reset(mNotifier);
-
- Thread.sleep(50);
- mMonitor.noteLingerDefaultNetwork(cell, wifi2);
- mMonitor.noteLingerDefaultNetwork(wifi2, cell);
- verifyNoNotifications();
-
- Thread.sleep(50);
- mMonitor.noteLingerDefaultNetwork(cell, wifi3);
- mMonitor.noteLingerDefaultNetwork(wifi3, cell);
- verifyNoNotifications();
- }
-
- @Test
- public void testDailyLimiting() throws InterruptedException {
- mMonitor = new TestableLingerMonitor(mCtx, mNotifier, LOW_DAILY_LIMIT, HIGH_RATE_LIMIT);
-
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
- NetworkAgentInfo wifi1 = wifiNai(100);
- NetworkAgentInfo wifi2 = wifiNai(101);
- NetworkAgentInfo wifi3 = wifiNai(102);
- NetworkAgentInfo cell = cellNai(103);
-
- mMonitor.noteLingerDefaultNetwork(wifi1, cell);
- verifyNotification(wifi1, cell);
- reset(mNotifier);
-
- Thread.sleep(50);
- mMonitor.noteLingerDefaultNetwork(cell, wifi2);
- mMonitor.noteLingerDefaultNetwork(wifi2, cell);
- verifyNotification(wifi2, cell);
- reset(mNotifier);
-
- Thread.sleep(50);
- mMonitor.noteLingerDefaultNetwork(cell, wifi3);
- mMonitor.noteLingerDefaultNetwork(wifi3, cell);
- verifyNoNotifications();
- }
-
- @Test
- public void testUniqueNotification() {
- setNotificationSwitch(transition(WIFI, CELLULAR));
- setNotificationType(LingerMonitor.NOTIFY_TYPE_NOTIFICATION);
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNotification(from, to);
-
- mMonitor.noteLingerDefaultNetwork(to, from);
- verify(mNotifier, times(1)).clearNotification(100);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNotification(from, to);
- }
-
- @Test
- public void testIgnoreNeverValidatedNetworks() {
- setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
- setNotificationSwitch(transition(WIFI, CELLULAR));
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
- from.everValidated = false;
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNoNotifications();
- }
-
- @Test
- public void testIgnoreCurrentlyValidatedNetworks() {
- setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
- setNotificationSwitch(transition(WIFI, CELLULAR));
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
- from.lastValidated = true;
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNoNotifications();
- }
-
- @Test
- public void testNoNotificationType() {
- setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
- setNotificationSwitch();
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNoNotifications();
- }
-
- @Test
- public void testNoTransitionToNotify() {
- setNotificationType(LingerMonitor.NOTIFY_TYPE_NONE);
- setNotificationSwitch(transition(WIFI, CELLULAR));
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNoNotifications();
- }
-
- @Test
- public void testDifferentTransitionToNotify() {
- setNotificationType(LingerMonitor.NOTIFY_TYPE_TOAST);
- setNotificationSwitch(transition(CELLULAR, WIFI));
- NetworkAgentInfo from = wifiNai(100);
- NetworkAgentInfo to = cellNai(101);
-
- mMonitor.noteLingerDefaultNetwork(from, to);
- verifyNoNotifications();
- }
-
- void setNotificationSwitch(String... transitions) {
- when(mResources.getStringArray(R.array.config_networkNotifySwitches))
- .thenReturn(transitions);
- }
-
- String transition(String from, String to) {
- return from + "-" + to;
- }
-
- void setNotificationType(int type) {
- when(mResources.getInteger(R.integer.config_networkNotifySwitchType)).thenReturn(type);
- }
-
- void verifyNoToast() {
- verify(mNotifier, never()).showToast(any(), any());
- }
-
- void verifyNoNotification() {
- verify(mNotifier, never())
- .showNotification(anyInt(), any(), any(), any(), any(), anyBoolean());
- }
-
- void verifyNoNotifications() {
- verifyNoToast();
- verifyNoNotification();
- }
-
- void verifyToast(NetworkAgentInfo from, NetworkAgentInfo to) {
- verifyNoNotification();
- verify(mNotifier, times(1)).showToast(from, to);
- }
-
- void verifyNotification(NetworkAgentInfo from, NetworkAgentInfo to) {
- verifyNoToast();
- verify(mNotifier, times(1)).showNotification(eq(from.network.netId),
- eq(NotificationType.NETWORK_SWITCH), eq(from), eq(to), any(), eq(true));
- }
-
- NetworkAgentInfo nai(int netId, int transport, int networkType, String networkTypeName) {
- NetworkInfo info = new NetworkInfo(networkType, 0, networkTypeName, "");
- NetworkCapabilities caps = new NetworkCapabilities();
- caps.addCapability(0);
- caps.addTransportType(transport);
- NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info,
- new LinkProperties(), caps, new NetworkScore.Builder().setLegacyInt(50).build(),
- mCtx, null, new NetworkAgentConfig.Builder().build(), mConnService, mNetd,
- mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(), TEST_LINGER_DELAY_MS,
- mQosCallbackTracker, new ConnectivityService.Dependencies());
- nai.everValidated = true;
- return nai;
- }
-
- NetworkAgentInfo wifiNai(int netId) {
- return nai(netId, NetworkCapabilities.TRANSPORT_WIFI,
- ConnectivityManager.TYPE_WIFI, WIFI);
- }
-
- NetworkAgentInfo cellNai(int netId) {
- return nai(netId, NetworkCapabilities.TRANSPORT_CELLULAR,
- ConnectivityManager.TYPE_MOBILE, CELLULAR);
- }
-
- public static class TestableLingerMonitor extends LingerMonitor {
- public TestableLingerMonitor(Context c, NetworkNotificationManager n, int l, long r) {
- super(c, n, l, r);
- }
- @Override protected PendingIntent createNotificationIntent() {
- return null;
- }
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/MetricsTestUtil.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/MetricsTestUtil.java
deleted file mode 100644
index 5064b9b..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/MetricsTestUtil.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import android.net.ConnectivityMetricsEvent;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.function.Consumer;
-
-abstract public class MetricsTestUtil {
- private MetricsTestUtil() {
- }
-
- static ConnectivityMetricsEvent ev(Parcelable p) {
- ConnectivityMetricsEvent ev = new ConnectivityMetricsEvent();
- ev.timestamp = 1L;
- ev.data = p;
- return ev;
- }
-
- static ConnectivityMetricsEvent describeIpEvent(Consumer<Parcel>... fs) {
- Parcel p = Parcel.obtain();
- for (Consumer<Parcel> f : fs) {
- f.accept(p);
- }
- p.setDataPosition(0);
- return ev(p.readParcelable(ClassLoader.getSystemClassLoader()));
- }
-
- static Consumer<Parcel> aType(Class<?> c) {
- return aString(c.getName());
- }
-
- static Consumer<Parcel> aBool(boolean b) {
- return aByte((byte) (b ? 1 : 0));
- }
-
- static Consumer<Parcel> aByte(byte b) {
- return (p) -> p.writeByte(b);
- }
-
- static Consumer<Parcel> anInt(int i) {
- return (p) -> p.writeInt(i);
- }
-
- static Consumer<Parcel> aLong(long l) {
- return (p) -> p.writeLong(l);
- }
-
- static Consumer<Parcel> aString(String s) {
- return (p) -> p.writeString(s);
- }
-
- static Consumer<Parcel> aByteArray(byte... ary) {
- return (p) -> p.writeByteArray(ary);
- }
-
- static Consumer<Parcel> anIntArray(int... ary) {
- return (p) -> p.writeIntArray(ary);
- }
-
- static byte b(int i) {
- return (byte) i;
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
deleted file mode 100644
index 38f6d7f..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.content.Intent.ACTION_CONFIGURATION_CHANGED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkPolicy.LIMIT_DISABLED;
-import static android.net.NetworkPolicy.SNOOZE_NEVER;
-import static android.net.NetworkPolicy.WARNING_DISABLED;
-import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES;
-
-import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_MULTIPATH;
-import static com.android.server.net.NetworkPolicyManagerService.OPPORTUNISTIC_QUOTA_UNKNOWN;
-
-import static junit.framework.TestCase.assertNotNull;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.usage.NetworkStatsManager;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.EthernetNetworkSpecifier;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkPolicy;
-import android.net.NetworkPolicyManager;
-import android.net.NetworkTemplate;
-import android.net.TelephonyNetworkSpecifier;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.telephony.TelephonyManager;
-import android.test.mock.MockContentResolver;
-import android.util.DataUnit;
-import android.util.RecurrenceRule;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.R;
-import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.LocalServices;
-import com.android.server.net.NetworkPolicyManagerInternal;
-import com.android.server.net.NetworkStatsManagerInternal;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.time.Clock;
-import java.time.Instant;
-import java.time.Period;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.time.temporal.ChronoUnit;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class MultipathPolicyTrackerTest {
- private static final Network TEST_NETWORK = new Network(123);
- private static final int POLICY_SNOOZED = -100;
-
- @Mock private Context mContext;
- @Mock private Context mUserAllContext;
- @Mock private Resources mResources;
- @Mock private Handler mHandler;
- @Mock private MultipathPolicyTracker.Dependencies mDeps;
- @Mock private Clock mClock;
- @Mock private ConnectivityManager mCM;
- @Mock private NetworkPolicyManager mNPM;
- @Mock private NetworkStatsManager mStatsManager;
- @Mock private NetworkPolicyManagerInternal mNPMI;
- @Mock private NetworkStatsManagerInternal mNetworkStatsManagerInternal;
- @Mock private TelephonyManager mTelephonyManager;
- private MockContentResolver mContentResolver;
-
- private ArgumentCaptor<BroadcastReceiver> mConfigChangeReceiverCaptor;
-
- private MultipathPolicyTracker mTracker;
-
- private Clock mPreviousRecurrenceRuleClock;
- private boolean mRecurrenceRuleClockMocked;
-
- private <T> void mockService(String serviceName, Class<T> serviceClass, T service) {
- when(mContext.getSystemServiceName(serviceClass)).thenReturn(serviceName);
- when(mContext.getSystemService(serviceName)).thenReturn(service);
- }
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- mPreviousRecurrenceRuleClock = RecurrenceRule.sClock;
- RecurrenceRule.sClock = mClock;
- mRecurrenceRuleClockMocked = true;
-
- mConfigChangeReceiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class);
-
- when(mContext.getResources()).thenReturn(mResources);
- when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
- // Mock user id to all users that Context#registerReceiver will register with all users too.
- doReturn(UserHandle.ALL.getIdentifier()).when(mUserAllContext).getUserId();
- when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt()))
- .thenReturn(mUserAllContext);
- when(mUserAllContext.registerReceiver(mConfigChangeReceiverCaptor.capture(),
- argThat(f -> f.hasAction(ACTION_CONFIGURATION_CHANGED)), any(), any()))
- .thenReturn(null);
-
- when(mDeps.getClock()).thenReturn(mClock);
-
- when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
-
- mContentResolver = Mockito.spy(new MockContentResolver(mContext));
- mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
- Settings.Global.clearProviderForTest();
- when(mContext.getContentResolver()).thenReturn(mContentResolver);
-
- mockService(Context.CONNECTIVITY_SERVICE, ConnectivityManager.class, mCM);
- mockService(Context.NETWORK_POLICY_SERVICE, NetworkPolicyManager.class, mNPM);
- mockService(Context.NETWORK_STATS_SERVICE, NetworkStatsManager.class, mStatsManager);
- mockService(Context.TELEPHONY_SERVICE, TelephonyManager.class, mTelephonyManager);
-
- LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
- LocalServices.addService(NetworkPolicyManagerInternal.class, mNPMI);
-
- LocalServices.removeServiceForTest(NetworkStatsManagerInternal.class);
- LocalServices.addService(NetworkStatsManagerInternal.class, mNetworkStatsManagerInternal);
-
- mTracker = new MultipathPolicyTracker(mContext, mHandler, mDeps);
- }
-
- @After
- public void tearDown() {
- // Avoid setting static clock to null (which should normally not be the case)
- // if MockitoAnnotations.initMocks threw an exception
- if (mRecurrenceRuleClockMocked) {
- RecurrenceRule.sClock = mPreviousRecurrenceRuleClock;
- }
- mRecurrenceRuleClockMocked = false;
- }
-
- private void setDefaultQuotaGlobalSetting(long setting) {
- Settings.Global.putInt(mContentResolver, NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES,
- (int) setting);
- }
-
- private void testGetMultipathPreference(
- long usedBytesToday, long subscriptionQuota, long policyWarning, long policyLimit,
- long defaultGlobalSetting, long defaultResSetting, boolean roaming) {
-
- // TODO: tests should not use ZoneId.systemDefault() once code handles TZ correctly.
- final ZonedDateTime now = ZonedDateTime.ofInstant(
- Instant.parse("2017-04-02T10:11:12Z"), ZoneId.systemDefault());
- final ZonedDateTime startOfDay = now.truncatedTo(ChronoUnit.DAYS);
- when(mClock.millis()).thenReturn(now.toInstant().toEpochMilli());
- when(mClock.instant()).thenReturn(now.toInstant());
- when(mClock.getZone()).thenReturn(ZoneId.systemDefault());
-
- // Setup plan quota
- when(mNPMI.getSubscriptionOpportunisticQuota(TEST_NETWORK, QUOTA_TYPE_MULTIPATH))
- .thenReturn(subscriptionQuota);
-
- // Setup user policy warning / limit
- if (policyWarning != WARNING_DISABLED || policyLimit != LIMIT_DISABLED) {
- final Instant recurrenceStart = Instant.parse("2017-04-01T00:00:00Z");
- final RecurrenceRule recurrenceRule = new RecurrenceRule(
- ZonedDateTime.ofInstant(
- recurrenceStart,
- ZoneId.systemDefault()),
- null /* end */,
- Period.ofMonths(1));
- final boolean snoozeWarning = policyWarning == POLICY_SNOOZED;
- final boolean snoozeLimit = policyLimit == POLICY_SNOOZED;
- when(mNPM.getNetworkPolicies()).thenReturn(new NetworkPolicy[] {
- new NetworkPolicy(
- NetworkTemplate.buildTemplateMobileWildcard(),
- recurrenceRule,
- snoozeWarning ? 0 : policyWarning,
- snoozeLimit ? 0 : policyLimit,
- snoozeWarning ? recurrenceStart.toEpochMilli() + 1 : SNOOZE_NEVER,
- snoozeLimit ? recurrenceStart.toEpochMilli() + 1 : SNOOZE_NEVER,
- SNOOZE_NEVER,
- true /* metered */,
- false /* inferred */)
- });
- } else {
- when(mNPM.getNetworkPolicies()).thenReturn(new NetworkPolicy[0]);
- }
-
- // Setup default quota in settings and resources
- if (defaultGlobalSetting > 0) {
- setDefaultQuotaGlobalSetting(defaultGlobalSetting);
- }
- when(mResources.getInteger(R.integer.config_networkDefaultDailyMultipathQuotaBytes))
- .thenReturn((int) defaultResSetting);
-
- when(mNetworkStatsManagerInternal.getNetworkTotalBytes(
- any(),
- eq(startOfDay.toInstant().toEpochMilli()),
- eq(now.toInstant().toEpochMilli()))).thenReturn(usedBytesToday);
-
- ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallback =
- ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
- mTracker.start();
- verify(mCM).registerNetworkCallback(any(), networkCallback.capture(), any());
-
- // Simulate callback after capability changes
- NetworkCapabilities capabilities = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addTransportType(TRANSPORT_CELLULAR)
- .setNetworkSpecifier(new EthernetNetworkSpecifier("eth234"));
- if (!roaming) {
- capabilities.addCapability(NET_CAPABILITY_NOT_ROAMING);
- }
- networkCallback.getValue().onCapabilitiesChanged(
- TEST_NETWORK,
- capabilities);
-
- // make sure it also works with the new introduced TelephonyNetworkSpecifier
- capabilities = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addTransportType(TRANSPORT_CELLULAR)
- .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
- .setSubscriptionId(234).build());
- if (!roaming) {
- capabilities.addCapability(NET_CAPABILITY_NOT_ROAMING);
- }
- networkCallback.getValue().onCapabilitiesChanged(
- TEST_NETWORK,
- capabilities);
- }
-
- @Test
- public void testGetMultipathPreference_SubscriptionQuota() {
- testGetMultipathPreference(
- DataUnit.MEGABYTES.toBytes(2) /* usedBytesToday */,
- DataUnit.MEGABYTES.toBytes(14) /* subscriptionQuota */,
- DataUnit.MEGABYTES.toBytes(100) /* policyWarning */,
- LIMIT_DISABLED,
- DataUnit.MEGABYTES.toBytes(12) /* defaultGlobalSetting */,
- 2_500_000 /* defaultResSetting */,
- false /* roaming */);
-
- verify(mStatsManager, times(1)).registerUsageCallback(
- any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(12)), any(), any());
- }
-
- @Test
- public void testGetMultipathPreference_UserWarningQuota() {
- testGetMultipathPreference(
- DataUnit.MEGABYTES.toBytes(7) /* usedBytesToday */,
- OPPORTUNISTIC_QUOTA_UNKNOWN,
- // 29 days from Apr. 2nd to May 1st
- DataUnit.MEGABYTES.toBytes(15 * 29 * 20) /* policyWarning */,
- LIMIT_DISABLED,
- DataUnit.MEGABYTES.toBytes(12) /* defaultGlobalSetting */,
- 2_500_000 /* defaultResSetting */,
- false /* roaming */);
-
- // Daily budget should be 15MB (5% of daily quota), 7MB used today: callback set for 8MB
- verify(mStatsManager, times(1)).registerUsageCallback(
- any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(8)), any(), any());
- }
-
- @Test
- public void testGetMultipathPreference_SnoozedWarningQuota() {
- testGetMultipathPreference(
- DataUnit.MEGABYTES.toBytes(7) /* usedBytesToday */,
- OPPORTUNISTIC_QUOTA_UNKNOWN,
- // 29 days from Apr. 2nd to May 1st
- POLICY_SNOOZED /* policyWarning */,
- DataUnit.MEGABYTES.toBytes(15 * 29 * 20) /* policyLimit */,
- DataUnit.MEGABYTES.toBytes(12) /* defaultGlobalSetting */,
- 2_500_000 /* defaultResSetting */,
- false /* roaming */);
-
- // Daily budget should be 15MB (5% of daily quota), 7MB used today: callback set for 8MB
- verify(mStatsManager, times(1)).registerUsageCallback(
- any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(8)), any(), any());
- }
-
- @Test
- public void testGetMultipathPreference_SnoozedBothQuota() {
- testGetMultipathPreference(
- DataUnit.MEGABYTES.toBytes(7) /* usedBytesToday */,
- OPPORTUNISTIC_QUOTA_UNKNOWN,
- // 29 days from Apr. 2nd to May 1st
- POLICY_SNOOZED /* policyWarning */,
- POLICY_SNOOZED /* policyLimit */,
- DataUnit.MEGABYTES.toBytes(12) /* defaultGlobalSetting */,
- 2_500_000 /* defaultResSetting */,
- false /* roaming */);
-
- // Default global setting should be used: 12 - 7 = 5
- verify(mStatsManager, times(1)).registerUsageCallback(
- any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(5)), any(), any());
- }
-
- @Test
- public void testGetMultipathPreference_SettingChanged() {
- testGetMultipathPreference(
- DataUnit.MEGABYTES.toBytes(2) /* usedBytesToday */,
- OPPORTUNISTIC_QUOTA_UNKNOWN,
- WARNING_DISABLED,
- LIMIT_DISABLED,
- -1 /* defaultGlobalSetting */,
- DataUnit.MEGABYTES.toBytes(10) /* defaultResSetting */,
- false /* roaming */);
-
- verify(mStatsManager, times(1)).registerUsageCallback(
- any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(8)), any(), any());
-
- // Update setting
- setDefaultQuotaGlobalSetting(DataUnit.MEGABYTES.toBytes(14));
- mTracker.mSettingsObserver.onChange(
- false, Settings.Global.getUriFor(NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES));
-
- // Callback must have been re-registered with new setting
- verify(mStatsManager, times(1)).unregisterUsageCallback(any());
- verify(mStatsManager, times(1)).registerUsageCallback(
- any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(12)), any(), any());
- }
-
- @Test
- public void testGetMultipathPreference_ResourceChanged() {
- testGetMultipathPreference(
- DataUnit.MEGABYTES.toBytes(2) /* usedBytesToday */,
- OPPORTUNISTIC_QUOTA_UNKNOWN,
- WARNING_DISABLED,
- LIMIT_DISABLED,
- -1 /* defaultGlobalSetting */,
- DataUnit.MEGABYTES.toBytes(14) /* defaultResSetting */,
- false /* roaming */);
-
- verify(mStatsManager, times(1)).registerUsageCallback(
- any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(12)), any(), any());
-
- when(mResources.getInteger(R.integer.config_networkDefaultDailyMultipathQuotaBytes))
- .thenReturn((int) DataUnit.MEGABYTES.toBytes(16));
-
- final BroadcastReceiver configChangeReceiver = mConfigChangeReceiverCaptor.getValue();
- assertNotNull(configChangeReceiver);
- configChangeReceiver.onReceive(mContext, new Intent());
-
- // Uses the new setting (16 - 2 = 14MB)
- verify(mStatsManager, times(1)).registerUsageCallback(
- any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(14)), any(), any());
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/Nat464XlatTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/Nat464XlatTest.java
deleted file mode 100644
index 9b2a638..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/Nat464XlatTest.java
+++ /dev/null
@@ -1,555 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.net.ConnectivityManager;
-import android.net.IDnsResolver;
-import android.net.INetd;
-import android.net.InterfaceConfigurationParcel;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.NetworkAgentConfig;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.os.Handler;
-import android.os.test.TestLooper;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.ConnectivityService;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class Nat464XlatTest {
-
- static final String BASE_IFACE = "test0";
- static final String STACKED_IFACE = "v4-test0";
- static final LinkAddress V6ADDR = new LinkAddress("2001:db8:1::f00/64");
- static final LinkAddress ADDR = new LinkAddress("192.0.2.5/29");
- static final String NAT64_PREFIX = "64:ff9b::/96";
- static final String OTHER_NAT64_PREFIX = "2001:db8:0:64::/96";
- static final int NETID = 42;
-
- @Mock ConnectivityService mConnectivity;
- @Mock IDnsResolver mDnsResolver;
- @Mock INetd mNetd;
- @Mock NetworkAgentInfo mNai;
-
- TestLooper mLooper;
- Handler mHandler;
- NetworkAgentConfig mAgentConfig = new NetworkAgentConfig();
-
- Nat464Xlat makeNat464Xlat(boolean isCellular464XlatEnabled) {
- return new Nat464Xlat(mNai, mNetd, mDnsResolver, new ConnectivityService.Dependencies()) {
- @Override protected int getNetId() {
- return NETID;
- }
-
- @Override protected boolean isCellular464XlatEnabled() {
- return isCellular464XlatEnabled;
- }
- };
- }
-
- private void markNetworkConnected() {
- mNai.networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "", "");
- }
-
- private void markNetworkDisconnected() {
- mNai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, "", "");
- }
-
- @Before
- public void setUp() throws Exception {
- mLooper = new TestLooper();
- mHandler = new Handler(mLooper.getLooper());
-
- MockitoAnnotations.initMocks(this);
-
- mNai.linkProperties = new LinkProperties();
- mNai.linkProperties.setInterfaceName(BASE_IFACE);
- mNai.networkInfo = new NetworkInfo(null);
- mNai.networkInfo.setType(ConnectivityManager.TYPE_WIFI);
- mNai.networkCapabilities = new NetworkCapabilities();
- markNetworkConnected();
- when(mNai.connService()).thenReturn(mConnectivity);
- when(mNai.netAgentConfig()).thenReturn(mAgentConfig);
- when(mNai.handler()).thenReturn(mHandler);
- final InterfaceConfigurationParcel mConfig = new InterfaceConfigurationParcel();
- when(mNetd.interfaceGetCfg(eq(STACKED_IFACE))).thenReturn(mConfig);
- mConfig.ipv4Addr = ADDR.getAddress().getHostAddress();
- mConfig.prefixLength = ADDR.getPrefixLength();
- }
-
- private void assertRequiresClat(boolean expected, NetworkAgentInfo nai) {
- Nat464Xlat nat = makeNat464Xlat(true);
- String msg = String.format("requiresClat expected %b for type=%d state=%s skip=%b "
- + "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(),
- nai.networkInfo.getDetailedState(),
- mAgentConfig.skip464xlat, nai.linkProperties.getNat64Prefix(),
- nai.linkProperties.getLinkAddresses());
- assertEquals(msg, expected, nat.requiresClat(nai));
- }
-
- private void assertShouldStartClat(boolean expected, NetworkAgentInfo nai) {
- Nat464Xlat nat = makeNat464Xlat(true);
- String msg = String.format("shouldStartClat expected %b for type=%d state=%s skip=%b "
- + "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(),
- nai.networkInfo.getDetailedState(),
- mAgentConfig.skip464xlat, nai.linkProperties.getNat64Prefix(),
- nai.linkProperties.getLinkAddresses());
- assertEquals(msg, expected, nat.shouldStartClat(nai));
- }
-
- @Test
- public void testRequiresClat() throws Exception {
- final int[] supportedTypes = {
- ConnectivityManager.TYPE_MOBILE,
- ConnectivityManager.TYPE_WIFI,
- ConnectivityManager.TYPE_ETHERNET,
- };
-
- // NetworkInfo doesn't allow setting the State directly, but rather
- // requires setting DetailedState in order set State as a side-effect.
- final NetworkInfo.DetailedState[] supportedDetailedStates = {
- NetworkInfo.DetailedState.CONNECTED,
- NetworkInfo.DetailedState.SUSPENDED,
- };
-
- LinkProperties oldLp = new LinkProperties(mNai.linkProperties);
- for (int type : supportedTypes) {
- mNai.networkInfo.setType(type);
- for (NetworkInfo.DetailedState state : supportedDetailedStates) {
- mNai.networkInfo.setDetailedState(state, "reason", "extraInfo");
-
- mNai.linkProperties.setNat64Prefix(new IpPrefix(OTHER_NAT64_PREFIX));
- assertRequiresClat(false, mNai);
- assertShouldStartClat(false, mNai);
-
- mNai.linkProperties.addLinkAddress(new LinkAddress("fc00::1/64"));
- assertRequiresClat(false, mNai);
- assertShouldStartClat(false, mNai);
-
- mNai.linkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64"));
- assertRequiresClat(true, mNai);
- assertShouldStartClat(true, mNai);
-
- mAgentConfig.skip464xlat = true;
- assertRequiresClat(false, mNai);
- assertShouldStartClat(false, mNai);
-
- mAgentConfig.skip464xlat = false;
- assertRequiresClat(true, mNai);
- assertShouldStartClat(true, mNai);
-
- mNai.linkProperties.addLinkAddress(new LinkAddress("192.0.2.2/24"));
- assertRequiresClat(false, mNai);
- assertShouldStartClat(false, mNai);
-
- mNai.linkProperties.removeLinkAddress(new LinkAddress("192.0.2.2/24"));
- assertRequiresClat(true, mNai);
- assertShouldStartClat(true, mNai);
-
- mNai.linkProperties.setNat64Prefix(null);
- assertRequiresClat(true, mNai);
- assertShouldStartClat(false, mNai);
-
- mNai.linkProperties = new LinkProperties(oldLp);
- }
- }
- }
-
- private void makeClatUnnecessary(boolean dueToDisconnect) {
- if (dueToDisconnect) {
- markNetworkDisconnected();
- } else {
- mNai.linkProperties.addLinkAddress(ADDR);
- }
- }
-
- private void checkNormalStartAndStop(boolean dueToDisconnect) throws Exception {
- Nat464Xlat nat = makeNat464Xlat(true);
- ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
-
- mNai.linkProperties.addLinkAddress(V6ADDR);
-
- nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
-
- // Start clat.
- nat.start();
-
- verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
-
- // Stacked interface up notification arrives.
- nat.interfaceLinkStateChanged(STACKED_IFACE, true);
- mLooper.dispatchNext();
-
- verify(mNetd).interfaceGetCfg(eq(STACKED_IFACE));
- verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
- assertFalse(c.getValue().getStackedLinks().isEmpty());
- assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- assertRunning(nat);
-
- // Stop clat (Network disconnects, IPv4 addr appears, ...).
- makeClatUnnecessary(dueToDisconnect);
- nat.stop();
-
- verify(mNetd).clatdStop(eq(BASE_IFACE));
- verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
- assertTrue(c.getValue().getStackedLinks().isEmpty());
- assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
- assertIdle(nat);
-
- // Stacked interface removed notification arrives and is ignored.
- nat.interfaceRemoved(STACKED_IFACE);
- mLooper.dispatchNext();
-
- verifyNoMoreInteractions(mNetd, mConnectivity);
- }
-
- @Test
- public void testNormalStartAndStopDueToDisconnect() throws Exception {
- checkNormalStartAndStop(true);
- }
-
- @Test
- public void testNormalStartAndStopDueToIpv4Addr() throws Exception {
- checkNormalStartAndStop(false);
- }
-
- private void checkStartStopStart(boolean interfaceRemovedFirst) throws Exception {
- Nat464Xlat nat = makeNat464Xlat(true);
- ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
- InOrder inOrder = inOrder(mNetd, mConnectivity);
-
- mNai.linkProperties.addLinkAddress(V6ADDR);
-
- nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
-
- nat.start();
-
- inOrder.verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
-
- // Stacked interface up notification arrives.
- nat.interfaceLinkStateChanged(STACKED_IFACE, true);
- mLooper.dispatchNext();
-
- inOrder.verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
- assertFalse(c.getValue().getStackedLinks().isEmpty());
- assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- assertRunning(nat);
-
- // ConnectivityService stops clat (Network disconnects, IPv4 addr appears, ...).
- nat.stop();
-
- inOrder.verify(mNetd).clatdStop(eq(BASE_IFACE));
-
- inOrder.verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture());
- assertTrue(c.getValue().getStackedLinks().isEmpty());
- assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- assertIdle(nat);
-
- if (interfaceRemovedFirst) {
- // Stacked interface removed notification arrives and is ignored.
- nat.interfaceRemoved(STACKED_IFACE);
- mLooper.dispatchNext();
- nat.interfaceLinkStateChanged(STACKED_IFACE, false);
- mLooper.dispatchNext();
- }
-
- assertTrue(c.getValue().getStackedLinks().isEmpty());
- assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- assertIdle(nat);
- inOrder.verifyNoMoreInteractions();
-
- nat.start();
-
- inOrder.verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
-
- if (!interfaceRemovedFirst) {
- // Stacked interface removed notification arrives and is ignored.
- nat.interfaceRemoved(STACKED_IFACE);
- mLooper.dispatchNext();
- nat.interfaceLinkStateChanged(STACKED_IFACE, false);
- mLooper.dispatchNext();
- }
-
- // Stacked interface up notification arrives.
- nat.interfaceLinkStateChanged(STACKED_IFACE, true);
- mLooper.dispatchNext();
-
- inOrder.verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
- assertFalse(c.getValue().getStackedLinks().isEmpty());
- assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- assertRunning(nat);
-
- // ConnectivityService stops clat again.
- nat.stop();
-
- inOrder.verify(mNetd).clatdStop(eq(BASE_IFACE));
-
- inOrder.verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture());
- assertTrue(c.getValue().getStackedLinks().isEmpty());
- assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- assertIdle(nat);
-
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void testStartStopStart() throws Exception {
- checkStartStopStart(true);
- }
-
- @Test
- public void testStartStopStartBeforeInterfaceRemoved() throws Exception {
- checkStartStopStart(false);
- }
-
- @Test
- public void testClatdCrashWhileRunning() throws Exception {
- Nat464Xlat nat = makeNat464Xlat(true);
- ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
-
- nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
-
- nat.start();
-
- verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
-
- // Stacked interface up notification arrives.
- nat.interfaceLinkStateChanged(STACKED_IFACE, true);
- mLooper.dispatchNext();
-
- verify(mNetd).interfaceGetCfg(eq(STACKED_IFACE));
- verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture());
- assertFalse(c.getValue().getStackedLinks().isEmpty());
- assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- assertRunning(nat);
-
- // Stacked interface removed notification arrives (clatd crashed, ...).
- nat.interfaceRemoved(STACKED_IFACE);
- mLooper.dispatchNext();
-
- verify(mNetd).clatdStop(eq(BASE_IFACE));
- verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
- verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
- assertTrue(c.getValue().getStackedLinks().isEmpty());
- assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
- assertIdle(nat);
-
- // ConnectivityService stops clat: no-op.
- nat.stop();
-
- verifyNoMoreInteractions(mNetd, mConnectivity);
- }
-
- private void checkStopBeforeClatdStarts(boolean dueToDisconnect) throws Exception {
- Nat464Xlat nat = makeNat464Xlat(true);
-
- mNai.linkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64"));
-
- nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
-
- nat.start();
-
- verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
-
- // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
- makeClatUnnecessary(dueToDisconnect);
- nat.stop();
-
- verify(mNetd).clatdStop(eq(BASE_IFACE));
- verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
- assertIdle(nat);
-
- // In-flight interface up notification arrives: no-op
- nat.interfaceLinkStateChanged(STACKED_IFACE, true);
- mLooper.dispatchNext();
-
- // Interface removed notification arrives after stopClatd() takes effect: no-op.
- nat.interfaceRemoved(STACKED_IFACE);
- mLooper.dispatchNext();
-
- assertIdle(nat);
-
- verifyNoMoreInteractions(mNetd, mConnectivity);
- }
-
- @Test
- public void testStopDueToDisconnectBeforeClatdStarts() throws Exception {
- checkStopBeforeClatdStarts(true);
- }
-
- @Test
- public void testStopDueToIpv4AddrBeforeClatdStarts() throws Exception {
- checkStopBeforeClatdStarts(false);
- }
-
- private void checkStopAndClatdNeverStarts(boolean dueToDisconnect) throws Exception {
- Nat464Xlat nat = makeNat464Xlat(true);
-
- mNai.linkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64"));
-
- nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
-
- nat.start();
-
- verify(mNetd).clatdStart(eq(BASE_IFACE), eq(NAT64_PREFIX));
-
- // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
- makeClatUnnecessary(dueToDisconnect);
- nat.stop();
-
- verify(mNetd).clatdStop(eq(BASE_IFACE));
- verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
- assertIdle(nat);
-
- verifyNoMoreInteractions(mNetd, mConnectivity);
- }
-
- @Test
- public void testStopDueToDisconnectAndClatdNeverStarts() throws Exception {
- checkStopAndClatdNeverStarts(true);
- }
-
- @Test
- public void testStopDueToIpv4AddressAndClatdNeverStarts() throws Exception {
- checkStopAndClatdNeverStarts(false);
- }
-
- @Test
- public void testNat64PrefixPreference() throws Exception {
- final IpPrefix prefixFromDns = new IpPrefix(NAT64_PREFIX);
- final IpPrefix prefixFromRa = new IpPrefix(OTHER_NAT64_PREFIX);
-
- Nat464Xlat nat = makeNat464Xlat(true);
-
- final LinkProperties emptyLp = new LinkProperties();
- LinkProperties fixedupLp;
-
- fixedupLp = new LinkProperties();
- nat.setNat64PrefixFromDns(prefixFromDns);
- nat.fixupLinkProperties(emptyLp, fixedupLp);
- assertEquals(prefixFromDns, fixedupLp.getNat64Prefix());
-
- fixedupLp = new LinkProperties();
- nat.setNat64PrefixFromRa(prefixFromRa);
- nat.fixupLinkProperties(emptyLp, fixedupLp);
- assertEquals(prefixFromRa, fixedupLp.getNat64Prefix());
-
- fixedupLp = new LinkProperties();
- nat.setNat64PrefixFromRa(null);
- nat.fixupLinkProperties(emptyLp, fixedupLp);
- assertEquals(prefixFromDns, fixedupLp.getNat64Prefix());
-
- fixedupLp = new LinkProperties();
- nat.setNat64PrefixFromRa(prefixFromRa);
- nat.fixupLinkProperties(emptyLp, fixedupLp);
- assertEquals(prefixFromRa, fixedupLp.getNat64Prefix());
-
- fixedupLp = new LinkProperties();
- nat.setNat64PrefixFromDns(null);
- nat.fixupLinkProperties(emptyLp, fixedupLp);
- assertEquals(prefixFromRa, fixedupLp.getNat64Prefix());
-
- fixedupLp = new LinkProperties();
- nat.setNat64PrefixFromRa(null);
- nat.fixupLinkProperties(emptyLp, fixedupLp);
- assertEquals(null, fixedupLp.getNat64Prefix());
- }
-
- private void checkClatDisabledOnCellular(boolean onCellular) throws Exception {
- // Disable 464xlat on cellular networks.
- Nat464Xlat nat = makeNat464Xlat(false);
- mNai.linkProperties.addLinkAddress(V6ADDR);
- mNai.networkCapabilities.setTransportType(TRANSPORT_CELLULAR, onCellular);
- nat.update();
-
- final IpPrefix nat64Prefix = new IpPrefix(NAT64_PREFIX);
- if (onCellular) {
- // Prefix discovery is never started.
- verify(mDnsResolver, never()).startPrefix64Discovery(eq(NETID));
- assertIdle(nat);
-
- // If a NAT64 prefix comes in from an RA, clat is not started either.
- mNai.linkProperties.setNat64Prefix(nat64Prefix);
- nat.setNat64PrefixFromRa(nat64Prefix);
- nat.update();
- verify(mNetd, never()).clatdStart(anyString(), anyString());
- assertIdle(nat);
- } else {
- // Prefix discovery is started.
- verify(mDnsResolver).startPrefix64Discovery(eq(NETID));
- assertIdle(nat);
-
- // If a NAT64 prefix comes in from an RA, clat is started.
- mNai.linkProperties.setNat64Prefix(nat64Prefix);
- nat.setNat64PrefixFromRa(nat64Prefix);
- nat.update();
- verify(mNetd).clatdStart(BASE_IFACE, NAT64_PREFIX);
- assertStarting(nat);
- }
- }
-
- @Test
- public void testClatDisabledOnCellular() throws Exception {
- checkClatDisabledOnCellular(true);
- }
-
- @Test
- public void testClatDisabledOnNonCellular() throws Exception {
- checkClatDisabledOnCellular(false);
- }
-
- static void assertIdle(Nat464Xlat nat) {
- assertTrue("Nat464Xlat was not IDLE", !nat.isStarted());
- }
-
- static void assertStarting(Nat464Xlat nat) {
- assertTrue("Nat464Xlat was not STARTING", nat.isStarting());
- }
-
- static void assertRunning(Nat464Xlat nat) {
- assertTrue("Nat464Xlat was not RUNNING", nat.isRunning());
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
deleted file mode 100644
index 50aaaee..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ /dev/null
@@ -1,554 +0,0 @@
-/*
- * Copyright (C) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO;
-import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME;
-
-import static com.android.testutils.MiscAsserts.assertStringContains;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.system.OsConstants;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Base64;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
-import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetdEventListenerServiceTest {
- private static final String EXAMPLE_IPV4 = "192.0.2.1";
- private static final String EXAMPLE_IPV6 = "2001:db8:1200::2:1";
-
- private static final byte[] MAC_ADDR =
- {(byte)0x84, (byte)0xc9, (byte)0xb2, (byte)0x6a, (byte)0xed, (byte)0x4b};
-
- NetdEventListenerService mService;
- ConnectivityManager mCm;
- private static final NetworkCapabilities CAPABILITIES_WIFI = new NetworkCapabilities.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .build();
- private static final NetworkCapabilities CAPABILITIES_CELL = new NetworkCapabilities.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .build();
-
- @Before
- public void setUp() {
- mCm = mock(ConnectivityManager.class);
- mService = new NetdEventListenerService(mCm);
- }
-
- @Test
- public void testWakeupEventLogging() throws Exception {
- final int BUFFER_LENGTH = NetdEventListenerService.WAKEUP_EVENT_BUFFER_LENGTH;
- final long now = System.currentTimeMillis();
- final String iface = "wlan0";
- final byte[] mac = MAC_ADDR;
- final String srcIp = "192.168.2.1";
- final String dstIp = "192.168.2.23";
- final String srcIp6 = "2001:db8:4:fd00:a585:13d1:6a23:4fb4";
- final String dstIp6 = "2001:db8:4006:807::200a";
- final int sport = 2356;
- final int dport = 13489;
-
- final int v4 = 0x800;
- final int v6 = 0x86dd;
- final int tcp = 6;
- final int udp = 17;
- final int icmp6 = 58;
-
- // Baseline without any event
- String[] baseline = listNetdEvent();
-
- int[] uids = {10001, 10002, 10004, 1000, 10052, 10023, 10002, 10123, 10004};
- wakeupEvent(iface, uids[0], v4, tcp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent(iface, uids[1], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent(iface, uids[2], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent(iface, uids[3], v4, icmp6, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent(iface, uids[4], v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent(iface, uids[5], v4, tcp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent(iface, uids[6], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent(iface, uids[7], v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent(iface, uids[8], v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
-
- String[] events2 = remove(listNetdEvent(), baseline);
- int expectedLength2 = uids.length + 1; // +1 for the WakeupStats line
- assertEquals(expectedLength2, events2.length);
- assertStringContains(events2[0], "WakeupStats");
- assertStringContains(events2[0], "wlan0");
- assertStringContains(events2[0], "0x800");
- assertStringContains(events2[0], "0x86dd");
- for (int i = 0; i < uids.length; i++) {
- String got = events2[i+1];
- assertStringContains(got, "WakeupEvent");
- assertStringContains(got, "wlan0");
- assertStringContains(got, "uid: " + uids[i]);
- }
-
- int uid = 20000;
- for (int i = 0; i < BUFFER_LENGTH * 2; i++) {
- long ts = now + 10;
- wakeupEvent(iface, uid, 0x800, 6, mac, srcIp, dstIp, 23, 24, ts);
- }
-
- String[] events3 = remove(listNetdEvent(), baseline);
- int expectedLength3 = BUFFER_LENGTH + 1; // +1 for the WakeupStats line
- assertEquals(expectedLength3, events3.length);
- assertStringContains(events2[0], "WakeupStats");
- assertStringContains(events2[0], "wlan0");
- for (int i = 1; i < expectedLength3; i++) {
- String got = events3[i];
- assertStringContains(got, "WakeupEvent");
- assertStringContains(got, "wlan0");
- assertStringContains(got, "uid: " + uid);
- }
-
- uid = 45678;
- wakeupEvent(iface, uid, 0x800, 6, mac, srcIp, dstIp, 23, 24, now);
-
- String[] events4 = remove(listNetdEvent(), baseline);
- String lastEvent = events4[events4.length - 1];
- assertStringContains(lastEvent, "WakeupEvent");
- assertStringContains(lastEvent, "wlan0");
- assertStringContains(lastEvent, "uid: " + uid);
- }
-
- @Test
- public void testWakeupStatsLogging() throws Exception {
- final byte[] mac = MAC_ADDR;
- final String srcIp = "192.168.2.1";
- final String dstIp = "192.168.2.23";
- final String srcIp6 = "2401:fa00:4:fd00:a585:13d1:6a23:4fb4";
- final String dstIp6 = "2404:6800:4006:807::200a";
- final int sport = 2356;
- final int dport = 13489;
- final long now = 1001L;
-
- final int v4 = 0x800;
- final int v6 = 0x86dd;
- final int tcp = 6;
- final int udp = 17;
- final int icmp6 = 58;
-
- wakeupEvent("wlan0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent("rmnet0", 10123, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent("wlan0", 1000, v4, udp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent("rmnet0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent("wlan0", -1, v6, icmp6, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent("wlan0", 10008, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent("rmnet0", 1000, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent("wlan0", 10004, v4, udp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent("wlan0", 1000, v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent("wlan0", 0, v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent("wlan0", -1, v6, icmp6, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent("rmnet0", 10052, v4, tcp, mac, srcIp, dstIp, sport, dport, now);
- wakeupEvent("wlan0", 0, v6, udp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent("rmnet0", 1000, v6, tcp, mac, srcIp6, dstIp6, sport, dport, now);
- wakeupEvent("wlan0", 1010, v4, udp, mac, srcIp, dstIp, sport, dport, now);
-
- String got = flushStatistics();
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 2",
- " network_id: 0",
- " time_ms: 0",
- " transports: 0",
- " wakeup_stats <",
- " application_wakeups: 3",
- " duration_sec: 0",
- " ethertype_counts <",
- " key: 2048",
- " value: 4",
- " >",
- " ethertype_counts <",
- " key: 34525",
- " value: 1",
- " >",
- " ip_next_header_counts <",
- " key: 6",
- " value: 5",
- " >",
- " l2_broadcast_count: 0",
- " l2_multicast_count: 0",
- " l2_unicast_count: 5",
- " no_uid_wakeups: 0",
- " non_application_wakeups: 0",
- " root_wakeups: 0",
- " system_wakeups: 2",
- " total_wakeups: 5",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 0",
- " time_ms: 0",
- " transports: 0",
- " wakeup_stats <",
- " application_wakeups: 2",
- " duration_sec: 0",
- " ethertype_counts <",
- " key: 2048",
- " value: 5",
- " >",
- " ethertype_counts <",
- " key: 34525",
- " value: 5",
- " >",
- " ip_next_header_counts <",
- " key: 6",
- " value: 3",
- " >",
- " ip_next_header_counts <",
- " key: 17",
- " value: 5",
- " >",
- " ip_next_header_counts <",
- " key: 58",
- " value: 2",
- " >",
- " l2_broadcast_count: 0",
- " l2_multicast_count: 0",
- " l2_unicast_count: 10",
- " no_uid_wakeups: 2",
- " non_application_wakeups: 1",
- " root_wakeups: 2",
- " system_wakeups: 3",
- " total_wakeups: 10",
- " >",
- ">",
- "version: 2\n");
- assertEquals(want, got);
- }
-
- @Test
- public void testDnsLogging() throws Exception {
- asyncDump(100);
-
- dnsEvent(100, EVENT_GETADDRINFO, 0, 3456);
- dnsEvent(100, EVENT_GETADDRINFO, 0, 267);
- dnsEvent(100, EVENT_GETHOSTBYNAME, 22, 1230);
- dnsEvent(100, EVENT_GETADDRINFO, 3, 45);
- dnsEvent(100, EVENT_GETADDRINFO, 1, 2111);
- dnsEvent(100, EVENT_GETADDRINFO, 0, 450);
- dnsEvent(100, EVENT_GETHOSTBYNAME, 200, 638);
- dnsEvent(100, EVENT_GETHOSTBYNAME, 178, 1300);
- dnsEvent(101, EVENT_GETADDRINFO, 0, 56);
- dnsEvent(101, EVENT_GETADDRINFO, 0, 78);
- dnsEvent(101, EVENT_GETADDRINFO, 0, 14);
- dnsEvent(101, EVENT_GETHOSTBYNAME, 0, 56);
- dnsEvent(101, EVENT_GETADDRINFO, 0, 78);
- dnsEvent(101, EVENT_GETADDRINFO, 0, 14);
-
- String got = flushStatistics();
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 100",
- " time_ms: 0",
- " transports: 2",
- " dns_lookup_batch <",
- " event_types: 1",
- " event_types: 1",
- " event_types: 2",
- " event_types: 1",
- " event_types: 1",
- " event_types: 1",
- " event_types: 2",
- " event_types: 2",
- " getaddrinfo_error_count: 0",
- " getaddrinfo_query_count: 0",
- " gethostbyname_error_count: 0",
- " gethostbyname_query_count: 0",
- " latencies_ms: 3456",
- " latencies_ms: 267",
- " latencies_ms: 1230",
- " latencies_ms: 45",
- " latencies_ms: 2111",
- " latencies_ms: 450",
- " latencies_ms: 638",
- " latencies_ms: 1300",
- " return_codes: 0",
- " return_codes: 0",
- " return_codes: 22",
- " return_codes: 3",
- " return_codes: 1",
- " return_codes: 0",
- " return_codes: 200",
- " return_codes: 178",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 2",
- " network_id: 101",
- " time_ms: 0",
- " transports: 1",
- " dns_lookup_batch <",
- " event_types: 1",
- " event_types: 1",
- " event_types: 1",
- " event_types: 2",
- " event_types: 1",
- " event_types: 1",
- " getaddrinfo_error_count: 0",
- " getaddrinfo_query_count: 0",
- " gethostbyname_error_count: 0",
- " gethostbyname_query_count: 0",
- " latencies_ms: 56",
- " latencies_ms: 78",
- " latencies_ms: 14",
- " latencies_ms: 56",
- " latencies_ms: 78",
- " latencies_ms: 14",
- " return_codes: 0",
- " return_codes: 0",
- " return_codes: 0",
- " return_codes: 0",
- " return_codes: 0",
- " return_codes: 0",
- " >",
- ">",
- "version: 2\n");
- assertEquals(want, got);
- }
-
- @Test
- public void testConnectLogging() throws Exception {
- asyncDump(100);
-
- final int OK = 0;
- Thread[] logActions = {
- // ignored
- connectEventAction(100, OsConstants.EALREADY, 0, EXAMPLE_IPV4),
- connectEventAction(100, OsConstants.EALREADY, 0, EXAMPLE_IPV6),
- connectEventAction(100, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV4),
- connectEventAction(101, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6),
- connectEventAction(101, OsConstants.EINPROGRESS, 0, EXAMPLE_IPV6),
- // valid latencies
- connectEventAction(100, OK, 110, EXAMPLE_IPV4),
- connectEventAction(100, OK, 23, EXAMPLE_IPV4),
- connectEventAction(100, OK, 45, EXAMPLE_IPV4),
- connectEventAction(101, OK, 56, EXAMPLE_IPV4),
- connectEventAction(101, OK, 523, EXAMPLE_IPV6),
- connectEventAction(101, OK, 214, EXAMPLE_IPV6),
- connectEventAction(101, OK, 67, EXAMPLE_IPV6),
- // errors
- connectEventAction(100, OsConstants.EPERM, 0, EXAMPLE_IPV4),
- connectEventAction(101, OsConstants.EPERM, 0, EXAMPLE_IPV4),
- connectEventAction(100, OsConstants.EAGAIN, 0, EXAMPLE_IPV4),
- connectEventAction(100, OsConstants.EACCES, 0, EXAMPLE_IPV4),
- connectEventAction(101, OsConstants.EACCES, 0, EXAMPLE_IPV4),
- connectEventAction(101, OsConstants.EACCES, 0, EXAMPLE_IPV6),
- connectEventAction(100, OsConstants.EADDRINUSE, 0, EXAMPLE_IPV4),
- connectEventAction(101, OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV4),
- connectEventAction(100, OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV6),
- connectEventAction(100, OsConstants.ETIMEDOUT, 0, EXAMPLE_IPV6),
- connectEventAction(101, OsConstants.ECONNREFUSED, 0, EXAMPLE_IPV4),
- };
-
- for (Thread t : logActions) {
- t.start();
- }
- for (Thread t : logActions) {
- t.join();
- }
-
- String got = flushStatistics();
- String want = String.join("\n",
- "dropped_events: 0",
- "events <",
- " if_name: \"\"",
- " link_layer: 4",
- " network_id: 100",
- " time_ms: 0",
- " transports: 2",
- " connect_statistics <",
- " connect_blocking_count: 3",
- " connect_count: 6",
- " errnos_counters <",
- " key: 1",
- " value: 1",
- " >",
- " errnos_counters <",
- " key: 11",
- " value: 1",
- " >",
- " errnos_counters <",
- " key: 13",
- " value: 1",
- " >",
- " errnos_counters <",
- " key: 98",
- " value: 1",
- " >",
- " errnos_counters <",
- " key: 110",
- " value: 2",
- " >",
- " ipv6_addr_count: 1",
- " latencies_ms: 23",
- " latencies_ms: 45",
- " latencies_ms: 110",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 2",
- " network_id: 101",
- " time_ms: 0",
- " transports: 1",
- " connect_statistics <",
- " connect_blocking_count: 4",
- " connect_count: 6",
- " errnos_counters <",
- " key: 1",
- " value: 1",
- " >",
- " errnos_counters <",
- " key: 13",
- " value: 2",
- " >",
- " errnos_counters <",
- " key: 110",
- " value: 1",
- " >",
- " errnos_counters <",
- " key: 111",
- " value: 1",
- " >",
- " ipv6_addr_count: 5",
- " latencies_ms: 56",
- " latencies_ms: 67",
- " latencies_ms: 214",
- " latencies_ms: 523",
- " >",
- ">",
- "version: 2\n");
- assertEquals(want, got);
- }
-
- private void setCapabilities(int netId) {
- final ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallback =
- ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
- verify(mCm).registerNetworkCallback(any(), networkCallback.capture());
- networkCallback.getValue().onCapabilitiesChanged(new Network(netId),
- netId == 100 ? CAPABILITIES_WIFI : CAPABILITIES_CELL);
- }
-
- Thread connectEventAction(int netId, int error, int latencyMs, String ipAddr) {
- setCapabilities(netId);
- return new Thread(() -> {
- try {
- mService.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
- } catch (Exception e) {
- fail(e.toString());
- }
- });
- }
-
- void dnsEvent(int netId, int type, int result, int latency) throws Exception {
- setCapabilities(netId);
- mService.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
- }
-
- void wakeupEvent(String iface, int uid, int ether, int ip, byte[] mac, String srcIp,
- String dstIp, int sport, int dport, long now) throws Exception {
- String prefix = NetdEventListenerService.WAKEUP_EVENT_IFACE_PREFIX + iface;
- mService.onWakeupEvent(prefix, uid, ether, ip, mac, srcIp, dstIp, sport, dport, now);
- }
-
- void asyncDump(long durationMs) throws Exception {
- final long stop = System.currentTimeMillis() + durationMs;
- final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
- new Thread(() -> {
- while (System.currentTimeMillis() < stop) {
- mService.list(pw);
- }
- }).start();
- }
-
- // TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
- String flushStatistics() throws Exception {
- IpConnectivityMetrics metricsService =
- new IpConnectivityMetrics(mock(Context.class), (ctx) -> 2000);
- metricsService.mNetdListener = mService;
-
- StringWriter buffer = new StringWriter();
- PrintWriter writer = new PrintWriter(buffer);
- metricsService.impl.dump(null, writer, new String[]{"flush"});
- byte[] bytes = Base64.decode(buffer.toString(), Base64.DEFAULT);
- IpConnectivityLog log = IpConnectivityLog.parseFrom(bytes);
- for (IpConnectivityEvent ev : log.events) {
- if (ev.getConnectStatistics() == null) {
- continue;
- }
- // Sort repeated fields of connect() events arriving in non-deterministic order.
- Arrays.sort(ev.getConnectStatistics().latenciesMs);
- Arrays.sort(ev.getConnectStatistics().errnosCounters,
- Comparator.comparingInt((p) -> p.key));
- }
- return log.toString();
- }
-
- String[] listNetdEvent() throws Exception {
- StringWriter buffer = new StringWriter();
- PrintWriter writer = new PrintWriter(buffer);
- mService.list(writer);
- return buffer.toString().split("\\n");
- }
-
- static <T> T[] remove(T[] array, T[] filtered) {
- List<T> c = Arrays.asList(filtered);
- int next = 0;
- for (int i = 0; i < array.length; i++) {
- if (c.contains(array[i])) {
- continue;
- }
- array[next++] = array[i];
- }
- return Arrays.copyOf(array, next);
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
deleted file mode 100644
index c353cea..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.app.Notification.FLAG_ONGOING_EVENT;
-
-import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.LOST_INTERNET;
-import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.NETWORK_SWITCH;
-import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.NO_INTERNET;
-import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.PARTIAL_CONNECTIVITY;
-import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.PRIVATE_DNS_BROKEN;
-import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.SIGN_IN;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.net.ConnectivityResources;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.os.UserHandle;
-import android.telephony.TelephonyManager;
-import android.util.DisplayMetrics;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.connectivity.resources.R;
-import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.AdditionalAnswers;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkNotificationManagerTest {
-
- private static final String TEST_SSID = "Test SSID";
- private static final String TEST_EXTRA_INFO = "extra";
- static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
- static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
- static final NetworkCapabilities VPN_CAPABILITIES = new NetworkCapabilities();
- static {
- CELL_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
- CELL_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
-
- WIFI_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- WIFI_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
- WIFI_CAPABILITIES.setSSID(TEST_SSID);
-
- // Set the underyling network to wifi.
- VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
- VPN_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
- VPN_CAPABILITIES.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
- }
-
- @Mock Context mCtx;
- @Mock Resources mResources;
- @Mock DisplayMetrics mDisplayMetrics;
- @Mock PackageManager mPm;
- @Mock TelephonyManager mTelephonyManager;
- @Mock NotificationManager mNotificationManager;
- @Mock NetworkAgentInfo mWifiNai;
- @Mock NetworkAgentInfo mCellNai;
- @Mock NetworkAgentInfo mVpnNai;
- @Mock NetworkInfo mNetworkInfo;
- ArgumentCaptor<Notification> mCaptor;
-
- NetworkNotificationManager mManager;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mCaptor = ArgumentCaptor.forClass(Notification.class);
- mWifiNai.networkCapabilities = WIFI_CAPABILITIES;
- mWifiNai.networkInfo = mNetworkInfo;
- mCellNai.networkCapabilities = CELL_CAPABILITIES;
- mCellNai.networkInfo = mNetworkInfo;
- mVpnNai.networkCapabilities = VPN_CAPABILITIES;
- mVpnNai.networkInfo = mNetworkInfo;
- mDisplayMetrics.density = 2.275f;
- doReturn(true).when(mVpnNai).isVPN();
- when(mCtx.getResources()).thenReturn(mResources);
- when(mCtx.getPackageManager()).thenReturn(mPm);
- when(mCtx.getApplicationInfo()).thenReturn(new ApplicationInfo());
- final Context asUserCtx = mock(Context.class, AdditionalAnswers.delegatesTo(mCtx));
- doReturn(UserHandle.ALL).when(asUserCtx).getUser();
- when(mCtx.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);
- when(mCtx.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
- .thenReturn(mNotificationManager);
- when(mNetworkInfo.getExtraInfo()).thenReturn(TEST_EXTRA_INFO);
- ConnectivityResources.setResourcesContextForTest(mCtx);
- when(mResources.getColor(anyInt(), any())).thenReturn(0xFF607D8B);
- when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
-
- // Come up with some credible-looking transport names. The actual values do not matter.
- String[] transportNames = new String[NetworkCapabilities.MAX_TRANSPORT + 1];
- for (int transport = 0; transport <= NetworkCapabilities.MAX_TRANSPORT; transport++) {
- transportNames[transport] = NetworkCapabilities.transportNameOf(transport);
- }
- when(mResources.getStringArray(R.array.network_switch_type_name))
- .thenReturn(transportNames);
-
- mManager = new NetworkNotificationManager(mCtx, mTelephonyManager);
- }
-
- @After
- public void tearDown() {
- ConnectivityResources.setResourcesContextForTest(null);
- }
-
- private void verifyTitleByNetwork(final int id, final NetworkAgentInfo nai, final int title) {
- final String tag = NetworkNotificationManager.tagFor(id);
- mManager.showNotification(id, PRIVATE_DNS_BROKEN, nai, null, null, true);
- verify(mNotificationManager, times(1))
- .notify(eq(tag), eq(PRIVATE_DNS_BROKEN.eventId), any());
- final int transportType = NetworkNotificationManager.approximateTransportType(nai);
- if (transportType == NetworkCapabilities.TRANSPORT_WIFI) {
- verify(mResources, times(1)).getString(eq(title), eq(TEST_EXTRA_INFO));
- } else {
- verify(mResources, times(1)).getString(title);
- }
- verify(mResources, times(1)).getString(eq(R.string.private_dns_broken_detailed));
- }
-
- @Test
- public void testTitleOfPrivateDnsBroken() {
- // Test the title of mobile data.
- verifyTitleByNetwork(100, mCellNai, R.string.mobile_no_internet);
- clearInvocations(mResources);
-
- // Test the title of wifi.
- verifyTitleByNetwork(101, mWifiNai, R.string.wifi_no_internet);
- clearInvocations(mResources);
-
- // Test the title of other networks.
- verifyTitleByNetwork(102, mVpnNai, R.string.other_networks_no_internet);
- clearInvocations(mResources);
- }
-
- @Test
- public void testNotificationsShownAndCleared() {
- final int NETWORK_ID_BASE = 100;
- List<NotificationType> types = Arrays.asList(NotificationType.values());
- List<Integer> ids = new ArrayList<>(types.size());
- for (int i = 0; i < types.size(); i++) {
- ids.add(NETWORK_ID_BASE + i);
- }
- Collections.shuffle(ids);
- Collections.shuffle(types);
-
- for (int i = 0; i < ids.size(); i++) {
- mManager.showNotification(ids.get(i), types.get(i), mWifiNai, mCellNai, null, false);
- }
-
- List<Integer> idsToClear = new ArrayList<>(ids);
- Collections.shuffle(idsToClear);
- for (int i = 0; i < ids.size(); i++) {
- mManager.clearNotification(idsToClear.get(i));
- }
-
- for (int i = 0; i < ids.size(); i++) {
- final int id = ids.get(i);
- final int eventId = types.get(i).eventId;
- final String tag = NetworkNotificationManager.tagFor(id);
- verify(mNotificationManager, times(1)).notify(eq(tag), eq(eventId), any());
- verify(mNotificationManager, times(1)).cancel(eq(tag), eq(eventId));
- }
- }
-
- @Test
- @Ignore
- // Ignored because the code under test calls Log.wtf, which crashes the tests on eng builds.
- // TODO: re-enable after fixing this (e.g., turn Log.wtf into exceptions that this test catches)
- public void testNoInternetNotificationsNotShownForCellular() {
- mManager.showNotification(100, NO_INTERNET, mCellNai, mWifiNai, null, false);
- mManager.showNotification(101, LOST_INTERNET, mCellNai, mWifiNai, null, false);
-
- verify(mNotificationManager, never()).notify(any(), anyInt(), any());
-
- mManager.showNotification(102, NO_INTERNET, mWifiNai, mCellNai, null, false);
-
- final int eventId = NO_INTERNET.eventId;
- final String tag = NetworkNotificationManager.tagFor(102);
- verify(mNotificationManager, times(1)).notify(eq(tag), eq(eventId), any());
- }
-
- @Test
- public void testNotificationsNotShownIfNoInternetCapability() {
- mWifiNai.networkCapabilities = new NetworkCapabilities();
- mWifiNai.networkCapabilities .addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- mManager.showNotification(102, NO_INTERNET, mWifiNai, mCellNai, null, false);
- mManager.showNotification(103, LOST_INTERNET, mWifiNai, mCellNai, null, false);
- mManager.showNotification(104, NETWORK_SWITCH, mWifiNai, mCellNai, null, false);
-
- verify(mNotificationManager, never()).notify(any(), anyInt(), any());
- }
-
- private void assertNotification(NotificationType type, boolean ongoing) {
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
- final ArgumentCaptor<Notification> noteCaptor = ArgumentCaptor.forClass(Notification.class);
- mManager.showNotification(id, type, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1)).notify(eq(tag), eq(type.eventId),
- noteCaptor.capture());
-
- assertEquals("Notification ongoing flag should be " + (ongoing ? "set" : "unset"),
- ongoing, (noteCaptor.getValue().flags & FLAG_ONGOING_EVENT) != 0);
- }
-
- @Test
- public void testDuplicatedNotificationsNoInternetThenSignIn() {
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
-
- // Show first NO_INTERNET
- assertNotification(NO_INTERNET, false /* ongoing */);
-
- // Captive portal detection triggers SIGN_IN a bit later, clearing the previous NO_INTERNET
- assertNotification(SIGN_IN, false /* ongoing */);
- verify(mNotificationManager, times(1)).cancel(eq(tag), eq(NO_INTERNET.eventId));
-
- // Network disconnects
- mManager.clearNotification(id);
- verify(mNotificationManager, times(1)).cancel(eq(tag), eq(SIGN_IN.eventId));
- }
-
- @Test
- public void testOngoingSignInNotification() {
- doReturn(true).when(mResources).getBoolean(R.bool.config_ongoingSignInNotification);
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
-
- // Show first NO_INTERNET
- assertNotification(NO_INTERNET, false /* ongoing */);
-
- // Captive portal detection triggers SIGN_IN a bit later, clearing the previous NO_INTERNET
- assertNotification(SIGN_IN, true /* ongoing */);
- verify(mNotificationManager, times(1)).cancel(eq(tag), eq(NO_INTERNET.eventId));
-
- // Network disconnects
- mManager.clearNotification(id);
- verify(mNotificationManager, times(1)).cancel(eq(tag), eq(SIGN_IN.eventId));
- }
-
- @Test
- public void testDuplicatedNotificationsSignInThenNoInternet() {
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
-
- // Show first SIGN_IN
- mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1)).notify(eq(tag), eq(SIGN_IN.eventId), any());
- reset(mNotificationManager);
-
- // NO_INTERNET arrives after, but is ignored.
- mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, never()).cancel(any(), anyInt());
- verify(mNotificationManager, never()).notify(any(), anyInt(), any());
-
- // Network disconnects
- mManager.clearNotification(id);
- verify(mNotificationManager, times(1)).cancel(eq(tag), eq(SIGN_IN.eventId));
- }
-
- @Test
- public void testClearNotificationByType() {
- final int id = 101;
- final String tag = NetworkNotificationManager.tagFor(id);
-
- // clearNotification(int id, NotificationType notifyType) will check if given type is equal
- // to previous type or not. If they are equal then clear the notification; if they are not
- // equal then return.
- mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1)).notify(eq(tag), eq(NO_INTERNET.eventId), any());
-
- // Previous notification is NO_INTERNET and given type is NO_INTERNET too. The notification
- // should be cleared.
- mManager.clearNotification(id, NO_INTERNET);
- verify(mNotificationManager, times(1)).cancel(eq(tag), eq(NO_INTERNET.eventId));
-
- // SIGN_IN is popped-up.
- mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1)).notify(eq(tag), eq(SIGN_IN.eventId), any());
-
- // The notification type is not matching previous one, PARTIAL_CONNECTIVITY won't be
- // cleared.
- mManager.clearNotification(id, PARTIAL_CONNECTIVITY);
- verify(mNotificationManager, never()).cancel(eq(tag), eq(PARTIAL_CONNECTIVITY.eventId));
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetworkOfferTest.kt b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetworkOfferTest.kt
deleted file mode 100644
index 409f8c3..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetworkOfferTest.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity
-
-import android.net.INetworkOfferCallback
-import android.net.NetworkCapabilities
-import android.net.NetworkRequest
-import android.net.NetworkScore.KEEP_CONNECTED_NONE
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
-import kotlin.test.assertFalse
-import kotlin.test.assertTrue
-
-const val POLICY_NONE = 0L
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class NetworkOfferTest {
- val mockCallback = mock(INetworkOfferCallback::class.java)
-
- @Test
- fun testOfferNeededUnneeded() {
- val score = FullScore(50, POLICY_NONE, KEEP_CONNECTED_NONE)
- val offer = NetworkOffer(score, NetworkCapabilities.Builder().build(), mockCallback,
- 1 /* providerId */)
- val request1 = mock(NetworkRequest::class.java)
- val request2 = mock(NetworkRequest::class.java)
- offer.onNetworkNeeded(request1)
- verify(mockCallback).onNetworkNeeded(eq(request1))
- assertTrue(offer.neededFor(request1))
- assertFalse(offer.neededFor(request2))
-
- offer.onNetworkNeeded(request2)
- verify(mockCallback).onNetworkNeeded(eq(request2))
- assertTrue(offer.neededFor(request1))
- assertTrue(offer.neededFor(request2))
-
- // Note that the framework never calls onNetworkNeeded multiple times with the same
- // request without calling onNetworkUnneeded first. It would be incorrect usage and the
- // behavior would be undefined, so there is nothing to test.
-
- offer.onNetworkUnneeded(request1)
- verify(mockCallback).onNetworkUnneeded(eq(request1))
- assertFalse(offer.neededFor(request1))
- assertTrue(offer.neededFor(request2))
-
- offer.onNetworkUnneeded(request2)
- verify(mockCallback).onNetworkUnneeded(eq(request2))
- assertFalse(offer.neededFor(request1))
- assertFalse(offer.neededFor(request2))
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt
deleted file mode 100644
index 4408958..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/NetworkRankerTest.kt
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity
-
-import android.net.NetworkCapabilities
-import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
-import android.net.NetworkCapabilities.TRANSPORT_WIFI
-import android.net.NetworkScore.KEEP_CONNECTED_NONE
-import android.net.NetworkScore.POLICY_EXITING
-import android.net.NetworkScore.POLICY_TRANSPORT_PRIMARY
-import android.net.NetworkScore.POLICY_YIELD_TO_BAD_WIFI
-import android.os.Build
-import androidx.test.filters.SmallTest
-import com.android.server.connectivity.FullScore.POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD
-import com.android.server.connectivity.FullScore.POLICY_IS_VALIDATED
-import com.android.testutils.DevSdkIgnoreRule
-import com.android.testutils.DevSdkIgnoreRunner
-import org.junit.Test
-import org.junit.runner.RunWith
-import kotlin.test.assertEquals
-
-private fun score(vararg policies: Int) = FullScore(0,
- policies.fold(0L) { acc, e -> acc or (1L shl e) }, KEEP_CONNECTED_NONE)
-private fun caps(transport: Int) = NetworkCapabilities.Builder().addTransportType(transport).build()
-
-@SmallTest
-@RunWith(DevSdkIgnoreRunner::class)
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
-class NetworkRankerTest {
- private val mRanker = NetworkRanker()
-
- private class TestScore(private val sc: FullScore, private val nc: NetworkCapabilities)
- : NetworkRanker.Scoreable {
- override fun getScore() = sc
- override fun getCapsNoCopy(): NetworkCapabilities = nc
- }
-
- @Test
- fun testYieldToBadWiFiOneCell() {
- // Only cell, it wins
- val winner = TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
- caps(TRANSPORT_CELLULAR))
- val scores = listOf(winner)
- assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
- }
-
- @Test
- fun testYieldToBadWiFiOneCellOneBadWiFi() {
- // Bad wifi wins against yielding validated cell
- val winner = TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD),
- caps(TRANSPORT_WIFI))
- val scores = listOf(
- winner,
- TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
- caps(TRANSPORT_CELLULAR))
- )
- assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
- }
-
- @Test
- fun testYieldToBadWiFiOneCellTwoBadWiFi() {
- // Bad wifi wins against yielding validated cell. Prefer the one that's primary.
- val winner = TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
- POLICY_TRANSPORT_PRIMARY), caps(TRANSPORT_WIFI))
- val scores = listOf(
- winner,
- TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD),
- caps(TRANSPORT_WIFI)),
- TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
- caps(TRANSPORT_CELLULAR))
- )
- assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
- }
-
- @Test
- fun testYieldToBadWiFiOneCellTwoBadWiFiOneNotAvoided() {
- // Bad wifi ever validated wins against bad wifi that never was validated (or was
- // avoided when bad).
- val winner = TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD),
- caps(TRANSPORT_WIFI))
- val scores = listOf(
- winner,
- TestScore(score(), caps(TRANSPORT_WIFI)),
- TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
- caps(TRANSPORT_CELLULAR))
- )
- assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
- }
-
- @Test
- fun testYieldToBadWiFiOneCellOneBadWiFiOneGoodWiFi() {
- // Good wifi wins
- val winner = TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
- POLICY_IS_VALIDATED), caps(TRANSPORT_WIFI))
- val scores = listOf(
- winner,
- TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
- POLICY_TRANSPORT_PRIMARY), caps(TRANSPORT_WIFI)),
- TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
- caps(TRANSPORT_CELLULAR))
- )
- assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
- }
-
- @Test
- fun testYieldToBadWiFiTwoCellsOneBadWiFi() {
- // Cell that doesn't yield wins over cell that yields and bad wifi
- val winner = TestScore(score(POLICY_IS_VALIDATED), caps(TRANSPORT_CELLULAR))
- val scores = listOf(
- winner,
- TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
- POLICY_TRANSPORT_PRIMARY), caps(TRANSPORT_WIFI)),
- TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
- caps(TRANSPORT_CELLULAR))
- )
- assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
- }
-
- @Test
- fun testYieldToBadWiFiTwoCellsOneBadWiFiOneGoodWiFi() {
- // Good wifi wins over cell that doesn't yield and cell that yields
- val winner = TestScore(score(POLICY_IS_VALIDATED), caps(TRANSPORT_WIFI))
- val scores = listOf(
- winner,
- TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
- POLICY_TRANSPORT_PRIMARY), caps(TRANSPORT_WIFI)),
- TestScore(score(POLICY_IS_VALIDATED), caps(TRANSPORT_CELLULAR)),
- TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
- caps(TRANSPORT_CELLULAR))
- )
- assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
- }
-
- @Test
- fun testYieldToBadWiFiOneExitingGoodWiFi() {
- // Yielding cell wins over good exiting wifi
- val winner = TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
- caps(TRANSPORT_CELLULAR))
- val scores = listOf(
- winner,
- TestScore(score(POLICY_IS_VALIDATED, POLICY_EXITING), caps(TRANSPORT_WIFI))
- )
- assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
- }
-
- @Test
- fun testYieldToBadWiFiOneExitingBadWiFi() {
- // Yielding cell wins over bad exiting wifi
- val winner = TestScore(score(POLICY_YIELD_TO_BAD_WIFI, POLICY_IS_VALIDATED),
- caps(TRANSPORT_CELLULAR))
- val scores = listOf(
- winner,
- TestScore(score(POLICY_EVER_VALIDATED_NOT_AVOIDED_WHEN_BAD,
- POLICY_EXITING), caps(TRANSPORT_WIFI))
- )
- assertEquals(winner, mRanker.getBestNetworkByPolicy(scores, null))
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
deleted file mode 100644
index c75618f..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ /dev/null
@@ -1,1001 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.connectivity;
-
-import static android.Manifest.permission.CHANGE_NETWORK_STATE;
-import static android.Manifest.permission.CHANGE_WIFI_STATE;
-import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
-import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
-import static android.Manifest.permission.INTERNET;
-import static android.Manifest.permission.NETWORK_STACK;
-import static android.Manifest.permission.UPDATE_DEVICE_STATS;
-import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_OEM;
-import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT;
-import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
-import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
-import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_REQUIRED;
-import static android.content.pm.PackageManager.GET_PERMISSIONS;
-import static android.content.pm.PackageManager.MATCH_ANY_USER;
-import static android.net.ConnectivitySettingsManager.APPS_ALLOWED_ON_RESTRICTED_NETWORKS;
-import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
-import static android.os.Process.SYSTEM_UID;
-
-import static com.android.server.connectivity.PermissionMonitor.NETWORK;
-import static com.android.server.connectivity.PermissionMonitor.SYSTEM;
-
-import static junit.framework.Assert.fail;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.AdditionalMatchers.aryEq;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.database.ContentObserver;
-import android.net.INetd;
-import android.net.UidRange;
-import android.net.Uri;
-import android.os.Build;
-import android.os.SystemConfigManager;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.ArraySet;
-import android.util.SparseIntArray;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.AdditionalAnswers;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class PermissionMonitorTest {
- private static final UserHandle MOCK_USER1 = UserHandle.of(0);
- private static final UserHandle MOCK_USER2 = UserHandle.of(1);
- private static final int MOCK_UID1 = 10001;
- private static final int MOCK_UID2 = 10086;
- private static final int SYSTEM_UID1 = 1000;
- private static final int SYSTEM_UID2 = 1008;
- private static final int VPN_UID = 10002;
- private static final String REAL_SYSTEM_PACKAGE_NAME = "android";
- private static final String MOCK_PACKAGE1 = "appName1";
- private static final String MOCK_PACKAGE2 = "appName2";
- private static final String SYSTEM_PACKAGE1 = "sysName1";
- private static final String SYSTEM_PACKAGE2 = "sysName2";
- private static final String PARTITION_SYSTEM = "system";
- private static final String PARTITION_OEM = "oem";
- private static final String PARTITION_PRODUCT = "product";
- private static final String PARTITION_VENDOR = "vendor";
- private static final int VERSION_P = Build.VERSION_CODES.P;
- private static final int VERSION_Q = Build.VERSION_CODES.Q;
-
- @Mock private Context mContext;
- @Mock private PackageManager mPackageManager;
- @Mock private INetd mNetdService;
- @Mock private UserManager mUserManager;
- @Mock private PermissionMonitor.Dependencies mDeps;
- @Mock private SystemConfigManager mSystemConfigManager;
-
- private PermissionMonitor mPermissionMonitor;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- when(mContext.getPackageManager()).thenReturn(mPackageManager);
- when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
- when(mUserManager.getUserHandles(eq(true))).thenReturn(
- Arrays.asList(new UserHandle[] { MOCK_USER1, MOCK_USER2 }));
- when(mContext.getSystemServiceName(SystemConfigManager.class))
- .thenReturn(Context.SYSTEM_CONFIG_SERVICE);
- when(mContext.getSystemService(Context.SYSTEM_CONFIG_SERVICE))
- .thenReturn(mSystemConfigManager);
- when(mSystemConfigManager.getSystemPermissionUids(anyString())).thenReturn(new int[0]);
- final Context asUserCtx = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
- doReturn(UserHandle.ALL).when(asUserCtx).getUser();
- when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);
- when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
-
- mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
-
- when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
- mPermissionMonitor.startMonitoring();
- }
-
- private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
- String... permissions) {
- return hasRestrictedNetworkPermission(
- partition, targetSdkVersion, "" /* packageName */, uid, permissions);
- }
-
- private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion,
- String packageName, int uid, String... permissions) {
- final PackageInfo packageInfo =
- packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, permissions, partition);
- packageInfo.packageName = packageName;
- packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
- packageInfo.applicationInfo.uid = uid;
- return mPermissionMonitor.hasRestrictedNetworkPermission(packageInfo);
- }
-
- private static PackageInfo systemPackageInfoWithPermissions(String... permissions) {
- return packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM);
- }
-
- private static PackageInfo vendorPackageInfoWithPermissions(String... permissions) {
- return packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_VENDOR);
- }
-
- private static PackageInfo packageInfoWithPermissions(int permissionsFlags,
- String[] permissions, String partition) {
- int[] requestedPermissionsFlags = new int[permissions.length];
- for (int i = 0; i < permissions.length; i++) {
- requestedPermissionsFlags[i] = permissionsFlags;
- }
- final PackageInfo packageInfo = new PackageInfo();
- packageInfo.requestedPermissions = permissions;
- packageInfo.applicationInfo = new ApplicationInfo();
- packageInfo.requestedPermissionsFlags = requestedPermissionsFlags;
- int privateFlags = 0;
- switch (partition) {
- case PARTITION_OEM:
- privateFlags = PRIVATE_FLAG_OEM;
- break;
- case PARTITION_PRODUCT:
- privateFlags = PRIVATE_FLAG_PRODUCT;
- break;
- case PARTITION_VENDOR:
- privateFlags = PRIVATE_FLAG_VENDOR;
- break;
- }
- packageInfo.applicationInfo.privateFlags = privateFlags;
- return packageInfo;
- }
-
- private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid,
- UserHandle user) {
- final PackageInfo pkgInfo;
- if (hasSystemPermission) {
- pkgInfo = systemPackageInfoWithPermissions(
- CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
- } else {
- pkgInfo = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, new String[] {}, "");
- }
- pkgInfo.applicationInfo.uid = user.getUid(UserHandle.getAppId(uid));
- return pkgInfo;
- }
-
- @Test
- public void testHasPermission() {
- PackageInfo app = systemPackageInfoWithPermissions();
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
-
- app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE, NETWORK_STACK);
- assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
-
- app = systemPackageInfoWithPermissions(
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL);
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
- assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
-
- app = packageInfoWithPermissions(REQUESTED_PERMISSION_REQUIRED, new String[] {
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL, NETWORK_STACK },
- PARTITION_SYSTEM);
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
-
- app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
- app.requestedPermissions = null;
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
-
- app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
- app.requestedPermissionsFlags = null;
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- }
-
- @Test
- public void testIsVendorApp() {
- PackageInfo app = systemPackageInfoWithPermissions();
- assertFalse(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED,
- new String[] {}, PARTITION_OEM);
- assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED,
- new String[] {}, PARTITION_PRODUCT);
- assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = vendorPackageInfoWithPermissions();
- assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
- }
-
- @Test
- public void testHasNetworkPermission() {
- PackageInfo app = systemPackageInfoWithPermissions();
- assertFalse(mPermissionMonitor.hasNetworkPermission(app));
- app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
- assertTrue(mPermissionMonitor.hasNetworkPermission(app));
- app = systemPackageInfoWithPermissions(NETWORK_STACK);
- assertFalse(mPermissionMonitor.hasNetworkPermission(app));
- app = systemPackageInfoWithPermissions(CONNECTIVITY_USE_RESTRICTED_NETWORKS);
- assertFalse(mPermissionMonitor.hasNetworkPermission(app));
- app = systemPackageInfoWithPermissions(CONNECTIVITY_INTERNAL);
- assertFalse(mPermissionMonitor.hasNetworkPermission(app));
- }
-
- @Test
- public void testHasRestrictedNetworkPermission() {
- assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, NETWORK_STACK));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, MOCK_UID1, PERMISSION_MAINLINE_NETWORK_STACK));
-
- assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
- }
-
- @Test
- public void testHasRestrictedNetworkPermissionSystemUid() {
- doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt();
- assertTrue(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_INTERNAL));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
-
- doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
- assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_INTERNAL));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- }
-
- @Test
- public void testHasRestrictedNetworkPermissionVendorApp() {
- assertTrue(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, NETWORK_STACK));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
-
- assertFalse(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_NETWORK_STATE));
- }
-
- @Test
- public void testHasRestrictedNetworkPermissionAppAllowedOnRestrictedNetworks() {
- mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(
- new ArraySet<>(new String[] { MOCK_PACKAGE1 }));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1, CHANGE_NETWORK_STATE));
- assertTrue(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE1, MOCK_UID1, CONNECTIVITY_INTERNAL));
-
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID1));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID1, CHANGE_NETWORK_STATE));
- assertFalse(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_PACKAGE2, MOCK_UID1, CONNECTIVITY_INTERNAL));
-
- }
-
- private boolean wouldBeCarryoverPackage(String partition, int targetSdkVersion, int uid) {
- final PackageInfo packageInfo = packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, new String[] {}, partition);
- packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
- packageInfo.applicationInfo.uid = uid;
- return mPermissionMonitor.isCarryoverPackage(packageInfo.applicationInfo);
- }
-
- @Test
- public void testIsCarryoverPackage() {
- doReturn(VERSION_P).when(mDeps).getDeviceFirstSdkInt();
- assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
- assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
- assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
- assertTrue(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
- assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
- assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
-
- doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
- assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
- assertTrue(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
- assertFalse(wouldBeCarryoverPackage(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
-
- assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, SYSTEM_UID));
- assertFalse(wouldBeCarryoverPackage(PARTITION_OEM, VERSION_Q, MOCK_UID1));
- assertFalse(wouldBeCarryoverPackage(PARTITION_PRODUCT, VERSION_Q, MOCK_UID1));
- }
-
- private boolean wouldBeAppAllowedOnRestrictedNetworks(String packageName) {
- final PackageInfo packageInfo = new PackageInfo();
- packageInfo.packageName = packageName;
- return mPermissionMonitor.isAppAllowedOnRestrictedNetworks(packageInfo);
- }
-
- @Test
- public void testIsAppAllowedOnRestrictedNetworks() {
- mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(new ArraySet<>());
- assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1));
- assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2));
-
- mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(
- new ArraySet<>(new String[] { MOCK_PACKAGE1 }));
- assertTrue(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1));
- assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2));
-
- mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(
- new ArraySet<>(new String[] { MOCK_PACKAGE2 }));
- assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1));
- assertTrue(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2));
-
- mPermissionMonitor.updateAppsAllowedOnRestrictedNetworks(
- new ArraySet<>(new String[] { "com.android.test" }));
- assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE1));
- assertFalse(wouldBeAppAllowedOnRestrictedNetworks(MOCK_PACKAGE2));
- }
-
- private void assertBackgroundPermission(boolean hasPermission, String name, int uid,
- String... permissions) throws Exception {
- when(mPackageManager.getPackageInfo(eq(name), anyInt()))
- .thenReturn(packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM));
- mPermissionMonitor.onPackageAdded(name, uid);
- assertEquals(hasPermission, mPermissionMonitor.hasUseBackgroundNetworksPermission(uid));
- }
-
- @Test
- public void testHasUseBackgroundNetworksPermission() throws Exception {
- assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(SYSTEM_UID));
- assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID);
- assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID, CONNECTIVITY_INTERNAL);
- assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, CHANGE_NETWORK_STATE);
- assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, NETWORK_STACK);
-
- assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID1));
- assertBackgroundPermission(false, MOCK_PACKAGE1, MOCK_UID1);
- assertBackgroundPermission(true, MOCK_PACKAGE1, MOCK_UID1,
- CONNECTIVITY_USE_RESTRICTED_NETWORKS);
-
- assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID2));
- assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2);
- assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2,
- CONNECTIVITY_INTERNAL);
- assertBackgroundPermission(true, MOCK_PACKAGE2, MOCK_UID2, NETWORK_STACK);
- }
-
- private class NetdMonitor {
- private final HashMap<Integer, Boolean> mApps = new HashMap<>();
-
- NetdMonitor(INetd mockNetd) throws Exception {
- // Add hook to verify and track result of setPermission.
- doAnswer((InvocationOnMock invocation) -> {
- final Object[] args = invocation.getArguments();
- final Boolean isSystem = args[0].equals(INetd.PERMISSION_SYSTEM);
- for (final int uid : (int[]) args[1]) {
- // TODO: Currently, permission monitor will send duplicate commands for each uid
- // corresponding to each user. Need to fix that and uncomment below test.
- // if (mApps.containsKey(uid) && mApps.get(uid) == isSystem) {
- // fail("uid " + uid + " is already set to " + isSystem);
- // }
- mApps.put(uid, isSystem);
- }
- return null;
- }).when(mockNetd).networkSetPermissionForUser(anyInt(), any(int[].class));
-
- // Add hook to verify and track result of clearPermission.
- doAnswer((InvocationOnMock invocation) -> {
- final Object[] args = invocation.getArguments();
- for (final int uid : (int[]) args[0]) {
- // TODO: Currently, permission monitor will send duplicate commands for each uid
- // corresponding to each user. Need to fix that and uncomment below test.
- // if (!mApps.containsKey(uid)) {
- // fail("uid " + uid + " does not exist.");
- // }
- mApps.remove(uid);
- }
- return null;
- }).when(mockNetd).networkClearPermissionForUser(any(int[].class));
- }
-
- public void expectPermission(Boolean permission, UserHandle[] users, int[] apps) {
- for (final UserHandle user : users) {
- for (final int app : apps) {
- final int uid = user.getUid(app);
- if (!mApps.containsKey(uid)) {
- fail("uid " + uid + " does not exist.");
- }
- if (mApps.get(uid) != permission) {
- fail("uid " + uid + " has wrong permission: " + permission);
- }
- }
- }
- }
-
- public void expectNoPermission(UserHandle[] users, int[] apps) {
- for (final UserHandle user : users) {
- for (final int app : apps) {
- final int uid = user.getUid(app);
- if (mApps.containsKey(uid)) {
- fail("uid " + uid + " has listed permissions, expected none.");
- }
- }
- }
- }
- }
-
- @Test
- public void testUserAndPackageAddRemove() throws Exception {
- final NetdMonitor mNetdMonitor = new NetdMonitor(mNetdService);
-
- // MOCK_UID1: MOCK_PACKAGE1 only has network permission.
- // SYSTEM_UID: SYSTEM_PACKAGE1 has system permission.
- // SYSTEM_UID: SYSTEM_PACKAGE2 only has network permission.
- doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(eq(SYSTEM), anyString());
- doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(SYSTEM_PACKAGE1));
- doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(SYSTEM_PACKAGE2));
- doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(MOCK_PACKAGE1));
-
- // Add SYSTEM_PACKAGE2, expect only have network permission.
- mPermissionMonitor.onUserAdded(MOCK_USER1);
- addPackageForUsers(new UserHandle[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_UID);
- mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{SYSTEM_UID});
-
- // Add SYSTEM_PACKAGE1, expect permission escalate.
- addPackageForUsers(new UserHandle[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_UID);
- mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{SYSTEM_UID});
-
- mPermissionMonitor.onUserAdded(MOCK_USER2);
- mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
- new int[]{SYSTEM_UID});
-
- addPackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1, MOCK_USER2},
- new int[]{SYSTEM_UID});
- mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
- new int[]{MOCK_UID1});
-
- // Remove MOCK_UID1, expect no permission left for all user.
- mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- removePackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1, MOCK_USER2},
- new int[]{MOCK_UID1});
-
- // Remove SYSTEM_PACKAGE1, expect permission downgrade.
- when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{SYSTEM_PACKAGE2});
- removePackageForUsers(new UserHandle[]{MOCK_USER1, MOCK_USER2},
- SYSTEM_PACKAGE1, SYSTEM_UID);
- mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1, MOCK_USER2},
- new int[]{SYSTEM_UID});
-
- mPermissionMonitor.onUserRemoved(MOCK_USER1);
- mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER2}, new int[]{SYSTEM_UID});
-
- // Remove all packages, expect no permission left.
- when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{});
- removePackageForUsers(new UserHandle[]{MOCK_USER2}, SYSTEM_PACKAGE2, SYSTEM_UID);
- mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1, MOCK_USER2},
- new int[]{SYSTEM_UID, MOCK_UID1});
-
- // Remove last user, expect no redundant clearPermission is invoked.
- mPermissionMonitor.onUserRemoved(MOCK_USER2);
- mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1, MOCK_USER2},
- new int[]{SYSTEM_UID, MOCK_UID1});
- }
-
- @Test
- public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdates() throws Exception {
- when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
- Arrays.asList(new PackageInfo[] {
- buildPackageInfo(true /* hasSystemPermission */, SYSTEM_UID1, MOCK_USER1),
- buildPackageInfo(false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1),
- buildPackageInfo(false /* hasSystemPermission */, MOCK_UID2, MOCK_USER1),
- buildPackageInfo(false /* hasSystemPermission */, VPN_UID, MOCK_USER1)
- }));
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1),
- eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
- buildPackageInfo(false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1));
- mPermissionMonitor.startMonitoring();
- // Every app on user 0 except MOCK_UID2 are under VPN.
- final Set<UidRange> vpnRange1 = new HashSet<>(Arrays.asList(new UidRange[] {
- new UidRange(0, MOCK_UID2 - 1),
- new UidRange(MOCK_UID2 + 1, UserHandle.PER_USER_RANGE - 1)}));
- final Set<UidRange> vpnRange2 = Collections.singleton(new UidRange(MOCK_UID2, MOCK_UID2));
-
- // When VPN is connected, expect a rule to be set up for user app MOCK_UID1
- mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange1, VPN_UID);
- verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
- aryEq(new int[] {MOCK_UID1}));
-
- reset(mNetdService);
-
- // When MOCK_UID1 package is uninstalled and reinstalled, expect Netd to be updated
- mPermissionMonitor.onPackageRemoved(
- MOCK_PACKAGE1, MOCK_USER1.getUid(MOCK_UID1));
- verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
- mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, MOCK_USER1.getUid(MOCK_UID1));
- verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
- aryEq(new int[] {MOCK_UID1}));
-
- reset(mNetdService);
-
- // During VPN uid update (vpnRange1 -> vpnRange2), ConnectivityService first deletes the
- // old UID rules then adds the new ones. Expect netd to be updated
- mPermissionMonitor.onVpnUidRangesRemoved("tun0", vpnRange1, VPN_UID);
- verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
- mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange2, VPN_UID);
- verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
- aryEq(new int[] {MOCK_UID2}));
-
- reset(mNetdService);
-
- // When VPN is disconnected, expect rules to be torn down
- mPermissionMonitor.onVpnUidRangesRemoved("tun0", vpnRange2, VPN_UID);
- verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID2}));
- assertNull(mPermissionMonitor.getVpnUidRanges("tun0"));
- }
-
- @Test
- public void testUidFilteringDuringPackageInstallAndUninstall() throws Exception {
- when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
- Arrays.asList(new PackageInfo[] {
- buildPackageInfo(true /* hasSystemPermission */, SYSTEM_UID1, MOCK_USER1),
- buildPackageInfo(false /* hasSystemPermission */, VPN_UID, MOCK_USER1)
- }));
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1),
- eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
- buildPackageInfo(false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1));
-
- mPermissionMonitor.startMonitoring();
- final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(MOCK_USER1));
- mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange, VPN_UID);
-
- // Newly-installed package should have uid rules added
- mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, MOCK_USER1.getUid(MOCK_UID1));
- verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
- aryEq(new int[] {MOCK_UID1}));
-
- // Removed package should have its uid rules removed
- mPermissionMonitor.onPackageRemoved(
- MOCK_PACKAGE1, MOCK_USER1.getUid(MOCK_UID1));
- verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
- }
-
-
- // Normal package add/remove operations will trigger multiple intent for uids corresponding to
- // each user. To simulate generic package operations, the onPackageAdded/Removed will need to be
- // called multiple times with the uid corresponding to each user.
- private void addPackageForUsers(UserHandle[] users, String packageName, int uid) {
- for (final UserHandle user : users) {
- mPermissionMonitor.onPackageAdded(packageName, user.getUid(uid));
- }
- }
-
- private void removePackageForUsers(UserHandle[] users, String packageName, int uid) {
- for (final UserHandle user : users) {
- mPermissionMonitor.onPackageRemoved(packageName, user.getUid(uid));
- }
- }
-
- private class NetdServiceMonitor {
- private final HashMap<Integer, Integer> mPermissions = new HashMap<>();
-
- NetdServiceMonitor(INetd mockNetdService) throws Exception {
- // Add hook to verify and track result of setPermission.
- doAnswer((InvocationOnMock invocation) -> {
- final Object[] args = invocation.getArguments();
- final int permission = (int) args[0];
- for (final int uid : (int[]) args[1]) {
- mPermissions.put(uid, permission);
- }
- return null;
- }).when(mockNetdService).trafficSetNetPermForUids(anyInt(), any(int[].class));
- }
-
- public void expectPermission(int permission, int[] apps) {
- for (final int app : apps) {
- if (!mPermissions.containsKey(app)) {
- fail("uid " + app + " does not exist.");
- }
- if (mPermissions.get(app) != permission) {
- fail("uid " + app + " has wrong permission: " + mPermissions.get(app));
- }
- }
- }
- }
-
- @Test
- public void testPackagePermissionUpdate() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
- // MOCK_UID1: MOCK_PACKAGE1 only has internet permission.
- // MOCK_UID2: MOCK_PACKAGE2 does not have any permission.
- // SYSTEM_UID1: SYSTEM_PACKAGE1 has internet permission and update device stats permission.
- // SYSTEM_UID2: SYSTEM_PACKAGE2 has only update device stats permission.
-
- SparseIntArray netdPermissionsAppIds = new SparseIntArray();
- netdPermissionsAppIds.put(MOCK_UID1, INetd.PERMISSION_INTERNET);
- netdPermissionsAppIds.put(MOCK_UID2, INetd.PERMISSION_NONE);
- netdPermissionsAppIds.put(SYSTEM_UID1, INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS);
- netdPermissionsAppIds.put(SYSTEM_UID2, INetd.PERMISSION_UPDATE_DEVICE_STATS);
-
- // Send the permission information to netd, expect permission updated.
- mPermissionMonitor.sendPackagePermissionsToNetd(netdPermissionsAppIds);
-
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET,
- new int[]{MOCK_UID1});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID2});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UPDATE_DEVICE_STATS,
- new int[]{SYSTEM_UID2});
-
- // Update permission of MOCK_UID1, expect new permission show up.
- mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1,
- INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
-
- // Change permissions of SYSTEM_UID2, expect new permission show up and old permission
- // revoked.
- mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2,
- INetd.PERMISSION_INTERNET);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{SYSTEM_UID2});
-
- // Revoke permission from SYSTEM_UID1, expect no permission stored.
- mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, INetd.PERMISSION_NONE);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{SYSTEM_UID1});
- }
-
- private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions)
- throws Exception {
- PackageInfo packageInfo = packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM);
- when(mPackageManager.getPackageInfo(eq(packageName), anyInt())).thenReturn(packageInfo);
- when(mPackageManager.getPackagesForUid(eq(uid))).thenReturn(new String[]{packageName});
- return packageInfo;
- }
-
- private PackageInfo addPackage(String packageName, int uid, String[] permissions)
- throws Exception {
- PackageInfo packageInfo = setPackagePermissions(packageName, uid, permissions);
- mPermissionMonitor.onPackageAdded(packageName, uid);
- return packageInfo;
- }
-
- @Test
- public void testPackageInstall() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
-
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
-
- addPackage(MOCK_PACKAGE2, MOCK_UID2, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID2});
- }
-
- @Test
- public void testPackageInstallSharedUid() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
-
- PackageInfo packageInfo1 = addPackage(MOCK_PACKAGE1, MOCK_UID1,
- new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
-
- // Install another package with the same uid and no permissions should not cause the UID to
- // lose permissions.
- PackageInfo packageInfo2 = systemPackageInfoWithPermissions();
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
- when(mPackageManager.getPackagesForUid(MOCK_UID1))
- .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
- mPermissionMonitor.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
- }
-
- @Test
- public void testPackageUninstallBasic() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
-
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
-
- when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
- mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
- }
-
- @Test
- public void testPackageRemoveThenAdd() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
-
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
-
- when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
- mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
-
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
- }
-
- @Test
- public void testPackageUpdate() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
-
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID1});
-
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
- }
-
- @Test
- public void testPackageUninstallWithMultiplePackages() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
-
- addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
-
- // Mock another package with the same uid but different permissions.
- PackageInfo packageInfo2 = systemPackageInfoWithPermissions(INTERNET);
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
- when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{
- MOCK_PACKAGE2});
-
- mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
- }
-
- @Test
- public void testRealSystemPermission() throws Exception {
- // Use the real context as this test must ensure the *real* system package holds the
- // necessary permission.
- final Context realContext = InstrumentationRegistry.getContext();
- final PermissionMonitor monitor = new PermissionMonitor(realContext, mNetdService);
- final PackageManager manager = realContext.getPackageManager();
- final PackageInfo systemInfo = manager.getPackageInfo(REAL_SYSTEM_PACKAGE_NAME,
- GET_PERMISSIONS | MATCH_ANY_USER);
- assertTrue(monitor.hasPermission(systemInfo, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- }
-
- @Test
- public void testUpdateUidPermissionsFromSystemConfig() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
- when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(new ArrayList<>());
- when(mSystemConfigManager.getSystemPermissionUids(eq(INTERNET)))
- .thenReturn(new int[]{ MOCK_UID1, MOCK_UID2 });
- when(mSystemConfigManager.getSystemPermissionUids(eq(UPDATE_DEVICE_STATS)))
- .thenReturn(new int[]{ MOCK_UID2 });
-
- mPermissionMonitor.startMonitoring();
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{ MOCK_UID1 });
- mNetdServiceMonitor.expectPermission(
- INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
- new int[]{ MOCK_UID2 });
- }
-
- @Test
- public void testIntentReceiver() throws Exception {
- final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
- final ArgumentCaptor<BroadcastReceiver> receiverCaptor =
- ArgumentCaptor.forClass(BroadcastReceiver.class);
- verify(mContext, times(1)).registerReceiver(receiverCaptor.capture(), any(), any(), any());
- final BroadcastReceiver receiver = receiverCaptor.getValue();
-
- // Verify receiving PACKAGE_ADDED intent.
- final Intent addedIntent = new Intent(Intent.ACTION_PACKAGE_ADDED,
- Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
- addedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
- setPackagePermissions(MOCK_PACKAGE1, MOCK_UID1,
- new String[] { INTERNET, UPDATE_DEVICE_STATS });
- receiver.onReceive(mContext, addedIntent);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
- | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[] { MOCK_UID1 });
-
- // Verify receiving PACKAGE_REMOVED intent.
- when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(null);
- final Intent removedIntent = new Intent(Intent.ACTION_PACKAGE_REMOVED,
- Uri.fromParts("package", MOCK_PACKAGE1, null /* fragment */));
- removedIntent.putExtra(Intent.EXTRA_UID, MOCK_UID1);
- receiver.onReceive(mContext, removedIntent);
- mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[] { MOCK_UID1 });
- }
-
- @Test
- public void testAppsAllowedOnRestrictedNetworksChanged() throws Exception {
- final NetdMonitor mNetdMonitor = new NetdMonitor(mNetdService);
- final ArgumentCaptor<ContentObserver> captor =
- ArgumentCaptor.forClass(ContentObserver.class);
- verify(mDeps, times(1)).registerContentObserver(any(),
- argThat(uri -> uri.getEncodedPath().contains(APPS_ALLOWED_ON_RESTRICTED_NETWORKS)),
- anyBoolean(), captor.capture());
- final ContentObserver contentObserver = captor.getValue();
-
- mPermissionMonitor.onUserAdded(MOCK_USER1);
- // Prepare PackageInfo for MOCK_PACKAGE1
- final PackageInfo packageInfo = buildPackageInfo(
- false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1);
- packageInfo.packageName = MOCK_PACKAGE1;
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), anyInt())).thenReturn(packageInfo);
- when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{MOCK_PACKAGE1});
- // Prepare PackageInfo for MOCK_PACKAGE2
- final PackageInfo packageInfo2 = buildPackageInfo(
- false /* hasSystemPermission */, MOCK_UID2, MOCK_USER1);
- packageInfo2.packageName = MOCK_PACKAGE2;
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
- when(mPackageManager.getPackagesForUid(MOCK_UID2)).thenReturn(new String[]{MOCK_PACKAGE2});
-
- // MOCK_PACKAGE1 is listed in setting that allow to use restricted networks, MOCK_UID1
- // should have SYSTEM permission.
- when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(
- new ArraySet<>(new String[] { MOCK_PACKAGE1 }));
- contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
- mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID2});
-
- // MOCK_PACKAGE2 is listed in setting that allow to use restricted networks, MOCK_UID2
- // should have SYSTEM permission but MOCK_UID1 should revoke permission.
- when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(
- new ArraySet<>(new String[] { MOCK_PACKAGE2 }));
- contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID2});
- mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
-
- // No app lists in setting, should revoke permission from all uids.
- when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
- contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectNoPermission(
- new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1, MOCK_UID2});
- }
-
- @Test
- public void testAppsAllowedOnRestrictedNetworksChangedWithSharedUid() throws Exception {
- final NetdMonitor mNetdMonitor = new NetdMonitor(mNetdService);
- final ArgumentCaptor<ContentObserver> captor =
- ArgumentCaptor.forClass(ContentObserver.class);
- verify(mDeps, times(1)).registerContentObserver(any(),
- argThat(uri -> uri.getEncodedPath().contains(APPS_ALLOWED_ON_RESTRICTED_NETWORKS)),
- anyBoolean(), captor.capture());
- final ContentObserver contentObserver = captor.getValue();
-
- mPermissionMonitor.onUserAdded(MOCK_USER1);
- // Prepare PackageInfo for MOCK_PACKAGE1 and MOCK_PACKAGE2 with shared uid MOCK_UID1.
- final PackageInfo packageInfo = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
- packageInfo.applicationInfo.uid = MOCK_USER1.getUid(MOCK_UID1);
- packageInfo.packageName = MOCK_PACKAGE1;
- final PackageInfo packageInfo2 = buildPackageInfo(
- false /* hasSystemPermission */, MOCK_UID1, MOCK_USER1);
- packageInfo2.packageName = MOCK_PACKAGE2;
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), anyInt())).thenReturn(packageInfo);
- when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
- when(mPackageManager.getPackagesForUid(MOCK_UID1))
- .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
-
- // MOCK_PACKAGE1 have CHANGE_NETWORK_STATE, MOCK_UID1 should have NETWORK permission.
- addPackageForUsers(new UserHandle[]{MOCK_USER1}, MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
-
- // MOCK_PACKAGE2 is listed in setting that allow to use restricted networks, MOCK_UID1
- // should upgrade to SYSTEM permission.
- when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(
- new ArraySet<>(new String[] { MOCK_PACKAGE2 }));
- contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
-
- // MOCK_PACKAGE1 is listed in setting that allow to use restricted networks, MOCK_UID1
- // should still have SYSTEM permission.
- when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(
- new ArraySet<>(new String[] { MOCK_PACKAGE1 }));
- contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectPermission(SYSTEM, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
-
- // No app lists in setting, MOCK_UID1 should downgrade to NETWORK permission.
- when(mDeps.getAppsAllowedOnRestrictedNetworks(any())).thenReturn(new ArraySet<>());
- contentObserver.onChange(true /* selfChange */);
- mNetdMonitor.expectPermission(NETWORK, new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
-
- // MOCK_PACKAGE1 removed, should revoke permission from MOCK_UID1.
- when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{MOCK_PACKAGE2});
- removePackageForUsers(new UserHandle[]{MOCK_USER1}, MOCK_PACKAGE1, MOCK_UID1);
- mNetdMonitor.expectNoPermission(new UserHandle[]{MOCK_USER1}, new int[]{MOCK_UID1});
- }
-}
\ No newline at end of file
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/VpnTest.java b/packages/Connectivity/tests/unit/java/com/android/server/connectivity/VpnTest.java
deleted file mode 100644
index b725b82..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ /dev/null
@@ -1,1283 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.connectivity;
-
-import static android.content.pm.UserInfo.FLAG_ADMIN;
-import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
-import static android.content.pm.UserInfo.FLAG_PRIMARY;
-import static android.content.pm.UserInfo.FLAG_RESTRICTED;
-import static android.net.ConnectivityManager.NetworkCallback;
-import static android.net.INetd.IF_STATE_DOWN;
-import static android.net.INetd.IF_STATE_UP;
-import static android.os.UserHandle.PER_USER_RANGE;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.annotation.UserIdInt;
-import android.app.AppOpsManager;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.INetd;
-import android.net.Ikev2VpnProfile;
-import android.net.InetAddresses;
-import android.net.InterfaceConfigurationParcel;
-import android.net.IpPrefix;
-import android.net.IpSecManager;
-import android.net.IpSecTunnelInterfaceResponse;
-import android.net.LinkProperties;
-import android.net.LocalSocket;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo.DetailedState;
-import android.net.RouteInfo;
-import android.net.UidRangeParcel;
-import android.net.VpnManager;
-import android.net.VpnService;
-import android.net.VpnTransportInfo;
-import android.net.ipsec.ike.IkeSessionCallback;
-import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import android.os.Build.VERSION_CODES;
-import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.INetworkManagementService;
-import android.os.Process;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.os.test.TestLooper;
-import android.provider.Settings;
-import android.security.Credentials;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Range;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.R;
-import com.android.internal.net.LegacyVpnInfo;
-import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnProfile;
-import com.android.server.IpSecService;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.AdditionalAnswers;
-import org.mockito.Answers;
-import org.mockito.ArgumentCaptor;
-import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Stream;
-
-/**
- * Tests for {@link Vpn}.
- *
- * Build, install and run with:
- * runtest frameworks-net -c com.android.server.connectivity.VpnTest
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class VpnTest {
- private static final String TAG = "VpnTest";
-
- // Mock users
- static final UserInfo primaryUser = new UserInfo(27, "Primary", FLAG_ADMIN | FLAG_PRIMARY);
- static final UserInfo secondaryUser = new UserInfo(15, "Secondary", FLAG_ADMIN);
- static final UserInfo restrictedProfileA = new UserInfo(40, "RestrictedA", FLAG_RESTRICTED);
- static final UserInfo restrictedProfileB = new UserInfo(42, "RestrictedB", FLAG_RESTRICTED);
- static final UserInfo managedProfileA = new UserInfo(45, "ManagedA", FLAG_MANAGED_PROFILE);
- static {
- restrictedProfileA.restrictedProfileParentId = primaryUser.id;
- restrictedProfileB.restrictedProfileParentId = secondaryUser.id;
- managedProfileA.profileGroupId = primaryUser.id;
- }
-
- static final Network EGRESS_NETWORK = new Network(101);
- static final String EGRESS_IFACE = "wlan0";
- static final String TEST_VPN_PKG = "com.testvpn.vpn";
- private static final String TEST_VPN_SERVER = "1.2.3.4";
- private static final String TEST_VPN_IDENTITY = "identity";
- private static final byte[] TEST_VPN_PSK = "psk".getBytes();
-
- private static final Network TEST_NETWORK = new Network(Integer.MAX_VALUE);
- private static final String TEST_IFACE_NAME = "TEST_IFACE";
- private static final int TEST_TUNNEL_RESOURCE_ID = 0x2345;
- private static final long TEST_TIMEOUT_MS = 500L;
-
- /**
- * Names and UIDs for some fake packages. Important points:
- * - UID is ordered increasing.
- * - One pair of packages have consecutive UIDs.
- */
- static final String[] PKGS = {"com.example", "org.example", "net.example", "web.vpn"};
- static final int[] PKG_UIDS = {66, 77, 78, 400};
-
- // Mock packages
- static final Map<String, Integer> mPackages = new ArrayMap<>();
- static {
- for (int i = 0; i < PKGS.length; i++) {
- mPackages.put(PKGS[i], PKG_UIDS[i]);
- }
- }
- private static final Range<Integer> PRI_USER_RANGE = uidRangeForUser(primaryUser.id);
-
- @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
- @Mock private UserManager mUserManager;
- @Mock private PackageManager mPackageManager;
- @Mock private INetworkManagementService mNetService;
- @Mock private INetd mNetd;
- @Mock private AppOpsManager mAppOps;
- @Mock private NotificationManager mNotificationManager;
- @Mock private Vpn.SystemServices mSystemServices;
- @Mock private Vpn.Ikev2SessionCreator mIkev2SessionCreator;
- @Mock private ConnectivityManager mConnectivityManager;
- @Mock private IpSecService mIpSecService;
- @Mock private VpnProfileStore mVpnProfileStore;
- private final VpnProfile mVpnProfile;
-
- private IpSecManager mIpSecManager;
-
- public VpnTest() throws Exception {
- // Build an actual VPN profile that is capable of being converted to and from an
- // Ikev2VpnProfile
- final Ikev2VpnProfile.Builder builder =
- new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY);
- builder.setAuthPsk(TEST_VPN_PSK);
- mVpnProfile = builder.build().toVpnProfile();
- }
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- mIpSecManager = new IpSecManager(mContext, mIpSecService);
-
- when(mContext.getPackageManager()).thenReturn(mPackageManager);
- setMockedPackages(mPackages);
-
- when(mContext.getPackageName()).thenReturn(TEST_VPN_PKG);
- when(mContext.getOpPackageName()).thenReturn(TEST_VPN_PKG);
- when(mContext.getSystemServiceName(UserManager.class))
- .thenReturn(Context.USER_SERVICE);
- when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
- when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
- when(mContext.getSystemServiceName(NotificationManager.class))
- .thenReturn(Context.NOTIFICATION_SERVICE);
- when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
- .thenReturn(mNotificationManager);
- when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
- .thenReturn(mConnectivityManager);
- when(mContext.getSystemServiceName(eq(ConnectivityManager.class)))
- .thenReturn(Context.CONNECTIVITY_SERVICE);
- when(mContext.getSystemService(eq(Context.IPSEC_SERVICE))).thenReturn(mIpSecManager);
- when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
- .thenReturn(Resources.getSystem().getString(
- R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS))
- .thenReturn(true);
-
- // Used by {@link Notification.Builder}
- ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
- when(mContext.getApplicationInfo()).thenReturn(applicationInfo);
- when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
- .thenReturn(applicationInfo);
-
- doNothing().when(mNetService).registerObserver(any());
-
- // Deny all appops by default.
- when(mAppOps.noteOpNoThrow(anyString(), anyInt(), anyString(), any(), any()))
- .thenReturn(AppOpsManager.MODE_IGNORED);
-
- // Setup IpSecService
- final IpSecTunnelInterfaceResponse tunnelResp =
- new IpSecTunnelInterfaceResponse(
- IpSecManager.Status.OK, TEST_TUNNEL_RESOURCE_ID, TEST_IFACE_NAME);
- when(mIpSecService.createTunnelInterface(any(), any(), any(), any(), any()))
- .thenReturn(tunnelResp);
- }
-
- private Set<Range<Integer>> rangeSet(Range<Integer> ... ranges) {
- final Set<Range<Integer>> range = new ArraySet<>();
- for (Range<Integer> r : ranges) range.add(r);
-
- return range;
- }
-
- private static Range<Integer> uidRangeForUser(int userId) {
- return new Range<Integer>(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1);
- }
-
- private Range<Integer> uidRange(int start, int stop) {
- return new Range<Integer>(start, stop);
- }
-
- @Test
- public void testRestrictedProfilesAreAddedToVpn() {
- setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
-
- final Vpn vpn = createVpn(primaryUser.id);
-
- // Assume the user can have restricted profiles.
- doReturn(true).when(mUserManager).canHaveRestrictedProfile();
- final Set<Range<Integer>> ranges =
- vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null);
-
- assertEquals(rangeSet(PRI_USER_RANGE, uidRangeForUser(restrictedProfileA.id)), ranges);
- }
-
- @Test
- public void testManagedProfilesAreNotAddedToVpn() {
- setMockedUsers(primaryUser, managedProfileA);
-
- final Vpn vpn = createVpn(primaryUser.id);
- final Set<Range<Integer>> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
- null, null);
-
- assertEquals(rangeSet(PRI_USER_RANGE), ranges);
- }
-
- @Test
- public void testAddUserToVpnOnlyAddsOneUser() {
- setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
-
- final Vpn vpn = createVpn(primaryUser.id);
- final Set<Range<Integer>> ranges = new ArraySet<>();
- vpn.addUserToRanges(ranges, primaryUser.id, null, null);
-
- assertEquals(rangeSet(PRI_USER_RANGE), ranges);
- }
-
- @Test
- public void testUidAllowAndDenylist() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
- final Range<Integer> user = PRI_USER_RANGE;
- final int userStart = user.getLower();
- final int userStop = user.getUpper();
- final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
-
- // Allowed list
- final Set<Range<Integer>> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
- Arrays.asList(packages), null /* disallowedApplications */);
- assertEquals(rangeSet(
- uidRange(userStart + PKG_UIDS[0], userStart + PKG_UIDS[0]),
- uidRange(userStart + PKG_UIDS[1], userStart + PKG_UIDS[2])),
- allow);
-
- // Denied list
- final Set<Range<Integer>> disallow =
- vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
- null /* allowedApplications */, Arrays.asList(packages));
- assertEquals(rangeSet(
- uidRange(userStart, userStart + PKG_UIDS[0] - 1),
- uidRange(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
- /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
- uidRange(userStart + PKG_UIDS[2] + 1, userStop)),
- disallow);
- }
-
- @Test
- public void testGetAlwaysAndOnGetLockDown() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
-
- // Default state.
- assertFalse(vpn.getAlwaysOn());
- assertFalse(vpn.getLockdown());
-
- // Set always-on without lockdown.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList()));
- assertTrue(vpn.getAlwaysOn());
- assertFalse(vpn.getLockdown());
-
- // Set always-on with lockdown.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList()));
- assertTrue(vpn.getAlwaysOn());
- assertTrue(vpn.getLockdown());
-
- // Remove always-on configuration.
- assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList()));
- assertFalse(vpn.getAlwaysOn());
- assertFalse(vpn.getLockdown());
- }
-
- @Test
- public void testLockdownChangingPackage() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
- final Range<Integer> user = PRI_USER_RANGE;
- final int userStart = user.getLower();
- final int userStop = user.getUpper();
- // Set always-on without lockdown.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null));
-
- // Set always-on with lockdown.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null));
- verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
- new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
- }));
-
- // Switch to another app.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
- verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
- new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
- }));
- verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(userStart, userStart + PKG_UIDS[3] - 1),
- new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
- }));
- }
-
- @Test
- public void testLockdownAllowlist() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
- final Range<Integer> user = PRI_USER_RANGE;
- final int userStart = user.getLower();
- final int userStop = user.getUpper();
- // Set always-on with lockdown and allow app PKGS[2] from lockdown.
- assertTrue(vpn.setAlwaysOnPackage(
- PKGS[1], true, Collections.singletonList(PKGS[2])));
- verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
- new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
- }));
- // Change allowed app list to PKGS[3].
- assertTrue(vpn.setAlwaysOnPackage(
- PKGS[1], true, Collections.singletonList(PKGS[3])));
- verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
- }));
- verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1),
- new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
- }));
-
- // Change the VPN app.
- assertTrue(vpn.setAlwaysOnPackage(
- PKGS[0], true, Collections.singletonList(PKGS[3])));
- verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
- new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1)
- }));
- verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(userStart, userStart + PKG_UIDS[0] - 1),
- new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1)
- }));
-
- // Remove the list of allowed packages.
- assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null));
- verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1),
- new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
- }));
- verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStop),
- }));
-
- // Add the list of allowed packages.
- assertTrue(vpn.setAlwaysOnPackage(
- PKGS[0], true, Collections.singletonList(PKGS[1])));
- verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStop)
- }));
- verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
- new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
- }));
-
- // Try allowing a package with a comma, should be rejected.
- assertFalse(vpn.setAlwaysOnPackage(
- PKGS[0], true, Collections.singletonList("a.b,c.d")));
-
- // Pass a non-existent packages in the allowlist, they (and only they) should be ignored.
- // allowed package should change from PGKS[1] to PKGS[2].
- assertTrue(vpn.setAlwaysOnPackage(
- PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app")));
- verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
- new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
- }));
- verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
- new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[2] - 1),
- new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
- }));
- }
-
- @Test
- public void testLockdownRuleRepeatability() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
- final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] {
- new UidRangeParcel(PRI_USER_RANGE.getLower(), PRI_USER_RANGE.getUpper())};
- // Given legacy lockdown is already enabled,
- vpn.setLockdown(true);
- verify(mConnectivityManager, times(1)).setRequireVpnForUids(true,
- toRanges(primaryUserRangeParcel));
-
- // Enabling legacy lockdown twice should do nothing.
- vpn.setLockdown(true);
- verify(mConnectivityManager, times(1)).setRequireVpnForUids(anyBoolean(), any());
-
- // And disabling should remove the rules exactly once.
- vpn.setLockdown(false);
- verify(mConnectivityManager, times(1)).setRequireVpnForUids(false,
- toRanges(primaryUserRangeParcel));
-
- // Removing the lockdown again should have no effect.
- vpn.setLockdown(false);
- verify(mConnectivityManager, times(2)).setRequireVpnForUids(anyBoolean(), any());
- }
-
- private ArrayList<Range<Integer>> toRanges(UidRangeParcel[] ranges) {
- ArrayList<Range<Integer>> rangesArray = new ArrayList<>(ranges.length);
- for (int i = 0; i < ranges.length; i++) {
- rangesArray.add(new Range<>(ranges[i].start, ranges[i].stop));
- }
- return rangesArray;
- }
-
- @Test
- public void testLockdownRuleReversibility() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
- final UidRangeParcel[] entireUser = {
- new UidRangeParcel(PRI_USER_RANGE.getLower(), PRI_USER_RANGE.getUpper())
- };
- final UidRangeParcel[] exceptPkg0 = {
- new UidRangeParcel(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
- new UidRangeParcel(entireUser[0].start + PKG_UIDS[0] + 1, entireUser[0].stop)
- };
-
- final InOrder order = inOrder(mConnectivityManager);
-
- // Given lockdown is enabled with no package (legacy VPN),
- vpn.setLockdown(true);
- order.verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(entireUser));
-
- // When a new VPN package is set the rules should change to cover that package.
- vpn.prepare(null, PKGS[0], VpnManager.TYPE_VPN_SERVICE);
- order.verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(entireUser));
- order.verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(exceptPkg0));
-
- // When that VPN package is unset, everything should be undone again in reverse.
- vpn.prepare(null, VpnConfig.LEGACY_VPN, VpnManager.TYPE_VPN_SERVICE);
- order.verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(exceptPkg0));
- order.verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(entireUser));
- }
-
- @Test
- public void testIsAlwaysOnPackageSupported() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
-
- ApplicationInfo appInfo = new ApplicationInfo();
- when(mPackageManager.getApplicationInfoAsUser(eq(PKGS[0]), anyInt(), eq(primaryUser.id)))
- .thenReturn(appInfo);
-
- ServiceInfo svcInfo = new ServiceInfo();
- ResolveInfo resInfo = new ResolveInfo();
- resInfo.serviceInfo = svcInfo;
- when(mPackageManager.queryIntentServicesAsUser(any(), eq(PackageManager.GET_META_DATA),
- eq(primaryUser.id)))
- .thenReturn(Collections.singletonList(resInfo));
-
- // null package name should return false
- assertFalse(vpn.isAlwaysOnPackageSupported(null));
-
- // Pre-N apps are not supported
- appInfo.targetSdkVersion = VERSION_CODES.M;
- assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
-
- // N+ apps are supported by default
- appInfo.targetSdkVersion = VERSION_CODES.N;
- assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0]));
-
- // Apps that opt out explicitly are not supported
- appInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
- Bundle metaData = new Bundle();
- metaData.putBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, false);
- svcInfo.metaData = metaData;
- assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
- }
-
- @Test
- public void testNotificationShownForAlwaysOnApp() throws Exception {
- final UserHandle userHandle = UserHandle.of(primaryUser.id);
- final Vpn vpn = createVpn(primaryUser.id);
- setMockedUsers(primaryUser);
-
- final InOrder order = inOrder(mNotificationManager);
-
- // Don't show a notification for regular disconnected states.
- vpn.updateState(DetailedState.DISCONNECTED, TAG);
- order.verify(mNotificationManager, atLeastOnce()).cancel(anyString(), anyInt());
-
- // Start showing a notification for disconnected once always-on.
- vpn.setAlwaysOnPackage(PKGS[0], false, null);
- order.verify(mNotificationManager).notify(anyString(), anyInt(), any());
-
- // Stop showing the notification once connected.
- vpn.updateState(DetailedState.CONNECTED, TAG);
- order.verify(mNotificationManager).cancel(anyString(), anyInt());
-
- // Show the notification if we disconnect again.
- vpn.updateState(DetailedState.DISCONNECTED, TAG);
- order.verify(mNotificationManager).notify(anyString(), anyInt(), any());
-
- // Notification should be cleared after unsetting always-on package.
- vpn.setAlwaysOnPackage(null, false, null);
- order.verify(mNotificationManager).cancel(anyString(), anyInt());
- }
-
- /**
- * The profile name should NOT change between releases for backwards compatibility
- *
- * <p>If this is changed between releases, the {@link Vpn#getVpnProfilePrivileged()} method MUST
- * be updated to ensure backward compatibility.
- */
- @Test
- public void testGetProfileNameForPackage() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
- setMockedUsers(primaryUser);
-
- final String expected = Credentials.PLATFORM_VPN + primaryUser.id + "_" + TEST_VPN_PKG;
- assertEquals(expected, vpn.getProfileNameForPackage(TEST_VPN_PKG));
- }
-
- private Vpn createVpnAndSetupUidChecks(String... grantedOps) throws Exception {
- return createVpnAndSetupUidChecks(primaryUser, grantedOps);
- }
-
- private Vpn createVpnAndSetupUidChecks(UserInfo user, String... grantedOps) throws Exception {
- final Vpn vpn = createVpn(user.id);
- setMockedUsers(user);
-
- when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt()))
- .thenReturn(Process.myUid());
-
- for (final String opStr : grantedOps) {
- when(mAppOps.noteOpNoThrow(opStr, Process.myUid(), TEST_VPN_PKG,
- null /* attributionTag */, null /* message */))
- .thenReturn(AppOpsManager.MODE_ALLOWED);
- }
-
- return vpn;
- }
-
- private void checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, String... checkedOps) {
- assertEquals(expectedResult, vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile));
-
- // The profile should always be stored, whether or not consent has been previously granted.
- verify(mVpnProfileStore)
- .put(
- eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)),
- eq(mVpnProfile.encode()));
-
- for (final String checkedOpStr : checkedOps) {
- verify(mAppOps).noteOpNoThrow(checkedOpStr, Process.myUid(), TEST_VPN_PKG,
- null /* attributionTag */, null /* message */);
- }
- }
-
- @Test
- public void testProvisionVpnProfileNoIpsecTunnels() throws Exception {
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS))
- .thenReturn(false);
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
-
- try {
- checkProvisionVpnProfile(
- vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
- fail("Expected exception due to missing feature");
- } catch (UnsupportedOperationException expected) {
- }
- }
-
- @Test
- public void testProvisionVpnProfilePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
-
- checkProvisionVpnProfile(
- vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
- }
-
- @Test
- public void testProvisionVpnProfileNotPreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
-
- // Expect that both the ACTIVATE_VPN and ACTIVATE_PLATFORM_VPN were tried, but the caller
- // had neither.
- checkProvisionVpnProfile(vpn, false /* expectedResult */,
- AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN, AppOpsManager.OPSTR_ACTIVATE_VPN);
- }
-
- @Test
- public void testProvisionVpnProfileVpnServicePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN);
-
- checkProvisionVpnProfile(vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_VPN);
- }
-
- @Test
- public void testProvisionVpnProfileTooLarge() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
-
- final VpnProfile bigProfile = new VpnProfile("");
- bigProfile.name = new String(new byte[Vpn.MAX_VPN_PROFILE_SIZE_BYTES + 1]);
-
- try {
- vpn.provisionVpnProfile(TEST_VPN_PKG, bigProfile);
- fail("Expected IAE due to profile size");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testProvisionVpnProfileRestrictedUser() throws Exception {
- final Vpn vpn =
- createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
-
- try {
- vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile);
- fail("Expected SecurityException due to restricted user");
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void testDeleteVpnProfile() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
-
- vpn.deleteVpnProfile(TEST_VPN_PKG);
-
- verify(mVpnProfileStore)
- .remove(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
- }
-
- @Test
- public void testDeleteVpnProfileRestrictedUser() throws Exception {
- final Vpn vpn =
- createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
-
- try {
- vpn.deleteVpnProfile(TEST_VPN_PKG);
- fail("Expected SecurityException due to restricted user");
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void testGetVpnProfilePrivileged() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
-
- when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
- .thenReturn(new VpnProfile("").encode());
-
- vpn.getVpnProfilePrivileged(TEST_VPN_PKG);
-
- verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
- }
-
- @Test
- public void testStartVpnProfile() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
-
- when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
- .thenReturn(mVpnProfile.encode());
-
- vpn.startVpnProfile(TEST_VPN_PKG);
-
- verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
- verify(mAppOps)
- .noteOpNoThrow(
- eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
- eq(Process.myUid()),
- eq(TEST_VPN_PKG),
- eq(null) /* attributionTag */,
- eq(null) /* message */);
- }
-
- @Test
- public void testStartVpnProfileVpnServicePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN);
-
- when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
- .thenReturn(mVpnProfile.encode());
-
- vpn.startVpnProfile(TEST_VPN_PKG);
-
- // Verify that the the ACTIVATE_VPN appop was checked, but no error was thrown.
- verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(),
- TEST_VPN_PKG, null /* attributionTag */, null /* message */);
- }
-
- @Test
- public void testStartVpnProfileNotConsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
-
- try {
- vpn.startVpnProfile(TEST_VPN_PKG);
- fail("Expected failure due to no user consent");
- } catch (SecurityException expected) {
- }
-
- // Verify both appops were checked.
- verify(mAppOps)
- .noteOpNoThrow(
- eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
- eq(Process.myUid()),
- eq(TEST_VPN_PKG),
- eq(null) /* attributionTag */,
- eq(null) /* message */);
- verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(),
- TEST_VPN_PKG, null /* attributionTag */, null /* message */);
-
- // Keystore should never have been accessed.
- verify(mVpnProfileStore, never()).get(any());
- }
-
- @Test
- public void testStartVpnProfileMissingProfile() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
-
- when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null);
-
- try {
- vpn.startVpnProfile(TEST_VPN_PKG);
- fail("Expected failure due to missing profile");
- } catch (IllegalArgumentException expected) {
- }
-
- verify(mVpnProfileStore).get(vpn.getProfileNameForPackage(TEST_VPN_PKG));
- verify(mAppOps)
- .noteOpNoThrow(
- eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
- eq(Process.myUid()),
- eq(TEST_VPN_PKG),
- eq(null) /* attributionTag */,
- eq(null) /* message */);
- }
-
- @Test
- public void testStartVpnProfileRestrictedUser() throws Exception {
- final Vpn vpn =
- createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
-
- try {
- vpn.startVpnProfile(TEST_VPN_PKG);
- fail("Expected SecurityException due to restricted user");
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void testStopVpnProfileRestrictedUser() throws Exception {
- final Vpn vpn =
- createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
-
- try {
- vpn.stopVpnProfile(TEST_VPN_PKG);
- fail("Expected SecurityException due to restricted user");
- } catch (SecurityException expected) {
- }
- }
-
- @Test
- public void testSetPackageAuthorizationVpnService() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
-
- assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_SERVICE));
- verify(mAppOps)
- .setMode(
- eq(AppOpsManager.OPSTR_ACTIVATE_VPN),
- eq(Process.myUid()),
- eq(TEST_VPN_PKG),
- eq(AppOpsManager.MODE_ALLOWED));
- }
-
- @Test
- public void testSetPackageAuthorizationPlatformVpn() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
-
- assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_PLATFORM));
- verify(mAppOps)
- .setMode(
- eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
- eq(Process.myUid()),
- eq(TEST_VPN_PKG),
- eq(AppOpsManager.MODE_ALLOWED));
- }
-
- @Test
- public void testSetPackageAuthorizationRevokeAuthorization() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
-
- assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_NONE));
- verify(mAppOps)
- .setMode(
- eq(AppOpsManager.OPSTR_ACTIVATE_VPN),
- eq(Process.myUid()),
- eq(TEST_VPN_PKG),
- eq(AppOpsManager.MODE_IGNORED));
- verify(mAppOps)
- .setMode(
- eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
- eq(Process.myUid()),
- eq(TEST_VPN_PKG),
- eq(AppOpsManager.MODE_IGNORED));
- }
-
- private NetworkCallback triggerOnAvailableAndGetCallback() throws Exception {
- final ArgumentCaptor<NetworkCallback> networkCallbackCaptor =
- ArgumentCaptor.forClass(NetworkCallback.class);
- verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS))
- .requestNetwork(any(), networkCallbackCaptor.capture());
-
- // onAvailable() will trigger onDefaultNetworkChanged(), so NetdUtils#setInterfaceUp will be
- // invoked. Set the return value of INetd#interfaceGetCfg to prevent NullPointerException.
- final InterfaceConfigurationParcel config = new InterfaceConfigurationParcel();
- config.flags = new String[] {IF_STATE_DOWN};
- when(mNetd.interfaceGetCfg(anyString())).thenReturn(config);
- final NetworkCallback cb = networkCallbackCaptor.getValue();
- cb.onAvailable(TEST_NETWORK);
- return cb;
- }
-
- private void verifyInterfaceSetCfgWithFlags(String flag) throws Exception {
- // Add a timeout for waiting for interfaceSetCfg to be called.
- verify(mNetd, timeout(TEST_TIMEOUT_MS)).interfaceSetCfg(argThat(
- config -> Arrays.asList(config.flags).contains(flag)));
- }
-
- @Test
- public void testStartPlatformVpnAuthenticationFailed() throws Exception {
- final ArgumentCaptor<IkeSessionCallback> captor =
- ArgumentCaptor.forClass(IkeSessionCallback.class);
- final IkeProtocolException exception = mock(IkeProtocolException.class);
- when(exception.getErrorType())
- .thenReturn(IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED);
-
- final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), (mVpnProfile));
- final NetworkCallback cb = triggerOnAvailableAndGetCallback();
-
- verifyInterfaceSetCfgWithFlags(IF_STATE_UP);
-
- // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
- // state
- verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS))
- .createIkeSession(any(), any(), any(), any(), captor.capture(), any());
- final IkeSessionCallback ikeCb = captor.getValue();
- ikeCb.onClosedExceptionally(exception);
-
- verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
- assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
- }
-
- @Test
- public void testStartPlatformVpnIllegalArgumentExceptionInSetup() throws Exception {
- when(mIkev2SessionCreator.createIkeSession(any(), any(), any(), any(), any(), any()))
- .thenThrow(new IllegalArgumentException());
- final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
- final NetworkCallback cb = triggerOnAvailableAndGetCallback();
-
- verifyInterfaceSetCfgWithFlags(IF_STATE_UP);
-
- // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
- // state
- verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
- assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
- }
-
- private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) {
- assertTrue(vpn.setAlwaysOnPackage(TEST_VPN_PKG, lockdownEnabled, null));
-
- verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
- verify(mAppOps).setMode(
- eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), eq(uid), eq(TEST_VPN_PKG),
- eq(AppOpsManager.MODE_ALLOWED));
-
- verify(mSystemServices).settingsSecurePutStringForUser(
- eq(Settings.Secure.ALWAYS_ON_VPN_APP), eq(TEST_VPN_PKG), eq(primaryUser.id));
- verify(mSystemServices).settingsSecurePutIntForUser(
- eq(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN), eq(lockdownEnabled ? 1 : 0),
- eq(primaryUser.id));
- verify(mSystemServices).settingsSecurePutStringForUser(
- eq(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST), eq(""), eq(primaryUser.id));
- }
-
- @Test
- public void testSetAndStartAlwaysOnVpn() throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
- setMockedUsers(primaryUser);
-
- // UID checks must return a different UID; otherwise it'll be treated as already prepared.
- final int uid = Process.myUid() + 1;
- when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt()))
- .thenReturn(uid);
- when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
- .thenReturn(mVpnProfile.encode());
-
- setAndVerifyAlwaysOnPackage(vpn, uid, false);
- assertTrue(vpn.startAlwaysOnVpn());
-
- // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
- // a subsequent CL.
- }
-
- private Vpn startLegacyVpn(final Vpn vpn, final VpnProfile vpnProfile) throws Exception {
- setMockedUsers(primaryUser);
-
- // Dummy egress interface
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(EGRESS_IFACE);
-
- final RouteInfo defaultRoute = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
- InetAddresses.parseNumericAddress("192.0.2.0"), EGRESS_IFACE);
- lp.addRoute(defaultRoute);
-
- vpn.startLegacyVpn(vpnProfile, EGRESS_NETWORK, lp);
- return vpn;
- }
-
- @Test
- public void testStartPlatformVpn() throws Exception {
- startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
- // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
- // a subsequent patch.
- }
-
- @Test
- public void testStartRacoonNumericAddress() throws Exception {
- startRacoon("1.2.3.4", "1.2.3.4");
- }
-
- @Test
- public void testStartRacoonHostname() throws Exception {
- startRacoon("hostname", "5.6.7.8"); // address returned by deps.resolve
- }
-
- private void assertTransportInfoMatches(NetworkCapabilities nc, int type) {
- assertNotNull(nc);
- VpnTransportInfo ti = (VpnTransportInfo) nc.getTransportInfo();
- assertNotNull(ti);
- assertEquals(type, ti.getType());
- }
-
- public void startRacoon(final String serverAddr, final String expectedAddr)
- throws Exception {
- final ConditionVariable legacyRunnerReady = new ConditionVariable();
- final VpnProfile profile = new VpnProfile("testProfile" /* key */);
- profile.type = VpnProfile.TYPE_L2TP_IPSEC_PSK;
- profile.name = "testProfileName";
- profile.username = "userName";
- profile.password = "thePassword";
- profile.server = serverAddr;
- profile.ipsecIdentifier = "id";
- profile.ipsecSecret = "secret";
- profile.l2tpSecret = "l2tpsecret";
-
- when(mConnectivityManager.getAllNetworks())
- .thenReturn(new Network[] { new Network(101) });
-
- when(mConnectivityManager.registerNetworkAgent(any(), any(), any(), any(),
- any(), any(), anyInt())).thenAnswer(invocation -> {
- // The runner has registered an agent and is now ready.
- legacyRunnerReady.open();
- return new Network(102);
- });
- final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), profile);
- final TestDeps deps = (TestDeps) vpn.mDeps;
- try {
- // udppsk and 1701 are the values for TYPE_L2TP_IPSEC_PSK
- assertArrayEquals(
- new String[] { EGRESS_IFACE, expectedAddr, "udppsk",
- profile.ipsecIdentifier, profile.ipsecSecret, "1701" },
- deps.racoonArgs.get(10, TimeUnit.SECONDS));
- // literal values are hardcoded in Vpn.java for mtpd args
- assertArrayEquals(
- new String[] { EGRESS_IFACE, "l2tp", expectedAddr, "1701", profile.l2tpSecret,
- "name", profile.username, "password", profile.password,
- "linkname", "vpn", "refuse-eap", "nodefaultroute", "usepeerdns",
- "idle", "1800", "mtu", "1270", "mru", "1270" },
- deps.mtpdArgs.get(10, TimeUnit.SECONDS));
-
- // Now wait for the runner to be ready before testing for the route.
- ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class);
- ArgumentCaptor<NetworkCapabilities> ncCaptor =
- ArgumentCaptor.forClass(NetworkCapabilities.class);
- verify(mConnectivityManager, timeout(10_000)).registerNetworkAgent(any(), any(),
- lpCaptor.capture(), ncCaptor.capture(), any(), any(), anyInt());
-
- // In this test the expected address is always v4 so /32.
- // Note that the interface needs to be specified because RouteInfo objects stored in
- // LinkProperties objects always acquire the LinkProperties' interface.
- final RouteInfo expectedRoute = new RouteInfo(new IpPrefix(expectedAddr + "/32"),
- null, EGRESS_IFACE, RouteInfo.RTN_THROW);
- final List<RouteInfo> actualRoutes = lpCaptor.getValue().getRoutes();
- assertTrue("Expected throw route (" + expectedRoute + ") not found in " + actualRoutes,
- actualRoutes.contains(expectedRoute));
-
- assertTransportInfoMatches(ncCaptor.getValue(), VpnManager.TYPE_VPN_LEGACY);
- } finally {
- // Now interrupt the thread, unblock the runner and clean up.
- vpn.mVpnRunner.exitVpnRunner();
- deps.getStateFile().delete(); // set to delete on exit, but this deletes it earlier
- vpn.mVpnRunner.join(10_000); // wait for up to 10s for the runner to die and cleanup
- }
- }
-
- private static final class TestDeps extends Vpn.Dependencies {
- public final CompletableFuture<String[]> racoonArgs = new CompletableFuture();
- public final CompletableFuture<String[]> mtpdArgs = new CompletableFuture();
- public final File mStateFile;
-
- private final HashMap<String, Boolean> mRunningServices = new HashMap<>();
-
- TestDeps() {
- try {
- mStateFile = File.createTempFile("vpnTest", ".tmp");
- mStateFile.deleteOnExit();
- } catch (final IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public boolean isCallerSystem() {
- return true;
- }
-
- @Override
- public void startService(final String serviceName) {
- mRunningServices.put(serviceName, true);
- }
-
- @Override
- public void stopService(final String serviceName) {
- mRunningServices.put(serviceName, false);
- }
-
- @Override
- public boolean isServiceRunning(final String serviceName) {
- return mRunningServices.getOrDefault(serviceName, false);
- }
-
- @Override
- public boolean isServiceStopped(final String serviceName) {
- return !isServiceRunning(serviceName);
- }
-
- @Override
- public File getStateFile() {
- return mStateFile;
- }
-
- @Override
- public PendingIntent getIntentForStatusPanel(Context context) {
- return null;
- }
-
- @Override
- public void sendArgumentsToDaemon(
- final String daemon, final LocalSocket socket, final String[] arguments,
- final Vpn.RetryScheduler interruptChecker) throws IOException {
- if ("racoon".equals(daemon)) {
- racoonArgs.complete(arguments);
- } else if ("mtpd".equals(daemon)) {
- writeStateFile(arguments);
- mtpdArgs.complete(arguments);
- } else {
- throw new UnsupportedOperationException("Unsupported daemon : " + daemon);
- }
- }
-
- private void writeStateFile(final String[] arguments) throws IOException {
- mStateFile.delete();
- mStateFile.createNewFile();
- mStateFile.deleteOnExit();
- final BufferedWriter writer = new BufferedWriter(
- new FileWriter(mStateFile, false /* append */));
- writer.write(EGRESS_IFACE);
- writer.write("\n");
- // addresses
- writer.write("10.0.0.1/24\n");
- // routes
- writer.write("192.168.6.0/24\n");
- // dns servers
- writer.write("192.168.6.1\n");
- // search domains
- writer.write("vpn.searchdomains.com\n");
- // endpoint - intentionally empty
- writer.write("\n");
- writer.flush();
- writer.close();
- }
-
- @Override
- @NonNull
- public InetAddress resolve(final String endpoint) {
- try {
- // If a numeric IP address, return it.
- return InetAddress.parseNumericAddress(endpoint);
- } catch (IllegalArgumentException e) {
- // Otherwise, return some token IP to test for.
- return InetAddress.parseNumericAddress("5.6.7.8");
- }
- }
-
- @Override
- public boolean isInterfacePresent(final Vpn vpn, final String iface) {
- return true;
- }
- }
-
- /**
- * Mock some methods of vpn object.
- */
- private Vpn createVpn(@UserIdInt int userId) {
- final Context asUserContext = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
- doReturn(UserHandle.of(userId)).when(asUserContext).getUser();
- when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt()))
- .thenReturn(asUserContext);
- final TestLooper testLooper = new TestLooper();
- final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, new TestDeps(), mNetService,
- mNetd, userId, mVpnProfileStore, mSystemServices, mIkev2SessionCreator);
- verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat(
- provider -> provider.getName().contains("VpnNetworkProvider")
- ));
- return vpn;
- }
-
- /**
- * Populate {@link #mUserManager} with a list of fake users.
- */
- private void setMockedUsers(UserInfo... users) {
- final Map<Integer, UserInfo> userMap = new ArrayMap<>();
- for (UserInfo user : users) {
- userMap.put(user.id, user);
- }
-
- /**
- * @see UserManagerService#getUsers(boolean)
- */
- doAnswer(invocation -> {
- final ArrayList<UserInfo> result = new ArrayList<>(users.length);
- for (UserInfo ui : users) {
- if (ui.isEnabled() && !ui.partial) {
- result.add(ui);
- }
- }
- return result;
- }).when(mUserManager).getAliveUsers();
-
- doAnswer(invocation -> {
- final int id = (int) invocation.getArguments()[0];
- return userMap.get(id);
- }).when(mUserManager).getUserInfo(anyInt());
- }
-
- /**
- * Populate {@link #mPackageManager} with a fake packageName-to-UID mapping.
- */
- private void setMockedPackages(final Map<String, Integer> packages) {
- try {
- doAnswer(invocation -> {
- final String appName = (String) invocation.getArguments()[0];
- final int userId = (int) invocation.getArguments()[1];
- Integer appId = packages.get(appName);
- if (appId == null) throw new PackageManager.NameNotFoundException(appName);
- return UserHandle.getUid(userId, appId);
- }).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt());
- } catch (Exception e) {
- }
- }
-
- private void setMockedNetworks(final Map<Network, NetworkCapabilities> networks) {
- doAnswer(invocation -> {
- final Network network = (Network) invocation.getArguments()[0];
- return networks.get(network);
- }).when(mConnectivityManager).getNetworkCapabilities(any());
- }
-
- // Need multiple copies of this, but Java's Stream objects can't be reused or
- // duplicated.
- private Stream<String> publicIpV4Routes() {
- return Stream.of(
- "0.0.0.0/5", "8.0.0.0/7", "11.0.0.0/8", "12.0.0.0/6", "16.0.0.0/4",
- "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/3", "160.0.0.0/5", "168.0.0.0/6",
- "172.0.0.0/12", "172.32.0.0/11", "172.64.0.0/10", "172.128.0.0/9",
- "173.0.0.0/8", "174.0.0.0/7", "176.0.0.0/4", "192.0.0.0/9", "192.128.0.0/11",
- "192.160.0.0/13", "192.169.0.0/16", "192.170.0.0/15", "192.172.0.0/14",
- "192.176.0.0/12", "192.192.0.0/10", "193.0.0.0/8", "194.0.0.0/7",
- "196.0.0.0/6", "200.0.0.0/5", "208.0.0.0/4");
- }
-
- private Stream<String> publicIpV6Routes() {
- return Stream.of(
- "::/1", "8000::/2", "c000::/3", "e000::/4", "f000::/5", "f800::/6",
- "fe00::/8", "2605:ef80:e:af1d::/64");
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsAccessTest.java b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsAccessTest.java
deleted file mode 100644
index 8b730af..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsAccessTest.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.when;
-
-import android.Manifest;
-import android.Manifest.permission;
-import android.app.AppOpsManager;
-import android.app.admin.DevicePolicyManagerInternal;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.telephony.TelephonyManager;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.LocalServices;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkStatsAccessTest {
- private static final String TEST_PKG = "com.example.test";
- private static final int TEST_UID = 12345;
-
- @Mock private Context mContext;
- @Mock private DevicePolicyManagerInternal mDpmi;
- @Mock private TelephonyManager mTm;
- @Mock private AppOpsManager mAppOps;
-
- // Hold the real service so we can restore it when tearing down the test.
- private DevicePolicyManagerInternal mSystemDpmi;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- mSystemDpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
- LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
- LocalServices.addService(DevicePolicyManagerInternal.class, mDpmi);
-
- when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTm);
- when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOps);
- }
-
- @After
- public void tearDown() throws Exception {
- LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
- LocalServices.addService(DevicePolicyManagerInternal.class, mSystemDpmi);
- }
-
- @Test
- public void testCheckAccessLevel_hasCarrierPrivileges() throws Exception {
- setHasCarrierPrivileges(true);
- setIsDeviceOwner(false);
- setIsProfileOwner(false);
- setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
- setHasReadHistoryPermission(false);
- assertEquals(NetworkStatsAccess.Level.DEVICE,
- NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
- }
-
- @Test
- public void testCheckAccessLevel_isDeviceOwner() throws Exception {
- setHasCarrierPrivileges(false);
- setIsDeviceOwner(true);
- setIsProfileOwner(false);
- setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
- setHasReadHistoryPermission(false);
- assertEquals(NetworkStatsAccess.Level.DEVICE,
- NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
- }
-
- @Test
- public void testCheckAccessLevel_isProfileOwner() throws Exception {
- setHasCarrierPrivileges(false);
- setIsDeviceOwner(false);
- setIsProfileOwner(true);
- setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
- setHasReadHistoryPermission(false);
- assertEquals(NetworkStatsAccess.Level.USER,
- NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
- }
-
- @Test
- public void testCheckAccessLevel_hasAppOpsBitAllowed() throws Exception {
- setHasCarrierPrivileges(false);
- setIsDeviceOwner(false);
- setIsProfileOwner(true);
- setHasAppOpsPermission(AppOpsManager.MODE_ALLOWED, false);
- setHasReadHistoryPermission(false);
- assertEquals(NetworkStatsAccess.Level.DEVICESUMMARY,
- NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
- }
-
- @Test
- public void testCheckAccessLevel_hasAppOpsBitDefault_grantedPermission() throws Exception {
- setHasCarrierPrivileges(false);
- setIsDeviceOwner(false);
- setIsProfileOwner(true);
- setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, true);
- setHasReadHistoryPermission(false);
- assertEquals(NetworkStatsAccess.Level.DEVICESUMMARY,
- NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
- }
-
- @Test
- public void testCheckAccessLevel_hasReadHistoryPermission() throws Exception {
- setHasCarrierPrivileges(false);
- setIsDeviceOwner(false);
- setIsProfileOwner(true);
- setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
- setHasReadHistoryPermission(true);
- assertEquals(NetworkStatsAccess.Level.DEVICESUMMARY,
- NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
- }
-
- @Test
- public void testCheckAccessLevel_deniedAppOpsBit() throws Exception {
- setHasCarrierPrivileges(false);
- setIsDeviceOwner(false);
- setIsProfileOwner(false);
- setHasAppOpsPermission(AppOpsManager.MODE_ERRORED, true);
- setHasReadHistoryPermission(false);
- assertEquals(NetworkStatsAccess.Level.DEFAULT,
- NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
- }
-
- @Test
- public void testCheckAccessLevel_deniedAppOpsBit_deniedPermission() throws Exception {
- setHasCarrierPrivileges(false);
- setIsDeviceOwner(false);
- setIsProfileOwner(false);
- setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
- setHasReadHistoryPermission(false);
- assertEquals(NetworkStatsAccess.Level.DEFAULT,
- NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
- }
-
- private void setHasCarrierPrivileges(boolean hasPrivileges) {
- when(mTm.checkCarrierPrivilegesForPackageAnyPhone(TEST_PKG)).thenReturn(
- hasPrivileges ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
- : TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
- }
-
- private void setIsDeviceOwner(boolean isOwner) {
- when(mDpmi.isActiveDeviceOwner(TEST_UID)).thenReturn(isOwner);
- }
-
- private void setIsProfileOwner(boolean isOwner) {
- when(mDpmi.isActiveProfileOwner(TEST_UID)).thenReturn(isOwner);
- }
-
- private void setHasAppOpsPermission(int appOpsMode, boolean hasPermission) {
- when(mAppOps.noteOp(AppOpsManager.OP_GET_USAGE_STATS, TEST_UID, TEST_PKG))
- .thenReturn(appOpsMode);
- when(mContext.checkCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS)).thenReturn(
- hasPermission ? PackageManager.PERMISSION_GRANTED
- : PackageManager.PERMISSION_DENIED);
- }
-
- private void setHasReadHistoryPermission(boolean hasPermission) {
- when(mContext.checkCallingOrSelfPermission(permission.READ_NETWORK_USAGE_HISTORY))
- .thenReturn(hasPermission ? PackageManager.PERMISSION_GRANTED
- : PackageManager.PERMISSION_DENIED);
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsBaseTest.java b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsBaseTest.java
deleted file mode 100644
index a058a46..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsBaseTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
-import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
-import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
-import static android.net.NetworkStats.METERED_ALL;
-import static android.net.NetworkStats.METERED_NO;
-import static android.net.NetworkStats.METERED_YES;
-import static android.net.NetworkStats.ROAMING_ALL;
-import static android.net.NetworkStats.ROAMING_NO;
-import static android.net.NetworkStats.ROAMING_YES;
-import static android.net.NetworkStats.SET_ALL;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.SET_FOREGROUND;
-import static android.net.NetworkStats.TAG_NONE;
-
-import static org.junit.Assert.assertEquals;
-
-import android.net.NetworkStats;
-import android.net.UnderlyingNetworkInfo;
-
-import java.util.Arrays;
-
-/** Superclass with utilities for NetworkStats(Service|Factory)Test */
-abstract class NetworkStatsBaseTest {
- static final String TEST_IFACE = "test0";
- static final String TEST_IFACE2 = "test1";
- static final String TUN_IFACE = "test_nss_tun0";
- static final String TUN_IFACE2 = "test_nss_tun1";
-
- static final int UID_RED = 1001;
- static final int UID_BLUE = 1002;
- static final int UID_GREEN = 1003;
- static final int UID_VPN = 1004;
-
- void assertValues(NetworkStats stats, String iface, int uid, long rxBytes,
- long rxPackets, long txBytes, long txPackets) {
- assertValues(
- stats, iface, uid, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
- rxBytes, rxPackets, txBytes, txPackets, 0);
- }
-
- void assertValues(NetworkStats stats, String iface, int uid, int set, int tag,
- int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
- long txBytes, long txPackets, long operations) {
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- final int[] sets;
- if (set == SET_ALL) {
- sets = new int[] {SET_ALL, SET_DEFAULT, SET_FOREGROUND};
- } else {
- sets = new int[] {set};
- }
-
- final int[] roamings;
- if (roaming == ROAMING_ALL) {
- roamings = new int[] {ROAMING_ALL, ROAMING_YES, ROAMING_NO};
- } else {
- roamings = new int[] {roaming};
- }
-
- final int[] meterings;
- if (metered == METERED_ALL) {
- meterings = new int[] {METERED_ALL, METERED_YES, METERED_NO};
- } else {
- meterings = new int[] {metered};
- }
-
- final int[] defaultNetworks;
- if (defaultNetwork == DEFAULT_NETWORK_ALL) {
- defaultNetworks =
- new int[] {DEFAULT_NETWORK_ALL, DEFAULT_NETWORK_YES, DEFAULT_NETWORK_NO};
- } else {
- defaultNetworks = new int[] {defaultNetwork};
- }
-
- for (int s : sets) {
- for (int r : roamings) {
- for (int m : meterings) {
- for (int d : defaultNetworks) {
- final int i = stats.findIndex(iface, uid, s, tag, m, r, d);
- if (i != -1) {
- entry.add(stats.getValues(i, null));
- }
- }
- }
- }
- }
-
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- assertEquals("unexpected txPackets", txPackets, entry.txPackets);
- assertEquals("unexpected operations", operations, entry.operations);
- }
-
- static UnderlyingNetworkInfo createVpnInfo(String[] underlyingIfaces) {
- return createVpnInfo(TUN_IFACE, underlyingIfaces);
- }
-
- static UnderlyingNetworkInfo createVpnInfo(String vpnIface, String[] underlyingIfaces) {
- return new UnderlyingNetworkInfo(UID_VPN, vpnIface, Arrays.asList(underlyingIfaces));
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsCollectionTest.java b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsCollectionTest.java
deleted file mode 100644
index 505ff9b..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.NetworkIdentity.OEM_NONE;
-import static android.net.NetworkStats.SET_ALL;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkStatsHistory.FIELD_ALL;
-import static android.net.NetworkTemplate.buildTemplateMobileAll;
-import static android.os.Process.myUid;
-import static android.text.format.DateUtils.HOUR_IN_MILLIS;
-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-
-import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
-import static com.android.testutils.MiscAsserts.assertThrows;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.NetworkIdentity;
-import android.net.NetworkStats;
-import android.net.NetworkStatsHistory;
-import android.net.NetworkTemplate;
-import android.os.Process;
-import android.os.UserHandle;
-import android.telephony.SubscriptionPlan;
-import android.telephony.TelephonyManager;
-import android.text.format.DateUtils;
-import android.util.RecurrenceRule;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.frameworks.tests.net.R;
-
-import libcore.io.IoUtils;
-import libcore.io.Streams;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.time.Clock;
-import java.time.Instant;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tests for {@link NetworkStatsCollection}.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkStatsCollectionTest {
-
- private static final String TEST_FILE = "test.bin";
- private static final String TEST_IMSI = "310260000000000";
-
- private static final long TIME_A = 1326088800000L; // UTC: Monday 9th January 2012 06:00:00 AM
- private static final long TIME_B = 1326110400000L; // UTC: Monday 9th January 2012 12:00:00 PM
- private static final long TIME_C = 1326132000000L; // UTC: Monday 9th January 2012 06:00:00 PM
-
- private static Clock sOriginalClock;
-
- @Before
- public void setUp() throws Exception {
- sOriginalClock = RecurrenceRule.sClock;
- // ignore any device overlay while testing
- NetworkTemplate.forceAllNetworkTypes();
- }
-
- @After
- public void tearDown() throws Exception {
- RecurrenceRule.sClock = sOriginalClock;
- NetworkTemplate.resetForceAllNetworkTypes();
- }
-
- private void setClock(Instant instant) {
- RecurrenceRule.sClock = Clock.fixed(instant, ZoneId.systemDefault());
- }
-
- @Test
- public void testReadLegacyNetwork() throws Exception {
- final File testFile =
- new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
- stageFile(R.raw.netstats_v1, testFile);
-
- final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
- collection.readLegacyNetwork(testFile);
-
- // verify that history read correctly
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 636016770L, 709306L, 88038768L, 518836L, NetworkStatsAccess.Level.DEVICE);
-
- // now export into a unified format
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- collection.write(bos);
-
- // clear structure completely
- collection.reset();
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 0L, 0L, 0L, 0L, NetworkStatsAccess.Level.DEVICE);
-
- // and read back into structure, verifying that totals are same
- collection.read(new ByteArrayInputStream(bos.toByteArray()));
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 636016770L, 709306L, 88038768L, 518836L, NetworkStatsAccess.Level.DEVICE);
- }
-
- @Test
- public void testReadLegacyUid() throws Exception {
- final File testFile =
- new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
- stageFile(R.raw.netstats_uid_v4, testFile);
-
- final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
- collection.readLegacyUid(testFile, false);
-
- // verify that history read correctly
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 637076152L, 711413L, 88343717L, 521022L, NetworkStatsAccess.Level.DEVICE);
-
- // now export into a unified format
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- collection.write(bos);
-
- // clear structure completely
- collection.reset();
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 0L, 0L, 0L, 0L, NetworkStatsAccess.Level.DEVICE);
-
- // and read back into structure, verifying that totals are same
- collection.read(new ByteArrayInputStream(bos.toByteArray()));
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 637076152L, 711413L, 88343717L, 521022L, NetworkStatsAccess.Level.DEVICE);
- }
-
- @Test
- public void testReadLegacyUidTags() throws Exception {
- final File testFile =
- new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
- stageFile(R.raw.netstats_uid_v4, testFile);
-
- final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
- collection.readLegacyUid(testFile, true);
-
- // verify that history read correctly
- assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
- 77017831L, 100995L, 35436758L, 92344L);
-
- // now export into a unified format
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- collection.write(bos);
-
- // clear structure completely
- collection.reset();
- assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
- 0L, 0L, 0L, 0L);
-
- // and read back into structure, verifying that totals are same
- collection.read(new ByteArrayInputStream(bos.toByteArray()));
- assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
- 77017831L, 100995L, 35436758L, 92344L);
- }
-
- @Test
- public void testStartEndAtomicBuckets() throws Exception {
- final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS);
-
- // record empty data straddling between buckets
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- entry.rxBytes = 32;
- collection.recordData(null, UID_ALL, SET_DEFAULT, TAG_NONE, 30 * MINUTE_IN_MILLIS,
- 90 * MINUTE_IN_MILLIS, entry);
-
- // assert that we report boundary in atomic buckets
- assertEquals(0, collection.getStartMillis());
- assertEquals(2 * HOUR_IN_MILLIS, collection.getEndMillis());
- }
-
- @Test
- public void testAccessLevels() throws Exception {
- final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS);
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- final NetworkIdentitySet identSet = new NetworkIdentitySet();
- identSet.add(new NetworkIdentity(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- TEST_IMSI, null, false, true, true, OEM_NONE));
-
- int myUid = Process.myUid();
- int otherUidInSameUser = Process.myUid() + 1;
- int uidInDifferentUser = Process.myUid() + UserHandle.PER_USER_RANGE;
-
- // Record one entry for the current UID.
- entry.rxBytes = 32;
- collection.recordData(identSet, myUid, SET_DEFAULT, TAG_NONE, 0, 60 * MINUTE_IN_MILLIS,
- entry);
-
- // Record one entry for another UID in this user.
- entry.rxBytes = 64;
- collection.recordData(identSet, otherUidInSameUser, SET_DEFAULT, TAG_NONE, 0,
- 60 * MINUTE_IN_MILLIS, entry);
-
- // Record one entry for the system UID.
- entry.rxBytes = 128;
- collection.recordData(identSet, Process.SYSTEM_UID, SET_DEFAULT, TAG_NONE, 0,
- 60 * MINUTE_IN_MILLIS, entry);
-
- // Record one entry for a UID in a different user.
- entry.rxBytes = 256;
- collection.recordData(identSet, uidInDifferentUser, SET_DEFAULT, TAG_NONE, 0,
- 60 * MINUTE_IN_MILLIS, entry);
-
- // Verify the set of relevant UIDs for each access level.
- assertArrayEquals(new int[] { myUid },
- collection.getRelevantUids(NetworkStatsAccess.Level.DEFAULT));
- assertArrayEquals(new int[] { Process.SYSTEM_UID, myUid, otherUidInSameUser },
- collection.getRelevantUids(NetworkStatsAccess.Level.USER));
- assertArrayEquals(
- new int[] { Process.SYSTEM_UID, myUid, otherUidInSameUser, uidInDifferentUser },
- collection.getRelevantUids(NetworkStatsAccess.Level.DEVICE));
-
- // Verify security check in getHistory.
- assertNotNull(collection.getHistory(buildTemplateMobileAll(TEST_IMSI), null, myUid, SET_DEFAULT,
- TAG_NONE, 0, 0L, 0L, NetworkStatsAccess.Level.DEFAULT, myUid));
- try {
- collection.getHistory(buildTemplateMobileAll(TEST_IMSI), null, otherUidInSameUser,
- SET_DEFAULT, TAG_NONE, 0, 0L, 0L, NetworkStatsAccess.Level.DEFAULT, myUid);
- fail("Should have thrown SecurityException for accessing different UID");
- } catch (SecurityException e) {
- // expected
- }
-
- // Verify appropriate aggregation in getSummary.
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32, 0, 0, 0,
- NetworkStatsAccess.Level.DEFAULT);
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32 + 64 + 128, 0, 0, 0,
- NetworkStatsAccess.Level.USER);
- assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32 + 64 + 128 + 256, 0, 0,
- 0, NetworkStatsAccess.Level.DEVICE);
- }
-
- @Test
- public void testAugmentPlan() throws Exception {
- final File testFile =
- new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
- stageFile(R.raw.netstats_v1, testFile);
-
- final NetworkStatsCollection emptyCollection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
- final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
- collection.readLegacyNetwork(testFile);
-
- // We're in the future, but not that far off
- setClock(Instant.parse("2012-06-01T00:00:00.00Z"));
-
- // Test a bunch of plans that should result in no augmentation
- final List<SubscriptionPlan> plans = new ArrayList<>();
-
- // No plan
- plans.add(null);
- // No usage anchor
- plans.add(SubscriptionPlan.Builder
- .createRecurringMonthly(ZonedDateTime.parse("2011-01-14T00:00:00.00Z")).build());
- // Usage anchor far in past
- plans.add(SubscriptionPlan.Builder
- .createRecurringMonthly(ZonedDateTime.parse("2011-01-14T00:00:00.00Z"))
- .setDataUsage(1000L, TIME_A - DateUtils.YEAR_IN_MILLIS).build());
- // Usage anchor far in future
- plans.add(SubscriptionPlan.Builder
- .createRecurringMonthly(ZonedDateTime.parse("2011-01-14T00:00:00.00Z"))
- .setDataUsage(1000L, TIME_A + DateUtils.YEAR_IN_MILLIS).build());
- // Usage anchor near but outside cycle
- plans.add(SubscriptionPlan.Builder
- .createNonrecurring(ZonedDateTime.parse("2012-01-09T09:00:00.00Z"),
- ZonedDateTime.parse("2012-01-09T15:00:00.00Z"))
- .setDataUsage(1000L, TIME_C).build());
-
- for (SubscriptionPlan plan : plans) {
- int i;
- NetworkStatsHistory history;
-
- // Empty collection should be untouched
- history = getHistory(emptyCollection, plan, TIME_A, TIME_C);
- assertEquals(0L, history.getTotalBytes());
-
- // Normal collection should be untouched
- history = getHistory(collection, plan, TIME_A, TIME_C); i = 0;
- assertEntry(100647, 197, 23649, 185, history.getValues(i++, null));
- assertEntry(100647, 196, 23648, 185, history.getValues(i++, null));
- assertEntry(18323, 76, 15032, 76, history.getValues(i++, null));
- assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
- assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
- assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
- assertEntry(10747, 50, 16839, 55, history.getValues(i++, null));
- assertEntry(10747, 49, 16837, 54, history.getValues(i++, null));
- assertEntry(89191, 151, 18021, 140, history.getValues(i++, null));
- assertEntry(89190, 150, 18020, 139, history.getValues(i++, null));
- assertEntry(3821, 23, 4525, 26, history.getValues(i++, null));
- assertEntry(3820, 21, 4524, 26, history.getValues(i++, null));
- assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
- assertEntry(8289, 36, 6864, 39, history.getValues(i++, null));
- assertEntry(8289, 34, 6862, 37, history.getValues(i++, null));
- assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
- assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
- assertEntry(11378, 49, 9261, 50, history.getValues(i++, null));
- assertEntry(11377, 48, 9261, 48, history.getValues(i++, null));
- assertEntry(201766, 328, 41808, 291, history.getValues(i++, null));
- assertEntry(201764, 328, 41807, 290, history.getValues(i++, null));
- assertEntry(106106, 219, 39918, 202, history.getValues(i++, null));
- assertEntry(106105, 216, 39916, 200, history.getValues(i++, null));
- assertEquals(history.size(), i);
-
- // Slice from middle should be untouched
- history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
- TIME_B + HOUR_IN_MILLIS); i = 0;
- assertEntry(3821, 23, 4525, 26, history.getValues(i++, null));
- assertEntry(3820, 21, 4524, 26, history.getValues(i++, null));
- assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
- assertEquals(history.size(), i);
- }
-
- // Lower anchor in the middle of plan
- {
- int i;
- NetworkStatsHistory history;
-
- final SubscriptionPlan plan = SubscriptionPlan.Builder
- .createNonrecurring(ZonedDateTime.parse("2012-01-09T09:00:00.00Z"),
- ZonedDateTime.parse("2012-01-09T15:00:00.00Z"))
- .setDataUsage(200000L, TIME_B).build();
-
- // Empty collection should be augmented
- history = getHistory(emptyCollection, plan, TIME_A, TIME_C);
- assertEquals(200000L, history.getTotalBytes());
-
- // Normal collection should be augmented
- history = getHistory(collection, plan, TIME_A, TIME_C); i = 0;
- assertEntry(100647, 197, 23649, 185, history.getValues(i++, null));
- assertEntry(100647, 196, 23648, 185, history.getValues(i++, null));
- assertEntry(18323, 76, 15032, 76, history.getValues(i++, null));
- assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
- assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
- assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
- // Cycle point; start data normalization
- assertEntry(7507, 0, 11763, 0, history.getValues(i++, null));
- assertEntry(7507, 0, 11762, 0, history.getValues(i++, null));
- assertEntry(62309, 0, 12589, 0, history.getValues(i++, null));
- assertEntry(62309, 0, 12588, 0, history.getValues(i++, null));
- assertEntry(2669, 0, 3161, 0, history.getValues(i++, null));
- assertEntry(2668, 0, 3160, 0, history.getValues(i++, null));
- // Anchor point; end data normalization
- assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
- assertEntry(8289, 36, 6864, 39, history.getValues(i++, null));
- assertEntry(8289, 34, 6862, 37, history.getValues(i++, null));
- assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
- assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
- // Cycle point
- assertEntry(11378, 49, 9261, 50, history.getValues(i++, null));
- assertEntry(11377, 48, 9261, 48, history.getValues(i++, null));
- assertEntry(201766, 328, 41808, 291, history.getValues(i++, null));
- assertEntry(201764, 328, 41807, 290, history.getValues(i++, null));
- assertEntry(106106, 219, 39918, 202, history.getValues(i++, null));
- assertEntry(106105, 216, 39916, 200, history.getValues(i++, null));
- assertEquals(history.size(), i);
-
- // Slice from middle should be augmented
- history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
- TIME_B + HOUR_IN_MILLIS); i = 0;
- assertEntry(2669, 0, 3161, 0, history.getValues(i++, null));
- assertEntry(2668, 0, 3160, 0, history.getValues(i++, null));
- assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
- assertEquals(history.size(), i);
- }
-
- // Higher anchor in the middle of plan
- {
- int i;
- NetworkStatsHistory history;
-
- final SubscriptionPlan plan = SubscriptionPlan.Builder
- .createNonrecurring(ZonedDateTime.parse("2012-01-09T09:00:00.00Z"),
- ZonedDateTime.parse("2012-01-09T15:00:00.00Z"))
- .setDataUsage(400000L, TIME_B + MINUTE_IN_MILLIS).build();
-
- // Empty collection should be augmented
- history = getHistory(emptyCollection, plan, TIME_A, TIME_C);
- assertEquals(400000L, history.getTotalBytes());
-
- // Normal collection should be augmented
- history = getHistory(collection, plan, TIME_A, TIME_C); i = 0;
- assertEntry(100647, 197, 23649, 185, history.getValues(i++, null));
- assertEntry(100647, 196, 23648, 185, history.getValues(i++, null));
- assertEntry(18323, 76, 15032, 76, history.getValues(i++, null));
- assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
- assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
- assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
- // Cycle point; start data normalization
- assertEntry(15015, 0, 23527, 0, history.getValues(i++, null));
- assertEntry(15015, 0, 23524, 0, history.getValues(i++, null));
- assertEntry(124619, 0, 25179, 0, history.getValues(i++, null));
- assertEntry(124618, 0, 25177, 0, history.getValues(i++, null));
- assertEntry(5338, 0, 6322, 0, history.getValues(i++, null));
- assertEntry(5337, 0, 6320, 0, history.getValues(i++, null));
- // Anchor point; end data normalization
- assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
- assertEntry(8289, 36, 6864, 39, history.getValues(i++, null));
- assertEntry(8289, 34, 6862, 37, history.getValues(i++, null));
- assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
- assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
- // Cycle point
- assertEntry(11378, 49, 9261, 50, history.getValues(i++, null));
- assertEntry(11377, 48, 9261, 48, history.getValues(i++, null));
- assertEntry(201766, 328, 41808, 291, history.getValues(i++, null));
- assertEntry(201764, 328, 41807, 290, history.getValues(i++, null));
- assertEntry(106106, 219, 39918, 202, history.getValues(i++, null));
- assertEntry(106105, 216, 39916, 200, history.getValues(i++, null));
-
- // Slice from middle should be augmented
- history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
- TIME_B + HOUR_IN_MILLIS); i = 0;
- assertEntry(5338, 0, 6322, 0, history.getValues(i++, null));
- assertEntry(5337, 0, 6320, 0, history.getValues(i++, null));
- assertEntry(91686, 159, 18576, 146, history.getValues(i++, null));
- assertEntry(91685, 159, 18574, 146, history.getValues(i++, null));
- assertEquals(history.size(), i);
- }
- }
-
- @Test
- public void testAugmentPlanGigantic() throws Exception {
- // We're in the future, but not that far off
- setClock(Instant.parse("2012-06-01T00:00:00.00Z"));
-
- // Create a simple history with a ton of measured usage
- final NetworkStatsCollection large = new NetworkStatsCollection(HOUR_IN_MILLIS);
- final NetworkIdentitySet ident = new NetworkIdentitySet();
- ident.add(new NetworkIdentity(ConnectivityManager.TYPE_MOBILE, -1, TEST_IMSI, null,
- false, true, true, OEM_NONE));
- large.recordData(ident, UID_ALL, SET_ALL, TAG_NONE, TIME_A, TIME_B,
- new NetworkStats.Entry(12_730_893_164L, 1, 0, 0, 0));
-
- // Verify untouched total
- assertEquals(12_730_893_164L, getHistory(large, null, TIME_A, TIME_C).getTotalBytes());
-
- // Verify anchor that might cause overflows
- final SubscriptionPlan plan = SubscriptionPlan.Builder
- .createRecurringMonthly(ZonedDateTime.parse("2012-01-09T00:00:00.00Z"))
- .setDataUsage(4_939_212_390L, TIME_B).build();
- assertEquals(4_939_212_386L, getHistory(large, plan, TIME_A, TIME_C).getTotalBytes());
- }
-
- @Test
- public void testRounding() throws Exception {
- final NetworkStatsCollection coll = new NetworkStatsCollection(HOUR_IN_MILLIS);
-
- // Special values should remain unchanged
- for (long time : new long[] {
- Long.MIN_VALUE, Long.MAX_VALUE, SubscriptionPlan.TIME_UNKNOWN
- }) {
- assertEquals(time, coll.roundUp(time));
- assertEquals(time, coll.roundDown(time));
- }
-
- assertEquals(TIME_A, coll.roundUp(TIME_A));
- assertEquals(TIME_A, coll.roundDown(TIME_A));
-
- assertEquals(TIME_A + HOUR_IN_MILLIS, coll.roundUp(TIME_A + 1));
- assertEquals(TIME_A, coll.roundDown(TIME_A + 1));
-
- assertEquals(TIME_A, coll.roundUp(TIME_A - 1));
- assertEquals(TIME_A - HOUR_IN_MILLIS, coll.roundDown(TIME_A - 1));
- }
-
- @Test
- public void testMultiplySafeRational() {
- assertEquals(25, multiplySafeByRational(50, 1, 2));
- assertEquals(100, multiplySafeByRational(50, 2, 1));
-
- assertEquals(-10, multiplySafeByRational(30, -1, 3));
- assertEquals(0, multiplySafeByRational(30, 0, 3));
- assertEquals(10, multiplySafeByRational(30, 1, 3));
- assertEquals(20, multiplySafeByRational(30, 2, 3));
- assertEquals(30, multiplySafeByRational(30, 3, 3));
- assertEquals(40, multiplySafeByRational(30, 4, 3));
-
- assertEquals(100_000_000_000L,
- multiplySafeByRational(300_000_000_000L, 10_000_000_000L, 30_000_000_000L));
- assertEquals(100_000_000_010L,
- multiplySafeByRational(300_000_000_000L, 10_000_000_001L, 30_000_000_000L));
- assertEquals(823_202_048L,
- multiplySafeByRational(4_939_212_288L, 2_121_815_528L, 12_730_893_165L));
-
- assertThrows(ArithmeticException.class, () -> multiplySafeByRational(30, 3, 0));
- }
-
- /**
- * Copy a {@link Resources#openRawResource(int)} into {@link File} for
- * testing purposes.
- */
- private void stageFile(int rawId, File file) throws Exception {
- new File(file.getParent()).mkdirs();
- InputStream in = null;
- OutputStream out = null;
- try {
- in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
- out = new FileOutputStream(file);
- Streams.copy(in, out);
- } finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(out);
- }
- }
-
- private static NetworkStatsHistory getHistory(NetworkStatsCollection collection,
- SubscriptionPlan augmentPlan, long start, long end) {
- return collection.getHistory(buildTemplateMobileAll(TEST_IMSI), augmentPlan, UID_ALL,
- SET_ALL, TAG_NONE, FIELD_ALL, start, end, NetworkStatsAccess.Level.DEVICE, myUid());
- }
-
- private static void assertSummaryTotal(NetworkStatsCollection collection,
- NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets,
- @NetworkStatsAccess.Level int accessLevel) {
- final NetworkStats.Entry actual = collection.getSummary(
- template, Long.MIN_VALUE, Long.MAX_VALUE, accessLevel, myUid())
- .getTotal(null);
- assertEntry(rxBytes, rxPackets, txBytes, txPackets, actual);
- }
-
- private static void assertSummaryTotalIncludingTags(NetworkStatsCollection collection,
- NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets) {
- final NetworkStats.Entry actual = collection.getSummary(
- template, Long.MIN_VALUE, Long.MAX_VALUE, NetworkStatsAccess.Level.DEVICE, myUid())
- .getTotalIncludingTags(null);
- assertEntry(rxBytes, rxPackets, txBytes, txPackets, actual);
- }
-
- private static void assertEntry(long rxBytes, long rxPackets, long txBytes, long txPackets,
- NetworkStats.Entry actual) {
- assertEntry(new NetworkStats.Entry(rxBytes, rxPackets, txBytes, txPackets, 0L), actual);
- }
-
- private static void assertEntry(long rxBytes, long rxPackets, long txBytes, long txPackets,
- NetworkStatsHistory.Entry actual) {
- assertEntry(new NetworkStats.Entry(rxBytes, rxPackets, txBytes, txPackets, 0L), actual);
- }
-
- private static void assertEntry(NetworkStats.Entry expected,
- NetworkStatsHistory.Entry actual) {
- assertEntry(expected, new NetworkStats.Entry(actual.rxBytes, actual.rxPackets,
- actual.txBytes, actual.txPackets, 0L));
- }
-
- private static void assertEntry(NetworkStats.Entry expected,
- NetworkStats.Entry actual) {
- assertEquals("unexpected rxBytes", expected.rxBytes, actual.rxBytes);
- assertEquals("unexpected rxPackets", expected.rxPackets, actual.rxPackets);
- assertEquals("unexpected txBytes", expected.txBytes, actual.txBytes);
- assertEquals("unexpected txPackets", expected.txPackets, actual.txPackets);
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java
deleted file mode 100644
index f3ae9b0..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
-import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
-import static android.net.NetworkStats.METERED_ALL;
-import static android.net.NetworkStats.METERED_NO;
-import static android.net.NetworkStats.ROAMING_ALL;
-import static android.net.NetworkStats.ROAMING_NO;
-import static android.net.NetworkStats.SET_ALL;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.SET_FOREGROUND;
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkStats.UID_ALL;
-
-import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.content.res.Resources;
-import android.net.NetworkStats;
-import android.net.TrafficStats;
-import android.net.UnderlyingNetworkInfo;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.frameworks.tests.net.R;
-
-import libcore.io.IoUtils;
-import libcore.io.Streams;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/** Tests for {@link NetworkStatsFactory}. */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkStatsFactoryTest extends NetworkStatsBaseTest {
- private static final String CLAT_PREFIX = "v4-";
-
- private File mTestProc;
- private NetworkStatsFactory mFactory;
-
- @Before
- public void setUp() throws Exception {
- mTestProc = new File(InstrumentationRegistry.getContext().getFilesDir(), "proc");
- if (mTestProc.exists()) {
- IoUtils.deleteContents(mTestProc);
- }
-
- // The libandroid_servers which have the native method is not available to
- // applications. So in order to have a test support native library, the native code
- // related to networkStatsFactory is compiled to a minimal native library and loaded here.
- System.loadLibrary("networkstatsfactorytestjni");
- mFactory = new NetworkStatsFactory(mTestProc, false);
- mFactory.updateUnderlyingNetworkInfos(new UnderlyingNetworkInfo[0]);
- }
-
- @After
- public void tearDown() throws Exception {
- mFactory = null;
-
- if (mTestProc.exists()) {
- IoUtils.deleteContents(mTestProc);
- }
- }
-
- @Test
- public void testNetworkStatsDetail() throws Exception {
- final NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_typical);
-
- assertEquals(70, stats.size());
- assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 18621L, 2898L);
- assertStatsEntry(stats, "wlan0", 10011, SET_DEFAULT, 0x0, 35777L, 5718L);
- assertStatsEntry(stats, "wlan0", 10021, SET_DEFAULT, 0x7fffff01, 562386L, 49228L);
- assertStatsEntry(stats, "rmnet1", 10021, SET_DEFAULT, 0x30100000, 219110L, 227423L);
- assertStatsEntry(stats, "rmnet2", 10001, SET_DEFAULT, 0x0, 1125899906842624L, 984L);
- }
-
- @Test
- public void testVpnRewriteTrafficThroughItself() throws Exception {
- UnderlyingNetworkInfo[] underlyingNetworkInfos =
- new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- //
- // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
- // over VPN.
- // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
- // over VPN.
- //
- // VPN UID rewrites packets read from TUN back to TUN, plus some of its own traffic
-
- final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_rewrite_through_self);
-
- assertValues(tunStats, TUN_IFACE, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 2000L, 200L, 1000L, 100L, 0);
- assertValues(tunStats, TUN_IFACE, UID_BLUE, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 1000L, 100L, 500L, 50L, 0);
- assertValues(tunStats, TUN_IFACE, UID_VPN, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 0L, 0L, 1600L, 160L, 0);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 2000L, 200L, 1000L, 100L);
- assertValues(tunStats, TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 300L, 0L, 260L, 26L);
- }
-
- @Test
- public void testVpnWithClat() throws Exception {
- final UnderlyingNetworkInfo[] underlyingNetworkInfos = new UnderlyingNetworkInfo[] {
- createVpnInfo(new String[] {CLAT_PREFIX + TEST_IFACE})};
- mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
- mFactory.noteStackedIface(CLAT_PREFIX + TEST_IFACE, TEST_IFACE);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
- // over VPN.
- // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
- // over VPN.
- // VPN sent 1650 bytes (150 packets), and received 3300 (300 packets) over v4-WiFi, and clat
- // added 20 bytes per packet of extra overhead
- //
- // For 1650 bytes sent over v4-WiFi, 4650 bytes were actually sent over WiFi, which is
- // expected to be split as follows:
- // UID_RED: 1000 bytes, 100 packets
- // UID_BLUE: 500 bytes, 50 packets
- // UID_VPN: 3150 bytes, 0 packets
- //
- // For 3300 bytes received over v4-WiFi, 9300 bytes were actually sent over WiFi, which is
- // expected to be split as follows:
- // UID_RED: 2000 bytes, 200 packets
- // UID_BLUE: 1000 bytes, 100 packets
- // UID_VPN: 6300 bytes, 0 packets
- final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_with_clat);
-
- assertValues(tunStats, CLAT_PREFIX + TEST_IFACE, UID_RED, 2000L, 200L, 1000, 100L);
- assertValues(tunStats, CLAT_PREFIX + TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
- assertValues(tunStats, CLAT_PREFIX + TEST_IFACE, UID_VPN, 6300L, 0L, 3150L, 0L);
- }
-
- @Test
- public void testVpnWithOneUnderlyingIface() throws Exception {
- final UnderlyingNetworkInfo[] underlyingNetworkInfos =
- new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
- // over VPN.
- // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
- // over VPN.
- // VPN sent 1650 bytes (150 packets), and received 3300 (300 packets) over WiFi.
- // Of 1650 bytes sent over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes
- // attributed to UID_BLUE, and 150 bytes attributed to UID_VPN.
- // Of 3300 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes
- // attributed to UID_BLUE, and 300 bytes attributed to UID_VPN.
- final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_one_underlying);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 2000L, 200L, 1000L, 100L);
- assertValues(tunStats, TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 300L, 0L, 150L, 0L);
- }
-
- @Test
- public void testVpnWithOneUnderlyingIfaceAndOwnTraffic() throws Exception {
- // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
- final UnderlyingNetworkInfo[] underlyingNetworkInfos =
- new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
- // over VPN.
- // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
- // over VPN.
- // Additionally, the VPN sends 6000 bytes (600 packets) of its own traffic into the tun
- // interface (passing that traffic to the VPN endpoint), and receives 5000 bytes (500
- // packets) from it. Including overhead that is 6600/5500 bytes.
- // VPN sent 8250 bytes (750 packets), and received 8800 (800 packets) over WiFi.
- // Of 8250 bytes sent over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes
- // attributed to UID_BLUE, and 6750 bytes attributed to UID_VPN.
- // Of 8800 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes
- // attributed to UID_BLUE, and 5800 bytes attributed to UID_VPN.
- final NetworkStats tunStats =
- parseDetailedStats(R.raw.xt_qtaguid_vpn_one_underlying_own_traffic);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 2000L, 200L, 1000L, 100L);
- assertValues(tunStats, TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 5800L, 500L, 6750L, 600L);
- }
-
- @Test
- public void testVpnWithOneUnderlyingIface_withCompression() throws Exception {
- // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
- final UnderlyingNetworkInfo[] underlyingNetworkInfos =
- new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
- // 3000 bytes (300 packets) were sent/received by UID_BLUE over VPN.
- // VPN sent/received 1000 bytes (100 packets) over WiFi.
- // Of 1000 bytes over WiFi, expect 250 bytes attributed UID_RED and 750 bytes to UID_BLUE,
- // with nothing attributed to UID_VPN for both rx/tx traffic.
- final NetworkStats tunStats =
- parseDetailedStats(R.raw.xt_qtaguid_vpn_one_underlying_compression);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 250L, 25L, 250L, 25L);
- assertValues(tunStats, TEST_IFACE, UID_BLUE, 750L, 75L, 750L, 75L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 0L, 0L, 0L, 0L);
- }
-
- @Test
- public void testVpnWithTwoUnderlyingIfaces_packetDuplication() throws Exception {
- // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
- // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
- // Additionally, VPN is duplicating traffic across both WiFi and Cell.
- final UnderlyingNetworkInfo[] underlyingNetworkInfos =
- new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
- mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent/received by UID_RED and UID_BLUE over VPN.
- // VPN sent/received 4400 bytes (400 packets) over both WiFi and Cell (8800 bytes in total).
- // Of 8800 bytes over WiFi/Cell, expect:
- // - 500 bytes rx/tx each over WiFi/Cell attributed to both UID_RED and UID_BLUE.
- // - 1200 bytes rx/tx each over WiFi/Cell for VPN_UID.
- final NetworkStats tunStats =
- parseDetailedStats(R.raw.xt_qtaguid_vpn_two_underlying_duplication);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 500L, 50L, 500L, 50L);
- assertValues(tunStats, TEST_IFACE, UID_BLUE, 500L, 50L, 500L, 50L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 1200L, 100L, 1200L, 100L);
- assertValues(tunStats, TEST_IFACE2, UID_RED, 500L, 50L, 500L, 50L);
- assertValues(tunStats, TEST_IFACE2, UID_BLUE, 500L, 50L, 500L, 50L);
- assertValues(tunStats, TEST_IFACE2, UID_VPN, 1200L, 100L, 1200L, 100L);
- }
-
- @Test
- public void testConcurrentVpns() throws Exception {
- // Assume two VPNs are connected on two different network interfaces. VPN1 is using
- // TEST_IFACE and VPN2 is using TEST_IFACE2.
- final UnderlyingNetworkInfo[] underlyingNetworkInfos = new UnderlyingNetworkInfo[] {
- createVpnInfo(TUN_IFACE, new String[] {TEST_IFACE}),
- createVpnInfo(TUN_IFACE2, new String[] {TEST_IFACE2})};
- mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent, and 2000 bytes (200 packets) were received by UID_RED
- // over VPN1.
- // 700 bytes (70 packets) were sent, and 3000 bytes (300 packets) were received by UID_RED
- // over VPN2.
- // 500 bytes (50 packets) were sent, and 1000 bytes (100 packets) were received by UID_BLUE
- // over VPN1.
- // 250 bytes (25 packets) were sent, and 500 bytes (50 packets) were received by UID_BLUE
- // over VPN2.
- // VPN1 sent 1650 bytes (150 packets), and received 3300 (300 packets) over TEST_IFACE.
- // Of 1650 bytes sent over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes
- // attributed to UID_BLUE, and 150 bytes attributed to UID_VPN.
- // Of 3300 bytes received over WiFi, expect 2000 bytes attributed to UID_RED, 1000 bytes
- // attributed to UID_BLUE, and 300 bytes attributed to UID_VPN.
- // VPN2 sent 1045 bytes (95 packets), and received 3850 (350 packets) over TEST_IFACE2.
- // Of 1045 bytes sent over Cell, expect 700 bytes attributed to UID_RED, 250 bytes
- // attributed to UID_BLUE, and 95 bytes attributed to UID_VPN.
- // Of 3850 bytes received over Cell, expect 3000 bytes attributed to UID_RED, 500 bytes
- // attributed to UID_BLUE, and 350 bytes attributed to UID_VPN.
- final NetworkStats tunStats =
- parseDetailedStats(R.raw.xt_qtaguid_vpn_one_underlying_two_vpn);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 2000L, 200L, 1000L, 100L);
- assertValues(tunStats, TEST_IFACE, UID_BLUE, 1000L, 100L, 500L, 50L);
- assertValues(tunStats, TEST_IFACE2, UID_RED, 3000L, 300L, 700L, 70L);
- assertValues(tunStats, TEST_IFACE2, UID_BLUE, 500L, 50L, 250L, 25L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 300L, 0L, 150L, 0L);
- assertValues(tunStats, TEST_IFACE2, UID_VPN, 350L, 0L, 95L, 0L);
- }
-
- @Test
- public void testVpnWithTwoUnderlyingIfaces_splitTraffic() throws Exception {
- // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
- // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
- // Additionally, VPN is arbitrarily splitting traffic across WiFi and Cell.
- final UnderlyingNetworkInfo[] underlyingNetworkInfos =
- new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
- mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent, and 500 bytes (50 packets) received by UID_RED over
- // VPN.
- // VPN sent 660 bytes (60 packets) over WiFi and 440 bytes (40 packets) over Cell.
- // And, it received 330 bytes (30 packets) over WiFi and 220 bytes (20 packets) over Cell.
- // For UID_RED, expect 600 bytes attributed over WiFi and 400 bytes over Cell for sent (tx)
- // traffic. For received (rx) traffic, expect 300 bytes over WiFi and 200 bytes over Cell.
- //
- // For UID_VPN, expect 60 bytes attributed over WiFi and 40 bytes over Cell for tx traffic.
- // And, 30 bytes over WiFi and 20 bytes over Cell for rx traffic.
- final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_two_underlying_split);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 300L, 30L, 600L, 60L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 30L, 0L, 60L, 0L);
- assertValues(tunStats, TEST_IFACE2, UID_RED, 200L, 20L, 400L, 40L);
- assertValues(tunStats, TEST_IFACE2, UID_VPN, 20L, 0L, 40L, 0L);
- }
-
- @Test
- public void testVpnWithTwoUnderlyingIfaces_splitTrafficWithCompression() throws Exception {
- // WiFi and Cell networks are connected and VPN is using WiFi (which has TEST_IFACE) and
- // Cell (which has TEST_IFACE2) and has declared both of them in its underlying network set.
- // Additionally, VPN is arbitrarily splitting compressed traffic across WiFi and Cell.
- final UnderlyingNetworkInfo[] underlyingNetworkInfos =
- new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE, TEST_IFACE2})};
- mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface:
- // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
- // VPN sent/received 600 bytes (60 packets) over WiFi and 200 bytes (20 packets) over Cell.
- // For UID_RED, expect 600 bytes attributed over WiFi and 200 bytes over Cell for both
- // rx/tx.
- // UID_VPN gets nothing attributed to it (avoiding negative stats).
- final NetworkStats tunStats =
- parseDetailedStats(R.raw.xt_qtaguid_vpn_two_underlying_split_compression);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 600L, 60L, 600L, 60L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 0L, 0L, 0L, 0L);
- assertValues(tunStats, TEST_IFACE2, UID_RED, 200L, 20L, 200L, 20L);
- assertValues(tunStats, TEST_IFACE2, UID_VPN, 0L, 0L, 0L, 0L);
- }
-
- @Test
- public void testVpnWithIncorrectUnderlyingIface() throws Exception {
- // WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2),
- // but has declared only WiFi (TEST_IFACE) in its underlying network set.
- final UnderlyingNetworkInfo[] underlyingNetworkInfos =
- new UnderlyingNetworkInfo[] {createVpnInfo(new String[] {TEST_IFACE})};
- mFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos);
-
- // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
- // overhead per packet):
- // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
- // VPN sent/received 1100 bytes (100 packets) over Cell.
- // Of 1100 bytes over Cell, expect all of it attributed to UID_VPN for both rx/tx traffic.
- final NetworkStats tunStats = parseDetailedStats(R.raw.xt_qtaguid_vpn_incorrect_iface);
-
- assertValues(tunStats, TEST_IFACE, UID_RED, 0L, 0L, 0L, 0L);
- assertValues(tunStats, TEST_IFACE, UID_VPN, 0L, 0L, 0L, 0L);
- assertValues(tunStats, TEST_IFACE2, UID_RED, 0L, 0L, 0L, 0L);
- assertValues(tunStats, TEST_IFACE2, UID_VPN, 1100L, 100L, 1100L, 100L);
- }
-
- @Test
- public void testKernelTags() throws Exception {
- assertEquals(0, kernelToTag("0x0000000000000000"));
- assertEquals(0x32, kernelToTag("0x0000003200000000"));
- assertEquals(2147483647, kernelToTag("0x7fffffff00000000"));
- assertEquals(0, kernelToTag("0x0000000000000000"));
- assertEquals(2147483136, kernelToTag("0x7FFFFE0000000000"));
-
- assertEquals(0, kernelToTag("0x0"));
- assertEquals(0, kernelToTag("0xf00d"));
- assertEquals(1, kernelToTag("0x100000000"));
- assertEquals(14438007, kernelToTag("0xdc4e7700000000"));
- assertEquals(TrafficStats.TAG_SYSTEM_DOWNLOAD, kernelToTag("0xffffff0100000000"));
- }
-
- @Test
- public void testNetworkStatsWithSet() throws Exception {
- final NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_typical);
- assertEquals(70, stats.size());
- assertStatsEntry(stats, "rmnet1", 10021, SET_DEFAULT, 0x30100000, 219110L, 578L, 227423L,
- 676L);
- assertStatsEntry(stats, "rmnet1", 10021, SET_FOREGROUND, 0x30100000, 742L, 3L, 1265L, 3L);
- }
-
- @Test
- public void testNetworkStatsSingle() throws Exception {
- stageFile(R.raw.xt_qtaguid_iface_typical, file("net/xt_qtaguid/iface_stat_all"));
-
- final NetworkStats stats = mFactory.readNetworkStatsSummaryDev();
- assertEquals(6, stats.size());
- assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 2112L, 24L, 700L, 10L);
- assertStatsEntry(stats, "test1", UID_ALL, SET_ALL, TAG_NONE, 6L, 8L, 10L, 12L);
- assertStatsEntry(stats, "test2", UID_ALL, SET_ALL, TAG_NONE, 1L, 2L, 3L, 4L);
- }
-
- @Test
- public void testNetworkStatsXt() throws Exception {
- stageFile(R.raw.xt_qtaguid_iface_fmt_typical, file("net/xt_qtaguid/iface_stat_fmt"));
-
- final NetworkStats stats = mFactory.readNetworkStatsSummaryXt();
- assertEquals(3, stats.size());
- assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 6824L, 16L, 5692L, 10L);
- assertStatsEntry(stats, "rmnet1", UID_ALL, SET_ALL, TAG_NONE, 11153922L, 8051L, 190226L,
- 2468L);
- assertStatsEntry(stats, "rmnet2", UID_ALL, SET_ALL, TAG_NONE, 4968L, 35L, 3081L, 39L);
- }
-
- @Test
- public void testDoubleClatAccountingSimple() throws Exception {
- mFactory.noteStackedIface("v4-wlan0", "wlan0");
-
- // xt_qtaguid_with_clat_simple is a synthetic file that simulates
- // - 213 received 464xlat packets of size 200 bytes
- // - 41 sent 464xlat packets of size 100 bytes
- // - no other traffic on base interface for root uid.
- NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_simple);
- assertEquals(3, stats.size());
-
- assertStatsEntry(stats, "v4-wlan0", 10060, SET_DEFAULT, 0x0, 46860L, 4920L);
- assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 0L, 0L);
- }
-
- @Test
- public void testDoubleClatAccounting() throws Exception {
- mFactory.noteStackedIface("v4-wlan0", "wlan0");
-
- NetworkStats stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat);
- assertEquals(42, stats.size());
-
- assertStatsEntry(stats, "v4-wlan0", 0, SET_DEFAULT, 0x0, 356L, 276L);
- assertStatsEntry(stats, "v4-wlan0", 1000, SET_DEFAULT, 0x0, 30812L, 2310L);
- assertStatsEntry(stats, "v4-wlan0", 10102, SET_DEFAULT, 0x0, 10022L, 3330L);
- assertStatsEntry(stats, "v4-wlan0", 10060, SET_DEFAULT, 0x0, 9532772L, 254112L);
- assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 0L, 0L);
- assertStatsEntry(stats, "wlan0", 1000, SET_DEFAULT, 0x0, 6126L, 2013L);
- assertStatsEntry(stats, "wlan0", 10013, SET_DEFAULT, 0x0, 0L, 144L);
- assertStatsEntry(stats, "wlan0", 10018, SET_DEFAULT, 0x0, 5980263L, 167667L);
- assertStatsEntry(stats, "wlan0", 10060, SET_DEFAULT, 0x0, 134356L, 8705L);
- assertStatsEntry(stats, "wlan0", 10079, SET_DEFAULT, 0x0, 10926L, 1507L);
- assertStatsEntry(stats, "wlan0", 10102, SET_DEFAULT, 0x0, 25038L, 8245L);
- assertStatsEntry(stats, "wlan0", 10103, SET_DEFAULT, 0x0, 0L, 192L);
- assertStatsEntry(stats, "dummy0", 0, SET_DEFAULT, 0x0, 0L, 168L);
- assertStatsEntry(stats, "lo", 0, SET_DEFAULT, 0x0, 1288L, 1288L);
-
- assertNoStatsEntry(stats, "wlan0", 1029, SET_DEFAULT, 0x0);
- }
-
- @Test
- public void testDoubleClatAccounting100MBDownload() throws Exception {
- // Downloading 100mb from an ipv4 only destination in a foreground activity
-
- long appRxBytesBefore = 328684029L;
- long appRxBytesAfter = 439237478L;
- assertEquals("App traffic should be ~100MB", 110553449, appRxBytesAfter - appRxBytesBefore);
-
- long rootRxBytes = 330187296L;
-
- mFactory.noteStackedIface("v4-wlan0", "wlan0");
- NetworkStats stats;
-
- // Stats snapshot before the download
- stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_100mb_download_before);
- assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesBefore, 5199872L);
- assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytes, 0L);
-
- // Stats snapshot after the download
- stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_100mb_download_after);
- assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesAfter, 7867488L);
- assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytes, 0L);
- }
-
- /**
- * Copy a {@link Resources#openRawResource(int)} into {@link File} for
- * testing purposes.
- */
- private void stageFile(int rawId, File file) throws Exception {
- new File(file.getParent()).mkdirs();
- InputStream in = null;
- OutputStream out = null;
- try {
- in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
- out = new FileOutputStream(file);
- Streams.copy(in, out);
- } finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(out);
- }
- }
-
- private void stageLong(long value, File file) throws Exception {
- new File(file.getParent()).mkdirs();
- FileWriter out = null;
- try {
- out = new FileWriter(file);
- out.write(Long.toString(value));
- } finally {
- IoUtils.closeQuietly(out);
- }
- }
-
- private File file(String path) throws Exception {
- return new File(mTestProc, path);
- }
-
- private NetworkStats parseDetailedStats(int resourceId) throws Exception {
- stageFile(resourceId, file("net/xt_qtaguid/stats"));
- return mFactory.readNetworkStatsDetail();
- }
-
- private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
- int tag, long rxBytes, long txBytes) {
- final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO);
- if (i < 0) {
- fail(String.format("no NetworkStats for (iface: %s, uid: %d, set: %d, tag: %d)",
- iface, uid, set, tag));
- }
- final NetworkStats.Entry entry = stats.getValues(i, null);
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- }
-
- private static void assertNoStatsEntry(NetworkStats stats, String iface, int uid, int set,
- int tag) {
- final int i = stats.findIndex(iface, uid, set, tag, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO);
- if (i >= 0) {
- fail("unexpected NetworkStats entry at " + i);
- }
- }
-
- private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
- int tag, long rxBytes, long rxPackets, long txBytes, long txPackets) {
- assertStatsEntry(stats, iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
- rxBytes, rxPackets, txBytes, txPackets);
- }
-
- private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set,
- int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
- long txBytes, long txPackets) {
- final int i = stats.findIndex(iface, uid, set, tag, metered, roaming, defaultNetwork);
-
- if (i < 0) {
- fail(String.format("no NetworkStats for (iface: %s, uid: %d, set: %d, tag: %d, metered:"
- + " %d, roaming: %d, defaultNetwork: %d)",
- iface, uid, set, tag, metered, roaming, defaultNetwork));
- }
- final NetworkStats.Entry entry = stats.getValues(i, null);
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- assertEquals("unexpected txPackets", txPackets, entry.txPackets);
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java
deleted file mode 100644
index 9fa1c50..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsObserversTest.java
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.NetworkIdentity.OEM_NONE;
-import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
-import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
-import static android.net.NetworkStats.METERED_NO;
-import static android.net.NetworkStats.ROAMING_NO;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkTemplate.buildTemplateMobileAll;
-import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
-import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-
-import android.app.usage.NetworkStatsManager;
-import android.net.DataUsageRequest;
-import android.net.NetworkIdentity;
-import android.net.NetworkStats;
-import android.net.NetworkTemplate;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Messenger;
-import android.os.Process;
-import android.os.UserHandle;
-import android.telephony.TelephonyManager;
-import android.util.ArrayMap;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.net.NetworkStatsServiceTest.LatchedHandler;
-import com.android.testutils.HandlerUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Objects;
-
-/**
- * Tests for {@link NetworkStatsObservers}.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkStatsObserversTest {
- private static final String TEST_IFACE = "test0";
- private static final String TEST_IFACE2 = "test1";
- private static final long TEST_START = 1194220800000L;
-
- private static final String IMSI_1 = "310004";
- private static final String IMSI_2 = "310260";
- private static final String TEST_SSID = "AndroidAP";
-
- private static NetworkTemplate sTemplateWifi = buildTemplateWifiWildcard();
- private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
- private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
-
- private static final int UID_RED = UserHandle.PER_USER_RANGE + 1;
- private static final int UID_BLUE = UserHandle.PER_USER_RANGE + 2;
- private static final int UID_GREEN = UserHandle.PER_USER_RANGE + 3;
- private static final int UID_ANOTHER_USER = 2 * UserHandle.PER_USER_RANGE + 4;
-
- private static final long WAIT_TIMEOUT_MS = 500;
- private static final long THRESHOLD_BYTES = 2 * MB_IN_BYTES;
- private static final long BASE_BYTES = 7 * MB_IN_BYTES;
- private static final int INVALID_TYPE = -1;
-
- private long mElapsedRealtime;
-
- private HandlerThread mObserverHandlerThread;
- private Handler mObserverNoopHandler;
-
- private LatchedHandler mHandler;
-
- private NetworkStatsObservers mStatsObservers;
- private Messenger mMessenger;
- private ArrayMap<String, NetworkIdentitySet> mActiveIfaces;
- private ArrayMap<String, NetworkIdentitySet> mActiveUidIfaces;
-
- @Mock private IBinder mockBinder;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- mObserverHandlerThread = new HandlerThread("HandlerThread");
- mObserverHandlerThread.start();
- final Looper observerLooper = mObserverHandlerThread.getLooper();
- mStatsObservers = new NetworkStatsObservers() {
- @Override
- protected Looper getHandlerLooperLocked() {
- return observerLooper;
- }
- };
-
- mHandler = new LatchedHandler(Looper.getMainLooper(), new ConditionVariable());
- mMessenger = new Messenger(mHandler);
-
- mActiveIfaces = new ArrayMap<>();
- mActiveUidIfaces = new ArrayMap<>();
- }
-
- @Test
- public void testRegister_thresholdTooLow_setsDefaultThreshold() throws Exception {
- long thresholdTooLowBytes = 1L;
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, thresholdTooLowBytes);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateWifi, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
- }
-
- @Test
- public void testRegister_highThreshold_accepted() throws Exception {
- long highThresholdBytes = 2 * THRESHOLD_BYTES;
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, highThresholdBytes);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateWifi, request.template));
- assertEquals(highThresholdBytes, request.thresholdInBytes);
- }
-
- @Test
- public void testRegister_twoRequests_twoIds() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, THRESHOLD_BYTES);
-
- DataUsageRequest request1 = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request1.requestId > 0);
- assertTrue(Objects.equals(sTemplateWifi, request1.template));
- assertEquals(THRESHOLD_BYTES, request1.thresholdInBytes);
-
- DataUsageRequest request2 = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request2.requestId > request1.requestId);
- assertTrue(Objects.equals(sTemplateWifi, request2.template));
- assertEquals(THRESHOLD_BYTES, request2.thresholdInBytes);
- }
-
- @Test
- public void testUnregister_unknownRequest_noop() throws Exception {
- DataUsageRequest unknownRequest = new DataUsageRequest(
- 123456 /* id */, sTemplateWifi, THRESHOLD_BYTES);
-
- mStatsObservers.unregister(unknownRequest, UID_RED);
- }
-
- @Test
- public void testUnregister_knownRequest_releasesCaller() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
- Mockito.verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
-
- mStatsObservers.unregister(request, Process.SYSTEM_UID);
- waitForObserverToIdle();
-
- Mockito.verify(mockBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
- }
-
- @Test
- public void testUnregister_knownRequest_invalidUid_doesNotUnregister() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- UID_RED, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
- Mockito.verify(mockBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
-
- mStatsObservers.unregister(request, UID_BLUE);
- waitForObserverToIdle();
-
- Mockito.verifyZeroInteractions(mockBinder);
- }
-
- private NetworkIdentitySet makeTestIdentSet() {
- NetworkIdentitySet identSet = new NetworkIdentitySet();
- identSet.add(new NetworkIdentity(
- TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- IMSI_1, null /* networkId */, false /* roaming */, true /* metered */,
- true /* defaultNetwork */, OEM_NONE));
- return identSet;
- }
-
- @Test
- public void testUpdateStats_initialSample_doesNotNotify() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-
- NetworkIdentitySet identSet = makeTestIdentSet();
- mActiveIfaces.put(TEST_IFACE, identSet);
-
- // Baseline
- NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
- .insertEntry(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
- NetworkStats uidSnapshot = null;
-
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
- waitForObserverToIdle();
- }
-
- @Test
- public void testUpdateStats_belowThreshold_doesNotNotify() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-
- NetworkIdentitySet identSet = makeTestIdentSet();
- mActiveIfaces.put(TEST_IFACE, identSet);
-
- // Baseline
- NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
- .insertEntry(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
- NetworkStats uidSnapshot = null;
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
-
- // Delta
- xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
- .insertEntry(TEST_IFACE, BASE_BYTES + 1024L, 10L, BASE_BYTES + 2048L, 20L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
- waitForObserverToIdle();
- }
-
-
- @Test
- public void testUpdateStats_deviceAccess_notifies() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- Process.SYSTEM_UID, NetworkStatsAccess.Level.DEVICE);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-
- NetworkIdentitySet identSet = makeTestIdentSet();
- mActiveIfaces.put(TEST_IFACE, identSet);
-
- // Baseline
- NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */)
- .insertEntry(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L);
- NetworkStats uidSnapshot = null;
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
-
- // Delta
- xtSnapshot = new NetworkStats(TEST_START + MINUTE_IN_MILLIS, 1 /* initialSize */)
- .insertEntry(TEST_IFACE, BASE_BYTES + THRESHOLD_BYTES, 12L,
- BASE_BYTES + THRESHOLD_BYTES, 22L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
- waitForObserverToIdle();
- assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.lastMessageType);
- }
-
- @Test
- public void testUpdateStats_defaultAccess_notifiesSameUid() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- UID_RED, NetworkStatsAccess.Level.DEFAULT);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-
- NetworkIdentitySet identSet = makeTestIdentSet();
- mActiveUidIfaces.put(TEST_IFACE, identSet);
-
- // Baseline
- NetworkStats xtSnapshot = null;
- NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
-
- // Delta
- uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
- BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
- waitForObserverToIdle();
- assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.lastMessageType);
- }
-
- @Test
- public void testUpdateStats_defaultAccess_usageOtherUid_doesNotNotify() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- UID_BLUE, NetworkStatsAccess.Level.DEFAULT);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-
- NetworkIdentitySet identSet = makeTestIdentSet();
- mActiveUidIfaces.put(TEST_IFACE, identSet);
-
- // Baseline
- NetworkStats xtSnapshot = null;
- NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
-
- // Delta
- uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
- BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
- waitForObserverToIdle();
- }
-
- @Test
- public void testUpdateStats_userAccess_usageSameUser_notifies() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- UID_BLUE, NetworkStatsAccess.Level.USER);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-
- NetworkIdentitySet identSet = makeTestIdentSet();
- mActiveUidIfaces.put(TEST_IFACE, identSet);
-
- // Baseline
- NetworkStats xtSnapshot = null;
- NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
-
- // Delta
- uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, BASE_BYTES + THRESHOLD_BYTES, 2L,
- BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
- waitForObserverToIdle();
- assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, mHandler.lastMessageType);
- }
-
- @Test
- public void testUpdateStats_userAccess_usageAnotherUser_doesNotNotify() throws Exception {
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateImsi1, THRESHOLD_BYTES);
-
- DataUsageRequest request = mStatsObservers.register(inputRequest, mMessenger, mockBinder,
- UID_RED, NetworkStatsAccess.Level.USER);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateImsi1, request.template));
- assertEquals(THRESHOLD_BYTES, request.thresholdInBytes);
-
- NetworkIdentitySet identSet = makeTestIdentSet();
- mActiveUidIfaces.put(TEST_IFACE, identSet);
-
- // Baseline
- NetworkStats xtSnapshot = null;
- NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */)
- .insertEntry(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
-
- // Delta
- uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */)
- .insertEntry(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L,
- BASE_BYTES + THRESHOLD_BYTES, 2L, 0L);
- mStatsObservers.updateStats(
- xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START);
- waitForObserverToIdle();
- }
-
- private void waitForObserverToIdle() {
- HandlerUtils.waitForIdle(mObserverHandlerThread, WAIT_TIMEOUT_MS);
- HandlerUtils.waitForIdle(mHandler, WAIT_TIMEOUT_MS);
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
deleted file mode 100644
index c32c1d2..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ /dev/null
@@ -1,1812 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import static android.content.Intent.ACTION_UID_REMOVED;
-import static android.content.Intent.EXTRA_UID;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.NetworkIdentity.OEM_PAID;
-import static android.net.NetworkIdentity.OEM_PRIVATE;
-import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
-import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
-import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
-import static android.net.NetworkStats.IFACE_ALL;
-import static android.net.NetworkStats.INTERFACES_ALL;
-import static android.net.NetworkStats.METERED_ALL;
-import static android.net.NetworkStats.METERED_NO;
-import static android.net.NetworkStats.METERED_YES;
-import static android.net.NetworkStats.ROAMING_ALL;
-import static android.net.NetworkStats.ROAMING_NO;
-import static android.net.NetworkStats.ROAMING_YES;
-import static android.net.NetworkStats.SET_ALL;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.SET_FOREGROUND;
-import static android.net.NetworkStats.STATS_PER_UID;
-import static android.net.NetworkStats.TAG_ALL;
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkStatsHistory.FIELD_ALL;
-import static android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD;
-import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
-import static android.net.NetworkTemplate.OEM_MANAGED_NO;
-import static android.net.NetworkTemplate.OEM_MANAGED_YES;
-import static android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT;
-import static android.net.NetworkTemplate.buildTemplateMobileAll;
-import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
-import static android.net.NetworkTemplate.buildTemplateWifi;
-import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
-import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.net.TrafficStats.UID_REMOVED;
-import static android.net.TrafficStats.UID_TETHERING;
-import static android.text.format.DateUtils.DAY_IN_MILLIS;
-import static android.text.format.DateUtils.HOUR_IN_MILLIS;
-import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-import static android.text.format.DateUtils.WEEK_IN_MILLIS;
-
-import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.app.AlarmManager;
-import android.app.usage.NetworkStatsManager;
-import android.content.Context;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.net.DataUsageRequest;
-import android.net.INetworkManagementEventObserver;
-import android.net.INetworkStatsSession;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkStateSnapshot;
-import android.net.NetworkStats;
-import android.net.NetworkStatsHistory;
-import android.net.NetworkTemplate;
-import android.net.TelephonyNetworkSpecifier;
-import android.net.UnderlyingNetworkInfo;
-import android.net.netstats.provider.INetworkStatsProviderCallback;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.INetworkManagementService;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.PowerManager;
-import android.os.SimpleClock;
-import android.provider.Settings;
-import android.telephony.TelephonyManager;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.test.BroadcastInterceptingContext;
-import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
-import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
-import com.android.testutils.HandlerUtils;
-import com.android.testutils.TestableNetworkStatsProviderBinder;
-
-import libcore.io.IoUtils;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.File;
-import java.time.Clock;
-import java.time.ZoneOffset;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-
-/**
- * Tests for {@link NetworkStatsService}.
- *
- * TODO: This test used to be really brittle because it used Easymock - it uses Mockito now, but
- * still uses the Easymock structure, which could be simplified.
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
- private static final String TAG = "NetworkStatsServiceTest";
-
- private static final long TEST_START = 1194220800000L;
-
- private static final String IMSI_1 = "310004";
- private static final String IMSI_2 = "310260";
- private static final String TEST_SSID = "AndroidAP";
-
- private static NetworkTemplate sTemplateWifi = buildTemplateWifi(TEST_SSID);
- private static NetworkTemplate sTemplateCarrierWifi1 =
- buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL, IMSI_1);
- private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
- private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
-
- private static final Network WIFI_NETWORK = new Network(100);
- private static final Network MOBILE_NETWORK = new Network(101);
- private static final Network VPN_NETWORK = new Network(102);
-
- private static final Network[] NETWORKS_WIFI = new Network[]{ WIFI_NETWORK };
- private static final Network[] NETWORKS_MOBILE = new Network[]{ MOBILE_NETWORK };
-
- private static final long WAIT_TIMEOUT = 2 * 1000; // 2 secs
- private static final int INVALID_TYPE = -1;
-
- private long mElapsedRealtime;
-
- private File mStatsDir;
- private MockContext mServiceContext;
- private @Mock TelephonyManager mTelephonyManager;
- private @Mock INetworkManagementService mNetManager;
- private @Mock NetworkStatsFactory mStatsFactory;
- private @Mock NetworkStatsSettings mSettings;
- private @Mock IBinder mBinder;
- private @Mock AlarmManager mAlarmManager;
- @Mock
- private NetworkStatsSubscriptionsMonitor mNetworkStatsSubscriptionsMonitor;
- private HandlerThread mHandlerThread;
-
- private NetworkStatsService mService;
- private INetworkStatsSession mSession;
- private INetworkManagementEventObserver mNetworkObserver;
- private ContentObserver mContentObserver;
- private Handler mHandler;
-
- private class MockContext extends BroadcastInterceptingContext {
- private final Context mBaseContext;
-
- MockContext(Context base) {
- super(base);
- mBaseContext = base;
- }
-
- @Override
- public Object getSystemService(String name) {
- if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
- return mBaseContext.getSystemService(name);
- }
- }
-
- private final Clock mClock = new SimpleClock(ZoneOffset.UTC) {
- @Override
- public long millis() {
- return currentTimeMillis();
- }
- };
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- final Context context = InstrumentationRegistry.getContext();
- mServiceContext = new MockContext(context);
- mStatsDir = context.getFilesDir();
- if (mStatsDir.exists()) {
- IoUtils.deleteContents(mStatsDir);
- }
-
- PowerManager powerManager = (PowerManager) mServiceContext.getSystemService(
- Context.POWER_SERVICE);
- PowerManager.WakeLock wakeLock =
- powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-
- mHandlerThread = new HandlerThread("HandlerThread");
- final NetworkStatsService.Dependencies deps = makeDependencies();
- mService = new NetworkStatsService(mServiceContext, mNetManager, mAlarmManager, wakeLock,
- mClock, mSettings, mStatsFactory, new NetworkStatsObservers(), mStatsDir,
- getBaseDir(mStatsDir), deps);
-
- mElapsedRealtime = 0L;
-
- expectDefaultSettings();
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectSystemReady();
- mService.systemReady();
- // Verify that system ready fetches realtime stats
- verify(mStatsFactory).readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL);
- // Wait for posting onChange() event to handler thread and verify that when system ready,
- // start monitoring data usage per RAT type because the settings value is mock as false
- // by default in expectSettings().
- waitForIdle();
- verify(mNetworkStatsSubscriptionsMonitor).start();
- reset(mNetworkStatsSubscriptionsMonitor);
-
- doReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS).when(mTelephonyManager)
- .checkCarrierPrivilegesForPackageAnyPhone(anyString());
-
- mSession = mService.openSession();
- assertNotNull("openSession() failed", mSession);
-
- // catch INetworkManagementEventObserver during systemReady()
- ArgumentCaptor<INetworkManagementEventObserver> networkObserver =
- ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
- verify(mNetManager).registerObserver(networkObserver.capture());
- mNetworkObserver = networkObserver.getValue();
- }
-
- @NonNull
- private NetworkStatsService.Dependencies makeDependencies() {
- return new NetworkStatsService.Dependencies() {
- @Override
- public HandlerThread makeHandlerThread() {
- return mHandlerThread;
- }
-
- @Override
- public NetworkStatsSubscriptionsMonitor makeSubscriptionsMonitor(
- @NonNull Context context, @NonNull Looper looper, @NonNull Executor executor,
- @NonNull NetworkStatsService service) {
-
- return mNetworkStatsSubscriptionsMonitor;
- }
-
- @Override
- public ContentObserver makeContentObserver(Handler handler,
- NetworkStatsSettings settings, NetworkStatsSubscriptionsMonitor monitor) {
- mHandler = handler;
- return mContentObserver = super.makeContentObserver(handler, settings, monitor);
- }
-
- };
- }
-
- @After
- public void tearDown() throws Exception {
- IoUtils.deleteContents(mStatsDir);
-
- mServiceContext = null;
- mStatsDir = null;
-
- mNetManager = null;
- mSettings = null;
-
- mSession.close();
- mService = null;
-
- mHandlerThread.quitSafely();
- }
-
- private void initWifiStats(NetworkStateSnapshot snapshot) throws Exception {
- // pretend that wifi network comes online; service should ask about full
- // network state, and poll any existing interfaces before updating.
- expectDefaultSettings();
- NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {snapshot};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
- }
-
- private void incrementWifiStats(long durationMillis, String iface,
- long rxb, long rxp, long txb, long txp) throws Exception {
- incrementCurrentTime(durationMillis);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(iface, rxb, rxp, txb, txp));
- expectNetworkStatsUidDetail(buildEmptyStats());
- forcePollAndWaitForIdle();
- }
-
- @Test
- public void testNetworkStatsCarrierWifi() throws Exception {
- initWifiStats(buildWifiState(true, TEST_IFACE, IMSI_1));
- // verify service has empty history for carrier merged wifi and non-carrier wifi
- assertNetworkTotal(sTemplateCarrierWifi1, 0L, 0L, 0L, 0L, 0);
- assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
-
- // modify some number on wifi, and trigger poll event
- incrementWifiStats(HOUR_IN_MILLIS, TEST_IFACE, 1024L, 1L, 2048L, 2L);
-
- // verify service recorded history
- assertNetworkTotal(sTemplateCarrierWifi1, 1024L, 1L, 2048L, 2L, 0);
-
- // verify service recorded history for wifi with SSID filter
- assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0);
-
-
- // and bump forward again, with counters going higher. this is
- // important, since polling should correctly subtract last snapshot.
- incrementWifiStats(DAY_IN_MILLIS, TEST_IFACE, 4096L, 4L, 8192L, 8L);
-
- // verify service recorded history
- assertNetworkTotal(sTemplateCarrierWifi1, 4096L, 4L, 8192L, 8L, 0);
- // verify service recorded history for wifi with SSID filter
- assertNetworkTotal(sTemplateWifi, 4096L, 4L, 8192L, 8L, 0);
- }
-
- @Test
- public void testNetworkStatsNonCarrierWifi() throws Exception {
- initWifiStats(buildWifiState());
-
- // verify service has empty history for wifi
- assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
- // verify service has empty history for carrier merged wifi
- assertNetworkTotal(sTemplateCarrierWifi1, 0L, 0L, 0L, 0L, 0);
-
- // modify some number on wifi, and trigger poll event
- incrementWifiStats(HOUR_IN_MILLIS, TEST_IFACE, 1024L, 1L, 2048L, 2L);
-
- // verify service recorded history
- assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0);
- // verify service has empty history for carrier wifi since current network is non carrier
- // wifi
- assertNetworkTotal(sTemplateCarrierWifi1, 0L, 0L, 0L, 0L, 0);
-
- // and bump forward again, with counters going higher. this is
- // important, since polling should correctly subtract last snapshot.
- incrementWifiStats(DAY_IN_MILLIS, TEST_IFACE, 4096L, 4L, 8192L, 8L);
-
- // verify service recorded history
- assertNetworkTotal(sTemplateWifi, 4096L, 4L, 8192L, 8L, 0);
- // verify service has empty history for carrier wifi since current network is non carrier
- // wifi
- assertNetworkTotal(sTemplateCarrierWifi1, 0L, 0L, 0L, 0L, 0);
- }
-
- @Test
- public void testStatsRebootPersist() throws Exception {
- assertStatsFilesExist(false);
-
- // pretend that wifi network comes online; service should ask about full
- // network state, and poll any existing interfaces before updating.
- expectDefaultSettings();
- NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // verify service has empty history for wifi
- assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
-
-
- // modify some number on wifi, and trigger poll event
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 1024L, 8L, 2048L, 16L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L));
- mService.setUidForeground(UID_RED, false);
- mService.incrementOperationCount(UID_RED, 0xFAAD, 4);
- mService.setUidForeground(UID_RED, true);
- mService.incrementOperationCount(UID_RED, 0xFAAD, 6);
-
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
- assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10);
- assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 512L, 4L, 256L, 2L, 4);
- assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 512L, 4L, 256L, 2L, 6);
- assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
-
-
- // graceful shutdown system, which should trigger persist of stats, and
- // clear any values in memory.
- expectDefaultSettings();
- mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN));
- assertStatsFilesExist(true);
-
- // boot through serviceReady() again
- expectDefaultSettings();
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectSystemReady();
-
- mService.systemReady();
-
- // after systemReady(), we should have historical stats loaded again
- assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0);
- assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10);
- assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 512L, 4L, 256L, 2L, 4);
- assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 512L, 4L, 256L, 2L, 6);
- assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0);
-
- }
-
- // TODO: simulate reboot to test bucket resize
- @Test
- @Ignore
- public void testStatsBucketResize() throws Exception {
- NetworkStatsHistory history = null;
-
- assertStatsFilesExist(false);
-
- // pretend that wifi network comes online; service should ask about full
- // network state, and poll any existing interfaces before updating.
- expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
- NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // modify some number on wifi, and trigger poll event
- incrementCurrentTime(2 * HOUR_IN_MILLIS);
- expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 512L, 4L, 512L, 4L));
- expectNetworkStatsUidDetail(buildEmptyStats());
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- history = mSession.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
- assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
- assertEquals(HOUR_IN_MILLIS, history.getBucketDuration());
- assertEquals(2, history.size());
-
-
- // now change bucket duration setting and trigger another poll with
- // exact same values, which should resize existing buckets.
- expectSettings(0L, 30 * MINUTE_IN_MILLIS, WEEK_IN_MILLIS);
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
- forcePollAndWaitForIdle();
-
- // verify identical stats, but spread across 4 buckets now
- history = mSession.getHistoryForNetwork(sTemplateWifi, FIELD_ALL);
- assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0);
- assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration());
- assertEquals(4, history.size());
-
- }
-
- @Test
- public void testUidStatsAcrossNetworks() throws Exception {
- // pretend first mobile network comes online
- expectDefaultSettings();
- NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildMobile3gState(IMSI_1)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // create some traffic on first network
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 2048L, 16L, 512L, 4L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
- mService.incrementOperationCount(UID_RED, 0xF00D, 10);
-
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
- assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
- assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 512L, 4L, 10);
- assertUidTotal(sTemplateImsi1, UID_BLUE, 512L, 4L, 0L, 0L, 0);
-
-
- // now switch networks; this also tests that we're okay with interfaces
- // disappearing, to verify we don't count backwards.
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- states = new NetworkStateSnapshot[] {buildMobile3gState(IMSI_2)};
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 2048L, 16L, 512L, 4L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
-
- mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
- forcePollAndWaitForIdle();
-
-
- // create traffic on second network
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 2176L, 17L, 1536L, 12L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L));
- mService.incrementOperationCount(UID_BLUE, 0xFAAD, 10);
-
- forcePollAndWaitForIdle();
-
- // verify original history still intact
- assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
- assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 512L, 4L, 10);
- assertUidTotal(sTemplateImsi1, UID_BLUE, 512L, 4L, 0L, 0L, 0);
-
- // and verify new history also recorded under different template, which
- // verifies that we didn't cross the streams.
- assertNetworkTotal(sTemplateImsi2, 128L, 1L, 1024L, 8L, 0);
- assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
- assertUidTotal(sTemplateImsi2, UID_BLUE, 128L, 1L, 1024L, 8L, 10);
-
- }
-
- @Test
- public void testUidRemovedIsMoved() throws Exception {
- // pretend that network comes online
- expectDefaultSettings();
- NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // create some traffic
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 4128L, 258L, 544L, 34L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE,
- 4096L, 258L, 512L, 32L, 0L)
- .insertEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
- mService.incrementOperationCount(UID_RED, 0xFAAD, 10);
-
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertNetworkTotal(sTemplateWifi, 4128L, 258L, 544L, 34L, 0);
- assertUidTotal(sTemplateWifi, UID_RED, 16L, 1L, 16L, 1L, 10);
- assertUidTotal(sTemplateWifi, UID_BLUE, 4096L, 258L, 512L, 32L, 0);
- assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 1L, 16L, 1L, 0);
-
-
- // now pretend two UIDs are uninstalled, which should migrate stats to
- // special "removed" bucket.
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 4128L, 258L, 544L, 34L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE,
- 4096L, 258L, 512L, 32L, 0L)
- .insertEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L));
- final Intent intent = new Intent(ACTION_UID_REMOVED);
- intent.putExtra(EXTRA_UID, UID_BLUE);
- mServiceContext.sendBroadcast(intent);
- intent.putExtra(EXTRA_UID, UID_RED);
- mServiceContext.sendBroadcast(intent);
-
- // existing uid and total should remain unchanged; but removed UID
- // should be gone completely.
- assertNetworkTotal(sTemplateWifi, 4128L, 258L, 544L, 34L, 0);
- assertUidTotal(sTemplateWifi, UID_RED, 0L, 0L, 0L, 0L, 0);
- assertUidTotal(sTemplateWifi, UID_BLUE, 0L, 0L, 0L, 0L, 0);
- assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 1L, 16L, 1L, 0);
- assertUidTotal(sTemplateWifi, UID_REMOVED, 4112L, 259L, 528L, 33L, 10);
-
- }
-
- @Test
- public void testMobileStatsByRatType() throws Exception {
- final NetworkTemplate template3g =
- buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS);
- final NetworkTemplate template4g =
- buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_LTE);
- final NetworkTemplate template5g =
- buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_NR);
- final NetworkStateSnapshot[] states =
- new NetworkStateSnapshot[]{buildMobile3gState(IMSI_1)};
-
- // 3G network comes online.
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
- mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // Create some traffic.
- incrementCurrentTime(MINUTE_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 12L, 18L, 14L, 1L, 0L)));
- forcePollAndWaitForIdle();
-
- // Verify 3g templates gets stats.
- assertUidTotal(sTemplateImsi1, UID_RED, 12L, 18L, 14L, 1L, 0);
- assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0);
- assertUidTotal(template4g, UID_RED, 0L, 0L, 0L, 0L, 0);
- assertUidTotal(template5g, UID_RED, 0L, 0L, 0L, 0L, 0);
-
- // 4G network comes online.
- incrementCurrentTime(MINUTE_IN_MILLIS);
- setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_LTE);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- // Append more traffic on existing 3g stats entry.
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 16L, 22L, 17L, 2L, 0L))
- // Add entry that is new on 4g.
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
- 33L, 27L, 8L, 10L, 1L)));
- forcePollAndWaitForIdle();
-
- // Verify ALL_MOBILE template gets all. 3g template counters do not increase.
- assertUidTotal(sTemplateImsi1, UID_RED, 49L, 49L, 25L, 12L, 1);
- assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0);
- // Verify 4g template counts appended stats on existing entry and newly created entry.
- assertUidTotal(template4g, UID_RED, 4L + 33L, 4L + 27L, 3L + 8L, 1L + 10L, 1);
- // Verify 5g template doesn't get anything since no traffic is generated on 5g.
- assertUidTotal(template5g, UID_RED, 0L, 0L, 0L, 0L, 0);
-
- // 5g network comes online.
- incrementCurrentTime(MINUTE_IN_MILLIS);
- setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_NR);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- // Existing stats remains.
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 16L, 22L, 17L, 2L, 0L))
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
- 33L, 27L, 8L, 10L, 1L))
- // Add some traffic on 5g.
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 5L, 13L, 31L, 9L, 2L)));
- forcePollAndWaitForIdle();
-
- // Verify ALL_MOBILE template gets all.
- assertUidTotal(sTemplateImsi1, UID_RED, 54L, 62L, 56L, 21L, 3);
- // 3g/4g template counters do not increase.
- assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0);
- assertUidTotal(template4g, UID_RED, 4L + 33L, 4L + 27L, 3L + 8L, 1L + 10L, 1);
- // Verify 5g template gets the 5g count.
- assertUidTotal(template5g, UID_RED, 5L, 13L, 31L, 9L, 2);
- }
-
- @Test
- public void testMobileStatsOemManaged() throws Exception {
- final NetworkTemplate templateOemPaid = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
- /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PAID,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
-
- final NetworkTemplate templateOemPrivate = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
- /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PRIVATE,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
-
- final NetworkTemplate templateOemAll = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
- /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
- OEM_PAID | OEM_PRIVATE, SUBSCRIBER_ID_MATCH_RULE_EXACT);
-
- final NetworkTemplate templateOemYes = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
- /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_YES,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
-
- final NetworkTemplate templateOemNone = new NetworkTemplate(MATCH_MOBILE_WILDCARD,
- /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null,
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_NO,
- SUBSCRIBER_ID_MATCH_RULE_EXACT);
-
- // OEM_PAID network comes online.
- NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
- buildOemManagedMobileState(IMSI_1, false,
- new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PAID})};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
- mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // Create some traffic.
- incrementCurrentTime(MINUTE_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 36L, 41L, 24L, 96L, 0L)));
- forcePollAndWaitForIdle();
-
- // OEM_PRIVATE network comes online.
- states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false,
- new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE})};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
- mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // Create some traffic.
- incrementCurrentTime(MINUTE_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 49L, 71L, 72L, 48L, 0L)));
- forcePollAndWaitForIdle();
-
- // OEM_PAID + OEM_PRIVATE network comes online.
- states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false,
- new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE,
- NetworkCapabilities.NET_CAPABILITY_OEM_PAID})};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
- mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // Create some traffic.
- incrementCurrentTime(MINUTE_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 57L, 86L, 83L, 93L, 0L)));
- forcePollAndWaitForIdle();
-
- // OEM_NONE network comes online.
- states = new NetworkStateSnapshot[]{buildOemManagedMobileState(IMSI_1, false, new int[]{})};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
- mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // Create some traffic.
- incrementCurrentTime(MINUTE_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 29L, 73L, 34L, 31L, 0L)));
- forcePollAndWaitForIdle();
-
- // Verify OEM_PAID template gets only relevant stats.
- assertUidTotal(templateOemPaid, UID_RED, 36L, 41L, 24L, 96L, 0);
-
- // Verify OEM_PRIVATE template gets only relevant stats.
- assertUidTotal(templateOemPrivate, UID_RED, 49L, 71L, 72L, 48L, 0);
-
- // Verify OEM_PAID + OEM_PRIVATE template gets only relevant stats.
- assertUidTotal(templateOemAll, UID_RED, 57L, 86L, 83L, 93L, 0);
-
- // Verify OEM_NONE sees only non-OEM managed stats.
- assertUidTotal(templateOemNone, UID_RED, 29L, 73L, 34L, 31L, 0);
-
- // Verify OEM_MANAGED_YES sees all OEM managed stats.
- assertUidTotal(templateOemYes, UID_RED,
- 36L + 49L + 57L,
- 41L + 71L + 86L,
- 24L + 72L + 83L,
- 96L + 48L + 93L, 0);
-
- // Verify ALL_MOBILE template gets both OEM managed and non-OEM managed stats.
- assertUidTotal(sTemplateImsi1, UID_RED,
- 36L + 49L + 57L + 29L,
- 41L + 71L + 86L + 73L,
- 24L + 72L + 83L + 34L,
- 96L + 48L + 93L + 31L, 0);
- }
-
- // TODO: support per IMSI state
- private void setMobileRatTypeAndWaitForIdle(int ratType) {
- when(mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(anyString()))
- .thenReturn(ratType);
- mService.handleOnCollapsedRatTypeChanged();
- HandlerUtils.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
- }
-
- @Test
- public void testSummaryForAllUid() throws Exception {
- // pretend that network comes online
- expectDefaultSettings();
- NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // create some traffic for two apps
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L));
- mService.incrementOperationCount(UID_RED, 0xF00D, 1);
-
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertUidTotal(sTemplateWifi, UID_RED, 50L, 5L, 50L, 5L, 1);
- assertUidTotal(sTemplateWifi, UID_BLUE, 1024L, 8L, 512L, 4L, 0);
-
-
- // now create more traffic in next hour, but only for one app
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE,
- 2048L, 16L, 1024L, 8L, 0L));
- forcePollAndWaitForIdle();
-
- // first verify entire history present
- NetworkStats stats = mSession.getSummaryForAllUid(
- sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
- assertEquals(3, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 50L, 5L, 50L, 5L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 10L, 1L, 10L, 1L, 1);
- assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 2048L, 16L, 1024L, 8L, 0);
-
- // now verify that recent history only contains one uid
- final long currentTime = currentTimeMillis();
- stats = mSession.getSummaryForAllUid(
- sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true);
- assertEquals(1, stats.size());
- assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1024L, 8L, 512L, 4L, 0);
- }
-
- @Test
- public void testDetailedUidStats() throws Exception {
- // pretend that network comes online
- expectDefaultSettings();
- NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- NetworkStats.Entry entry1 = new NetworkStats.Entry(
- TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L);
- NetworkStats.Entry entry2 = new NetworkStats.Entry(
- TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 50L, 5L, 50L, 5L, 0L);
- NetworkStats.Entry entry3 = new NetworkStats.Entry(
- TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xBEEF, 1024L, 8L, 512L, 4L, 0L);
-
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
- .insertEntry(entry1)
- .insertEntry(entry2)
- .insertEntry(entry3));
- mService.incrementOperationCount(UID_RED, 0xF00D, 1);
-
- NetworkStats stats = mService.getDetailedUidStats(INTERFACES_ALL);
-
- assertEquals(3, stats.size());
- entry1.operations = 1;
- assertEquals(entry1, stats.getValues(0, null));
- entry2.operations = 1;
- assertEquals(entry2, stats.getValues(1, null));
- assertEquals(entry3, stats.getValues(2, null));
- }
-
- @Test
- public void testDetailedUidStats_Filtered() throws Exception {
- // pretend that network comes online
- expectDefaultSettings();
-
- final String stackedIface = "stacked-test0";
- final LinkProperties stackedProp = new LinkProperties();
- stackedProp.setInterfaceName(stackedIface);
- final NetworkStateSnapshot wifiState = buildWifiState();
- wifiState.getLinkProperties().addStackedLink(stackedProp);
- NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {wifiState};
-
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- NetworkStats.Entry uidStats = new NetworkStats.Entry(
- TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
- // Stacked on matching interface
- NetworkStats.Entry tetheredStats1 = new NetworkStats.Entry(
- stackedIface, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
- // Different interface
- NetworkStats.Entry tetheredStats2 = new NetworkStats.Entry(
- "otherif", UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
-
- final String[] ifaceFilter = new String[] { TEST_IFACE };
- final String[] augmentedIfaceFilter = new String[] { stackedIface, TEST_IFACE };
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- when(mStatsFactory.augmentWithStackedInterfaces(eq(ifaceFilter)))
- .thenReturn(augmentedIfaceFilter);
- when(mStatsFactory.readNetworkStatsDetail(eq(UID_ALL), any(), eq(TAG_ALL)))
- .thenReturn(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(uidStats));
- when(mNetManager.getNetworkStatsTethering(STATS_PER_UID))
- .thenReturn(new NetworkStats(getElapsedRealtime(), 2)
- .insertEntry(tetheredStats1)
- .insertEntry(tetheredStats2));
-
- NetworkStats stats = mService.getDetailedUidStats(ifaceFilter);
-
- // mStatsFactory#readNetworkStatsDetail() has the following invocations:
- // 1) NetworkStatsService#systemReady from #setUp.
- // 2) mService#notifyNetworkStatus in the test above.
- //
- // Additionally, we should have one call from the above call to mService#getDetailedUidStats
- // with the augmented ifaceFilter.
- verify(mStatsFactory, times(2)).readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL);
- verify(mStatsFactory, times(1)).readNetworkStatsDetail(
- eq(UID_ALL),
- eq(augmentedIfaceFilter),
- eq(TAG_ALL));
- assertTrue(ArrayUtils.contains(stats.getUniqueIfaces(), TEST_IFACE));
- assertTrue(ArrayUtils.contains(stats.getUniqueIfaces(), stackedIface));
- assertEquals(2, stats.size());
- assertEquals(uidStats, stats.getValues(0, null));
- assertEquals(tetheredStats1, stats.getValues(1, null));
- }
-
- @Test
- public void testForegroundBackground() throws Exception {
- // pretend that network comes online
- expectDefaultSettings();
- NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // create some initial traffic
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L));
- mService.incrementOperationCount(UID_RED, 0xF00D, 1);
-
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1);
-
-
- // now switch to foreground
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L));
- mService.setUidForeground(UID_RED, true);
- mService.incrementOperationCount(UID_RED, 0xFAAD, 1);
-
- forcePollAndWaitForIdle();
-
- // test that we combined correctly
- assertUidTotal(sTemplateWifi, UID_RED, 160L, 4L, 160L, 4L, 2);
-
- // verify entire history present
- final NetworkStats stats = mSession.getSummaryForAllUid(
- sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
- assertEquals(4, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 32L, 2L, 32L, 2L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1L, 1L, 1L, 1L, 1);
- }
-
- @Test
- public void testMetered() throws Exception {
- // pretend that network comes online
- expectDefaultSettings();
- NetworkStateSnapshot[] states =
- new NetworkStateSnapshot[] {buildWifiState(true /* isMetered */, TEST_IFACE)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // create some initial traffic
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- // Note that all traffic from NetworkManagementService is tagged as METERED_NO, ROAMING_NO
- // and DEFAULT_NETWORK_YES, because these three properties aren't tracked at that layer.
- // We layer them on top by inspecting the iface properties.
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0L));
- mService.incrementOperationCount(UID_RED, 0xF00D, 1);
-
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1);
- // verify entire history present
- final NetworkStats stats = mSession.getSummaryForAllUid(
- sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
- assertEquals(2, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 1);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 1);
- }
-
- @Test
- public void testRoaming() throws Exception {
- // pretend that network comes online
- expectDefaultSettings();
- NetworkStateSnapshot[] states =
- new NetworkStateSnapshot[] {buildMobile3gState(IMSI_1, true /* isRoaming */)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // Create some traffic
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- // Note that all traffic from NetworkManagementService is tagged as METERED_NO and
- // ROAMING_NO, because metered and roaming isn't tracked at that layer. We layer it
- // on top by inspecting the iface properties.
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0L));
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
-
- // verify entire history present
- final NetworkStats stats = mSession.getSummaryForAllUid(
- sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
- assertEquals(2, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_YES,
- DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_YES,
- DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0);
- }
-
- @Test
- public void testTethering() throws Exception {
- // pretend first mobile network comes online
- expectDefaultSettings();
- final NetworkStateSnapshot[] states =
- new NetworkStateSnapshot[]{buildMobile3gState(IMSI_1)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // create some tethering traffic
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
-
- // Register custom provider and retrieve callback.
- final TestableNetworkStatsProviderBinder provider =
- new TestableNetworkStatsProviderBinder();
- final INetworkStatsProviderCallback cb =
- mService.registerNetworkStatsProvider("TEST-TETHERING-OFFLOAD", provider);
- assertNotNull(cb);
- final long now = getElapsedRealtime();
-
- // Traffic seen by kernel counters (includes software tethering).
- final NetworkStats swIfaceStats = new NetworkStats(now, 1)
- .insertEntry(TEST_IFACE, 1536L, 12L, 384L, 3L);
- // Hardware tethering traffic, not seen by kernel counters.
- final NetworkStats tetherHwIfaceStats = new NetworkStats(now, 1)
- .insertEntry(new NetworkStats.Entry(TEST_IFACE, UID_ALL, SET_DEFAULT,
- TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
- 512L, 4L, 128L, 1L, 0L));
- final NetworkStats tetherHwUidStats = new NetworkStats(now, 1)
- .insertEntry(new NetworkStats.Entry(TEST_IFACE, UID_TETHERING, SET_DEFAULT,
- TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
- 512L, 4L, 128L, 1L, 0L));
- cb.notifyStatsUpdated(0 /* unused */, tetherHwIfaceStats, tetherHwUidStats);
-
- // Fake some traffic done by apps on the device (as opposed to tethering), and record it
- // into UID stats (as opposed to iface stats).
- final NetworkStats localUidStats = new NetworkStats(now, 1)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L);
- // Software per-uid tethering traffic.
- final NetworkStats tetherSwUidStats = new NetworkStats(now, 1)
- .insertEntry(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1408L, 10L, 256L, 1L,
- 0L);
-
- expectNetworkStatsSummary(swIfaceStats);
- expectNetworkStatsUidDetail(localUidStats, tetherSwUidStats);
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
- assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
- assertUidTotal(sTemplateImsi1, UID_TETHERING, 1920L, 14L, 384L, 2L, 0);
- }
-
- @Test
- public void testRegisterUsageCallback() throws Exception {
- // pretend that wifi network comes online; service should ask about full
- // network state, and poll any existing interfaces before updating.
- expectDefaultSettings();
- NetworkStateSnapshot[] states = new NetworkStateSnapshot[] {buildWifiState()};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // verify service has empty history for wifi
- assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
- long thresholdInBytes = 1L; // very small; should be overriden by framework
- DataUsageRequest inputRequest = new DataUsageRequest(
- DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, thresholdInBytes);
-
- // Create a messenger that waits for callback activity
- ConditionVariable cv = new ConditionVariable(false);
- LatchedHandler latchedHandler = new LatchedHandler(Looper.getMainLooper(), cv);
- Messenger messenger = new Messenger(latchedHandler);
-
- // Force poll
- expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- // Register and verify request and that binder was called
- DataUsageRequest request =
- mService.registerUsageCallback(mServiceContext.getOpPackageName(), inputRequest,
- messenger, mBinder);
- assertTrue(request.requestId > 0);
- assertTrue(Objects.equals(sTemplateWifi, request.template));
- long minThresholdInBytes = 2 * 1024 * 1024; // 2 MB
- assertEquals(minThresholdInBytes, request.thresholdInBytes);
-
- HandlerUtils.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
-
- // Make sure that the caller binder gets connected
- verify(mBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
-
- // modify some number on wifi, and trigger poll event
- // not enough traffic to call data usage callback
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 1024L, 1L, 2048L, 2L));
- expectNetworkStatsUidDetail(buildEmptyStats());
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0);
-
- // make sure callback has not being called
- assertEquals(INVALID_TYPE, latchedHandler.lastMessageType);
-
- // and bump forward again, with counters going higher. this is
- // important, since it will trigger the data usage callback
- incrementCurrentTime(DAY_IN_MILLIS);
- expectDefaultSettings();
- expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 4096000L, 4L, 8192000L, 8L));
- expectNetworkStatsUidDetail(buildEmptyStats());
- forcePollAndWaitForIdle();
-
- // verify service recorded history
- assertNetworkTotal(sTemplateWifi, 4096000L, 4L, 8192000L, 8L, 0);
-
-
- // Wait for the caller to ack receipt of CALLBACK_LIMIT_REACHED
- assertTrue(cv.block(WAIT_TIMEOUT));
- assertEquals(NetworkStatsManager.CALLBACK_LIMIT_REACHED, latchedHandler.lastMessageType);
- cv.close();
-
- // Allow binder to disconnect
- when(mBinder.unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt())).thenReturn(true);
-
- // Unregister request
- mService.unregisterUsageRequest(request);
-
- // Wait for the caller to ack receipt of CALLBACK_RELEASED
- assertTrue(cv.block(WAIT_TIMEOUT));
- assertEquals(NetworkStatsManager.CALLBACK_RELEASED, latchedHandler.lastMessageType);
-
- // Make sure that the caller binder gets disconnected
- verify(mBinder).unlinkToDeath(any(IBinder.DeathRecipient.class), anyInt());
- }
-
- @Test
- public void testUnregisterUsageCallback_unknown_noop() throws Exception {
- String callingPackage = "the.calling.package";
- long thresholdInBytes = 10 * 1024 * 1024; // 10 MB
- DataUsageRequest unknownRequest = new DataUsageRequest(
- 2 /* requestId */, sTemplateImsi1, thresholdInBytes);
-
- mService.unregisterUsageRequest(unknownRequest);
- }
-
- @Test
- public void testStatsProviderUpdateStats() throws Exception {
- // Pretend that network comes online.
- expectDefaultSettings();
- final NetworkStateSnapshot[] states =
- new NetworkStateSnapshot[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- // Register custom provider and retrieve callback.
- final TestableNetworkStatsProviderBinder provider =
- new TestableNetworkStatsProviderBinder();
- final INetworkStatsProviderCallback cb =
- mService.registerNetworkStatsProvider("TEST", provider);
- assertNotNull(cb);
-
- mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // Verifies that one requestStatsUpdate will be called during iface update.
- provider.expectOnRequestStatsUpdate(0 /* unused */);
-
- // Create some initial traffic and report to the service.
- incrementCurrentTime(HOUR_IN_MILLIS);
- final NetworkStats expectedStats = new NetworkStats(0L, 1)
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT,
- TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
- 128L, 2L, 128L, 2L, 1L))
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT,
- 0xF00D, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
- 64L, 1L, 64L, 1L, 1L));
- cb.notifyStatsUpdated(0 /* unused */, expectedStats, expectedStats);
-
- // Make another empty mutable stats object. This is necessary since the new NetworkStats
- // object will be used to compare with the old one in NetworkStatsRecoder, two of them
- // cannot be the same object.
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- forcePollAndWaitForIdle();
-
- // Verifies that one requestStatsUpdate and setAlert will be called during polling.
- provider.expectOnRequestStatsUpdate(0 /* unused */);
- provider.expectOnSetAlert(MB_IN_BYTES);
-
- // Verifies that service recorded history, does not verify uid tag part.
- assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1);
-
- // Verifies that onStatsUpdated updates the stats accordingly.
- final NetworkStats stats = mSession.getSummaryForAllUid(
- sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
- assertEquals(2, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 1L);
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 1L);
-
- // Verifies that unregister the callback will remove the provider from service.
- cb.unregister();
- forcePollAndWaitForIdle();
- provider.assertNoCallback();
- }
-
- @Test
- public void testDualVilteProviderStats() throws Exception {
- // Pretend that network comes online.
- expectDefaultSettings();
- final int subId1 = 1;
- final int subId2 = 2;
- final NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
- buildImsState(IMSI_1, subId1, TEST_IFACE),
- buildImsState(IMSI_2, subId2, TEST_IFACE2)};
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- // Register custom provider and retrieve callback.
- final TestableNetworkStatsProviderBinder provider =
- new TestableNetworkStatsProviderBinder();
- final INetworkStatsProviderCallback cb =
- mService.registerNetworkStatsProvider("TEST", provider);
- assertNotNull(cb);
-
- mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // Verifies that one requestStatsUpdate will be called during iface update.
- provider.expectOnRequestStatsUpdate(0 /* unused */);
-
- // Create some initial traffic and report to the service.
- incrementCurrentTime(HOUR_IN_MILLIS);
- final String vtIface1 = NetworkStats.IFACE_VT + subId1;
- final String vtIface2 = NetworkStats.IFACE_VT + subId2;
- final NetworkStats expectedStats = new NetworkStats(0L, 1)
- .addEntry(new NetworkStats.Entry(vtIface1, UID_RED, SET_DEFAULT,
- TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
- 128L, 2L, 128L, 2L, 1L))
- .addEntry(new NetworkStats.Entry(vtIface2, UID_RED, SET_DEFAULT,
- TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
- 64L, 1L, 64L, 1L, 1L));
- cb.notifyStatsUpdated(0 /* unused */, expectedStats, expectedStats);
-
- // Make another empty mutable stats object. This is necessary since the new NetworkStats
- // object will be used to compare with the old one in NetworkStatsRecoder, two of them
- // cannot be the same object.
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- forcePollAndWaitForIdle();
-
- // Verifies that one requestStatsUpdate and setAlert will be called during polling.
- provider.expectOnRequestStatsUpdate(0 /* unused */);
- provider.expectOnSetAlert(MB_IN_BYTES);
-
- // Verifies that service recorded history, does not verify uid tag part.
- assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 1);
-
- // Verifies that onStatsUpdated updates the stats accordingly.
- NetworkStats stats = mSession.getSummaryForAllUid(
- sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
- assertEquals(1, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 1L);
-
- stats = mSession.getSummaryForAllUid(
- sTemplateImsi2, Long.MIN_VALUE, Long.MAX_VALUE, true);
- assertEquals(1, stats.size());
- assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
- DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 1L);
-
- // Verifies that unregister the callback will remove the provider from service.
- cb.unregister();
- forcePollAndWaitForIdle();
- provider.assertNoCallback();
- }
-
- @Test
- public void testStatsProviderSetAlert() throws Exception {
- // Pretend that network comes online.
- expectDefaultSettings();
- NetworkStateSnapshot[] states =
- new NetworkStateSnapshot[]{buildWifiState(true /* isMetered */, TEST_IFACE)};
- mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // Register custom provider and retrieve callback.
- final TestableNetworkStatsProviderBinder provider =
- new TestableNetworkStatsProviderBinder();
- final INetworkStatsProviderCallback cb =
- mService.registerNetworkStatsProvider("TEST", provider);
- assertNotNull(cb);
-
- // Simulates alert quota of the provider has been reached.
- cb.notifyAlertReached();
- HandlerUtils.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
-
- // Verifies that polling is triggered by alert reached.
- provider.expectOnRequestStatsUpdate(0 /* unused */);
- // Verifies that global alert will be re-armed.
- provider.expectOnSetAlert(MB_IN_BYTES);
- }
-
- private void setCombineSubtypeEnabled(boolean enable) {
- when(mSettings.getCombineSubtypeEnabled()).thenReturn(enable);
- mHandler.post(() -> mContentObserver.onChange(false, Settings.Global
- .getUriFor(Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED)));
- waitForIdle();
- if (enable) {
- verify(mNetworkStatsSubscriptionsMonitor).stop();
- } else {
- verify(mNetworkStatsSubscriptionsMonitor).start();
- }
- }
-
- @Test
- public void testDynamicWatchForNetworkRatTypeChanges() throws Exception {
- // Build 3G template, type unknown template to get stats while network type is unknown
- // and type all template to get the sum of all network type stats.
- final NetworkTemplate template3g =
- buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS);
- final NetworkTemplate templateUnknown =
- buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- final NetworkTemplate templateAll =
- buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL);
- final NetworkStateSnapshot[] states =
- new NetworkStateSnapshot[]{buildMobile3gState(IMSI_1)};
-
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
-
- // 3G network comes online.
- setMobileRatTypeAndWaitForIdle(TelephonyManager.NETWORK_TYPE_UMTS);
- mService.notifyNetworkStatus(NETWORKS_MOBILE, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // Create some traffic.
- incrementCurrentTime(MINUTE_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 12L, 18L, 14L, 1L, 0L)));
- forcePollAndWaitForIdle();
-
- // Since CombineSubtypeEnabled is false by default in unit test, the generated traffic
- // will be split by RAT type. Verify 3G templates gets stats, while template with unknown
- // RAT type gets nothing, and template with NETWORK_TYPE_ALL gets all stats.
- assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0);
- assertUidTotal(templateUnknown, UID_RED, 0L, 0L, 0L, 0L, 0);
- assertUidTotal(templateAll, UID_RED, 12L, 18L, 14L, 1L, 0);
-
- // Stop monitoring data usage per RAT type changes NetworkStatsService records data
- // to {@link TelephonyManager#NETWORK_TYPE_UNKNOWN}.
- setCombineSubtypeEnabled(true);
-
- // Call handleOnCollapsedRatTypeChanged manually to simulate the callback fired
- // when stopping monitor, this is needed by NetworkStatsService to trigger
- // handleNotifyNetworkStatus.
- mService.handleOnCollapsedRatTypeChanged();
- HandlerUtils.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
- // Create some traffic.
- incrementCurrentTime(MINUTE_IN_MILLIS);
- // Append more traffic on existing snapshot.
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 12L + 4L, 18L + 4L, 14L + 3L, 1L + 1L, 0L))
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
- 35L, 29L, 7L, 11L, 1L)));
- forcePollAndWaitForIdle();
-
- // Verify 3G counters do not increase, while template with unknown RAT type gets new
- // traffic and template with NETWORK_TYPE_ALL gets all stats.
- assertUidTotal(template3g, UID_RED, 12L, 18L, 14L, 1L, 0);
- assertUidTotal(templateUnknown, UID_RED, 4L + 35L, 4L + 29L, 3L + 7L, 1L + 11L, 1);
- assertUidTotal(templateAll, UID_RED, 16L + 35L, 22L + 29L, 17L + 7L, 2L + 11L, 1);
-
- // Start monitoring data usage per RAT type changes and NetworkStatsService records data
- // by a granular subtype representative of the actual subtype
- setCombineSubtypeEnabled(false);
-
- mService.handleOnCollapsedRatTypeChanged();
- HandlerUtils.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
- // Create some traffic.
- incrementCurrentTime(MINUTE_IN_MILLIS);
- // Append more traffic on existing snapshot.
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE,
- 22L, 26L, 19L, 5L, 0L))
- .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE,
- 35L, 29L, 7L, 11L, 1L)));
- forcePollAndWaitForIdle();
-
- // Verify traffic is split by RAT type, no increase on template with unknown RAT type
- // and template with NETWORK_TYPE_ALL gets all stats.
- assertUidTotal(template3g, UID_RED, 6L + 12L , 4L + 18L, 2L + 14L, 3L + 1L, 0);
- assertUidTotal(templateUnknown, UID_RED, 4L + 35L, 4L + 29L, 3L + 7L, 1L + 11L, 1);
- assertUidTotal(templateAll, UID_RED, 22L + 35L, 26L + 29L, 19L + 7L, 5L + 11L, 1);
- }
-
- @Test
- public void testOperationCount_nonDefault_traffic() throws Exception {
- // Pretend mobile network comes online, but wifi is the default network.
- expectDefaultSettings();
- NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
- buildWifiState(true /*isMetered*/, TEST_IFACE2), buildMobile3gState(IMSI_1)};
- expectNetworkStatsUidDetail(buildEmptyStats());
- mService.notifyNetworkStatus(NETWORKS_WIFI, states, getActiveIface(states),
- new UnderlyingNetworkInfo[0]);
-
- // Create some traffic on mobile network.
- incrementCurrentTime(HOUR_IN_MILLIS);
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 4)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_NO, 2L, 1L, 3L, 4L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO,
- DEFAULT_NETWORK_YES, 1L, 3L, 2L, 1L, 0L)
- .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 5L, 4L, 1L, 4L, 0L));
- // Increment operation count, which must have a specific tag.
- mService.incrementOperationCount(UID_RED, 0xF00D, 2);
- forcePollAndWaitForIdle();
-
- // Verify mobile summary is not changed by the operation count.
- final NetworkTemplate templateMobile =
- buildTemplateMobileWithRatType(null, NETWORK_TYPE_ALL);
- final NetworkStats statsMobile = mSession.getSummaryForAllUid(
- templateMobile, Long.MIN_VALUE, Long.MAX_VALUE, true);
- assertValues(statsMobile, IFACE_ALL, UID_RED, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 3L, 4L, 5L, 5L, 0);
- assertValues(statsMobile, IFACE_ALL, UID_RED, SET_ALL, 0xF00D, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 5L, 4L, 1L, 4L, 0);
-
- // Verify the operation count is blamed onto the default network.
- // TODO: Blame onto the default network is not very reasonable. Consider blame onto the
- // network that generates the traffic.
- final NetworkTemplate templateWifi = buildTemplateWifiWildcard();
- final NetworkStats statsWifi = mSession.getSummaryForAllUid(
- templateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
- assertValues(statsWifi, IFACE_ALL, UID_RED, SET_ALL, 0xF00D, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, 0L, 0L, 0L, 0L, 2);
- }
-
- private static File getBaseDir(File statsDir) {
- File baseDir = new File(statsDir, "netstats");
- baseDir.mkdirs();
- return baseDir;
- }
-
- private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long rxPackets,
- long txBytes, long txPackets, int operations) throws Exception {
- assertNetworkTotal(template, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
- txPackets, operations);
- }
-
- private void assertNetworkTotal(NetworkTemplate template, long start, long end, long rxBytes,
- long rxPackets, long txBytes, long txPackets, int operations) throws Exception {
- // verify history API
- final NetworkStatsHistory history = mSession.getHistoryForNetwork(template, FIELD_ALL);
- assertValues(history, start, end, rxBytes, rxPackets, txBytes, txPackets, operations);
-
- // verify summary API
- final NetworkStats stats = mSession.getSummaryForNetwork(template, start, end);
- assertValues(stats, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
- DEFAULT_NETWORK_ALL, rxBytes, rxPackets, txBytes, txPackets, operations);
- }
-
- private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long rxPackets,
- long txBytes, long txPackets, int operations) throws Exception {
- assertUidTotal(template, uid, SET_ALL, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
- rxBytes, rxPackets, txBytes, txPackets, operations);
- }
-
- private void assertUidTotal(NetworkTemplate template, int uid, int set, int metered,
- int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes,
- long txPackets, int operations) throws Exception {
- // verify history API
- final NetworkStatsHistory history = mSession.getHistoryForUid(
- template, uid, set, TAG_NONE, FIELD_ALL);
- assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
- txPackets, operations);
-
- // verify summary API
- final NetworkStats stats = mSession.getSummaryForAllUid(
- template, Long.MIN_VALUE, Long.MAX_VALUE, false);
- assertValues(stats, IFACE_ALL, uid, set, TAG_NONE, metered, roaming, defaultNetwork,
- rxBytes, rxPackets, txBytes, txPackets, operations);
- }
-
- private void expectSystemReady() throws Exception {
- expectNetworkStatsSummary(buildEmptyStats());
- }
-
- private String getActiveIface(NetworkStateSnapshot... states) throws Exception {
- if (states == null || states.length == 0 || states[0].getLinkProperties() == null) {
- return null;
- }
- return states[0].getLinkProperties().getInterfaceName();
- }
-
- private void expectNetworkStatsSummary(NetworkStats summary) throws Exception {
- expectNetworkStatsSummaryDev(summary.clone());
- expectNetworkStatsSummaryXt(summary.clone());
- }
-
- private void expectNetworkStatsSummaryDev(NetworkStats summary) throws Exception {
- when(mStatsFactory.readNetworkStatsSummaryDev()).thenReturn(summary);
- }
-
- private void expectNetworkStatsSummaryXt(NetworkStats summary) throws Exception {
- when(mStatsFactory.readNetworkStatsSummaryXt()).thenReturn(summary);
- }
-
- private void expectNetworkStatsUidDetail(NetworkStats detail) throws Exception {
- expectNetworkStatsUidDetail(detail, new NetworkStats(0L, 0));
- }
-
- private void expectNetworkStatsUidDetail(NetworkStats detail, NetworkStats tetherStats)
- throws Exception {
- when(mStatsFactory.readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL))
- .thenReturn(detail);
-
- // also include tethering details, since they are folded into UID
- when(mNetManager.getNetworkStatsTethering(STATS_PER_UID)).thenReturn(tetherStats);
- }
-
- private void expectDefaultSettings() throws Exception {
- expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
- }
-
- private void expectSettings(long persistBytes, long bucketDuration, long deleteAge)
- throws Exception {
- when(mSettings.getPollInterval()).thenReturn(HOUR_IN_MILLIS);
- when(mSettings.getPollDelay()).thenReturn(0L);
- when(mSettings.getSampleEnabled()).thenReturn(true);
- when(mSettings.getCombineSubtypeEnabled()).thenReturn(false);
-
- final Config config = new Config(bucketDuration, deleteAge, deleteAge);
- when(mSettings.getDevConfig()).thenReturn(config);
- when(mSettings.getXtConfig()).thenReturn(config);
- when(mSettings.getUidConfig()).thenReturn(config);
- when(mSettings.getUidTagConfig()).thenReturn(config);
-
- when(mSettings.getGlobalAlertBytes(anyLong())).thenReturn(MB_IN_BYTES);
- when(mSettings.getDevPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
- when(mSettings.getXtPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
- when(mSettings.getUidPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
- when(mSettings.getUidTagPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
- }
-
- private void assertStatsFilesExist(boolean exist) {
- final File basePath = new File(mStatsDir, "netstats");
- if (exist) {
- assertTrue(basePath.list().length > 0);
- } else {
- assertTrue(basePath.list().length == 0);
- }
- }
-
- private static void assertValues(NetworkStatsHistory stats, long start, long end, long rxBytes,
- long rxPackets, long txBytes, long txPackets, int operations) {
- final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- assertEquals("unexpected txPackets", txPackets, entry.txPackets);
- assertEquals("unexpected operations", operations, entry.operations);
- }
-
- private static NetworkStateSnapshot buildWifiState() {
- return buildWifiState(false, TEST_IFACE, null);
- }
-
- private static NetworkStateSnapshot buildWifiState(boolean isMetered, @NonNull String iface) {
- return buildWifiState(isMetered, iface, null);
- }
-
- private static NetworkStateSnapshot buildWifiState(boolean isMetered, @NonNull String iface,
- String subscriberId) {
- final LinkProperties prop = new LinkProperties();
- prop.setInterfaceName(iface);
- final NetworkCapabilities capabilities = new NetworkCapabilities();
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, !isMetered);
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
- capabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- capabilities.setSSID(TEST_SSID);
- return new NetworkStateSnapshot(WIFI_NETWORK, capabilities, prop, subscriberId, TYPE_WIFI);
- }
-
- private static NetworkStateSnapshot buildMobile3gState(String subscriberId) {
- return buildMobile3gState(subscriberId, false /* isRoaming */);
- }
-
- private static NetworkStateSnapshot buildMobile3gState(String subscriberId, boolean isRoaming) {
- final LinkProperties prop = new LinkProperties();
- prop.setInterfaceName(TEST_IFACE);
- final NetworkCapabilities capabilities = new NetworkCapabilities();
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
- capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
- return new NetworkStateSnapshot(
- MOBILE_NETWORK, capabilities, prop, subscriberId, TYPE_MOBILE);
- }
-
- private NetworkStats buildEmptyStats() {
- return new NetworkStats(getElapsedRealtime(), 0);
- }
-
- private static NetworkStateSnapshot buildOemManagedMobileState(
- String subscriberId, boolean isRoaming, int[] oemNetCapabilities) {
- final LinkProperties prop = new LinkProperties();
- prop.setInterfaceName(TEST_IFACE);
- final NetworkCapabilities capabilities = new NetworkCapabilities();
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
- for (int nc : oemNetCapabilities) {
- capabilities.setCapability(nc, true);
- }
- capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
- return new NetworkStateSnapshot(MOBILE_NETWORK, capabilities, prop, subscriberId,
- TYPE_MOBILE);
- }
-
- private static NetworkStateSnapshot buildImsState(
- String subscriberId, int subId, String ifaceName) {
- final LinkProperties prop = new LinkProperties();
- prop.setInterfaceName(ifaceName);
- final NetworkCapabilities capabilities = new NetworkCapabilities();
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, true);
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
- capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_IMS, true);
- capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
- capabilities.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId));
- return new NetworkStateSnapshot(
- MOBILE_NETWORK, capabilities, prop, subscriberId, TYPE_MOBILE);
- }
-
- private long getElapsedRealtime() {
- return mElapsedRealtime;
- }
-
- private long startTimeMillis() {
- return TEST_START;
- }
-
- private long currentTimeMillis() {
- return startTimeMillis() + mElapsedRealtime;
- }
-
- private void incrementCurrentTime(long duration) {
- mElapsedRealtime += duration;
- }
-
- private void forcePollAndWaitForIdle() {
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
- waitForIdle();
- }
-
- private void waitForIdle() {
- HandlerUtils.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
- }
-
- static class LatchedHandler extends Handler {
- private final ConditionVariable mCv;
- int lastMessageType = INVALID_TYPE;
-
- LatchedHandler(Looper looper, ConditionVariable cv) {
- super(looper);
- mCv = cv;
- }
-
- @Override
- public void handleMessage(Message msg) {
- lastMessageType = msg.what;
- mCv.open();
- super.handleMessage(msg);
- }
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
deleted file mode 100644
index 6d2c7dc..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
+++ /dev/null
@@ -1,386 +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 com.android.server.net;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.net.NetworkTemplate;
-import android.os.test.TestLooper;
-import android.telephony.NetworkRegistrationInfo;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.util.CollectionUtils;
-import com.android.server.net.NetworkStatsSubscriptionsMonitor.RatTypeListener;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-
-@RunWith(JUnit4.class)
-public final class NetworkStatsSubscriptionsMonitorTest {
- private static final int TEST_SUBID1 = 3;
- private static final int TEST_SUBID2 = 5;
- private static final String TEST_IMSI1 = "466921234567890";
- private static final String TEST_IMSI2 = "466920987654321";
- private static final String TEST_IMSI3 = "466929999999999";
-
- @Mock private Context mContext;
- @Mock private SubscriptionManager mSubscriptionManager;
- @Mock private TelephonyManager mTelephonyManager;
- @Mock private NetworkStatsSubscriptionsMonitor.Delegate mDelegate;
- private final List<Integer> mTestSubList = new ArrayList<>();
-
- private final Executor mExecutor = Executors.newSingleThreadExecutor();
- private NetworkStatsSubscriptionsMonitor mMonitor;
- private TestLooper mTestLooper = new TestLooper();
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
-
- when(mContext.getSystemService(eq(Context.TELEPHONY_SUBSCRIPTION_SERVICE)))
- .thenReturn(mSubscriptionManager);
- when(mContext.getSystemService(eq(Context.TELEPHONY_SERVICE)))
- .thenReturn(mTelephonyManager);
-
- mMonitor = new NetworkStatsSubscriptionsMonitor(mContext, mTestLooper.getLooper(),
- mExecutor, mDelegate);
- }
-
- @Test
- public void testStartStop() {
- // Verify that addOnSubscriptionsChangedListener() is never called before start().
- verify(mSubscriptionManager, never())
- .addOnSubscriptionsChangedListener(mExecutor, mMonitor);
- mMonitor.start();
- verify(mSubscriptionManager).addOnSubscriptionsChangedListener(mExecutor, mMonitor);
-
- // Verify that removeOnSubscriptionsChangedListener() is never called before stop()
- verify(mSubscriptionManager, never()).removeOnSubscriptionsChangedListener(mMonitor);
- mMonitor.stop();
- verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(mMonitor);
- }
-
- @NonNull
- private static int[] convertArrayListToIntArray(@NonNull List<Integer> arrayList) {
- final int[] list = new int[arrayList.size()];
- for (int i = 0; i < arrayList.size(); i++) {
- list[i] = arrayList.get(i);
- }
- return list;
- }
-
- private void setRatTypeForSub(List<RatTypeListener> listeners,
- int subId, int type) {
- final ServiceState serviceState = mock(ServiceState.class);
- when(serviceState.getDataNetworkType()).thenReturn(type);
- final RatTypeListener match = CollectionUtils
- .find(listeners, it -> it.getSubId() == subId);
- if (match == null) {
- fail("Could not find listener with subId: " + subId);
- }
- match.onServiceStateChanged(serviceState);
- }
-
- private void addTestSub(int subId, String subscriberId) {
- // add SubId to TestSubList.
- if (mTestSubList.contains(subId)) fail("The subscriber list already contains this ID");
-
- mTestSubList.add(subId);
-
- final int[] subList = convertArrayListToIntArray(mTestSubList);
- when(mSubscriptionManager.getCompleteActiveSubscriptionIdList()).thenReturn(subList);
- when(mTelephonyManager.getSubscriberId(subId)).thenReturn(subscriberId);
- mMonitor.onSubscriptionsChanged();
- }
-
- private void updateSubscriberIdForTestSub(int subId, @Nullable final String subscriberId) {
- when(mTelephonyManager.getSubscriberId(subId)).thenReturn(subscriberId);
- mMonitor.onSubscriptionsChanged();
- }
-
- private void removeTestSub(int subId) {
- // Remove subId from TestSubList.
- mTestSubList.removeIf(it -> it == subId);
- final int[] subList = convertArrayListToIntArray(mTestSubList);
- when(mSubscriptionManager.getCompleteActiveSubscriptionIdList()).thenReturn(subList);
- mMonitor.onSubscriptionsChanged();
- }
-
- private void assertRatTypeChangedForSub(String subscriberId, int ratType) {
- assertEquals(ratType, mMonitor.getRatTypeForSubscriberId(subscriberId));
- final ArgumentCaptor<Integer> typeCaptor = ArgumentCaptor.forClass(Integer.class);
- // Verify callback with the subscriberId and the RAT type should be as expected.
- // It will fail if get a callback with an unexpected RAT type.
- verify(mDelegate).onCollapsedRatTypeChanged(eq(subscriberId), typeCaptor.capture());
- final int type = typeCaptor.getValue();
- assertEquals(ratType, type);
- }
-
- private void assertRatTypeNotChangedForSub(String subscriberId, int ratType) {
- assertEquals(mMonitor.getRatTypeForSubscriberId(subscriberId), ratType);
- // Should never get callback with any RAT type.
- verify(mDelegate, never()).onCollapsedRatTypeChanged(eq(subscriberId), anyInt());
- }
-
- @Test
- public void testSubChangedAndRatTypeChanged() {
- final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
- ArgumentCaptor.forClass(RatTypeListener.class);
-
- mMonitor.start();
- // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback
- // before changing RAT type.
- addTestSub(TEST_SUBID1, TEST_IMSI1);
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
-
- // Insert sim2.
- addTestSub(TEST_SUBID2, TEST_IMSI2);
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- verify(mTelephonyManager, times(2)).listen(ratTypeListenerCaptor.capture(),
- eq(PhoneStateListener.LISTEN_SERVICE_STATE));
- reset(mDelegate);
-
- // Set RAT type of sim1 to UMTS.
- // Verify RAT type of sim1 after subscription gets onCollapsedRatTypeChanged() callback
- // and others remain untouched.
- setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
- TelephonyManager.NETWORK_TYPE_UMTS);
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
- assertRatTypeNotChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- assertRatTypeNotChangedForSub(TEST_IMSI3, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- reset(mDelegate);
-
- // Set RAT type of sim2 to LTE.
- // Verify RAT type of sim2 after subscription gets onCollapsedRatTypeChanged() callback
- // and others remain untouched.
- setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID2,
- TelephonyManager.NETWORK_TYPE_LTE);
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
- assertRatTypeChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_LTE);
- assertRatTypeNotChangedForSub(TEST_IMSI3, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- reset(mDelegate);
-
- // Remove sim2 and verify that callbacks are fired and RAT type is correct for sim2.
- // while the other two remain untouched.
- removeTestSub(TEST_SUBID2);
- verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_NONE));
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
- assertRatTypeChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- assertRatTypeNotChangedForSub(TEST_IMSI3, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- reset(mDelegate);
-
- // Set RAT type of sim1 to UNKNOWN. Then stop monitoring subscription changes
- // and verify that the listener for sim1 is removed.
- setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
- TelephonyManager.NETWORK_TYPE_UNKNOWN);
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- reset(mDelegate);
-
- mMonitor.stop();
- verify(mTelephonyManager, times(2)).listen(any(), eq(PhoneStateListener.LISTEN_NONE));
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- }
-
-
- @Test
- public void test5g() {
- mMonitor.start();
- // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback
- // before changing RAT type. Also capture listener for later use.
- addTestSub(TEST_SUBID1, TEST_IMSI1);
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
- ArgumentCaptor.forClass(RatTypeListener.class);
- verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(),
- eq(PhoneStateListener.LISTEN_SERVICE_STATE));
- final RatTypeListener listener = CollectionUtils
- .find(ratTypeListenerCaptor.getAllValues(), it -> it.getSubId() == TEST_SUBID1);
- assertNotNull(listener);
-
- // Set RAT type to 5G NSA (non-standalone) mode, verify the monitor outputs
- // NETWORK_TYPE_5G_NSA.
- final ServiceState serviceState = mock(ServiceState.class);
- when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_LTE);
- when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED);
- listener.onServiceStateChanged(serviceState);
- assertRatTypeChangedForSub(TEST_IMSI1, NetworkTemplate.NETWORK_TYPE_5G_NSA);
- reset(mDelegate);
-
- // Set RAT type to LTE without NR connected, the RAT type should be downgraded to LTE.
- when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_NONE);
- listener.onServiceStateChanged(serviceState);
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE);
- reset(mDelegate);
-
- // Verify NR connected with other RAT type does not take effect.
- when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_UMTS);
- when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED);
- listener.onServiceStateChanged(serviceState);
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
- reset(mDelegate);
-
- // Set RAT type to 5G standalone mode, the RAT type should be NR.
- setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
- TelephonyManager.NETWORK_TYPE_NR);
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR);
- reset(mDelegate);
-
- // Set NR state to none in standalone mode does not change anything.
- when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_NR);
- when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_NONE);
- listener.onServiceStateChanged(serviceState);
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR);
- }
-
- @Test
- public void testSubscriberIdUnavailable() {
- final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
- ArgumentCaptor.forClass(RatTypeListener.class);
-
- mMonitor.start();
- // Insert sim1, set subscriberId to null which is normal in SIM PIN locked case.
- // Verify RAT type is NETWORK_TYPE_UNKNOWN and service will not perform listener
- // registration.
- addTestSub(TEST_SUBID1, null);
- verify(mTelephonyManager, never()).listen(any(), anyInt());
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
-
- // Set IMSI for sim1, verify the listener will be registered.
- updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI1);
- verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(),
- eq(PhoneStateListener.LISTEN_SERVICE_STATE));
- reset(mTelephonyManager);
- when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
-
- // Set RAT type of sim1 to UMTS. Verify RAT type of sim1 is changed.
- setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
- TelephonyManager.NETWORK_TYPE_UMTS);
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
- reset(mDelegate);
-
- // Set IMSI to null again to simulate somehow IMSI is not available, such as
- // modem crash. Verify service should unregister listener.
- updateSubscriberIdForTestSub(TEST_SUBID1, null);
- verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()),
- eq(PhoneStateListener.LISTEN_NONE));
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- reset(mDelegate);
- clearInvocations(mTelephonyManager);
-
- // Simulate somehow IMSI is back. Verify service will register with
- // another listener and fire callback accordingly.
- final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor2 =
- ArgumentCaptor.forClass(RatTypeListener.class);
- updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI1);
- verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor2.capture(),
- eq(PhoneStateListener.LISTEN_SERVICE_STATE));
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- reset(mDelegate);
- clearInvocations(mTelephonyManager);
-
- // Set RAT type of sim1 to LTE. Verify RAT type of sim1 still works.
- setRatTypeForSub(ratTypeListenerCaptor2.getAllValues(), TEST_SUBID1,
- TelephonyManager.NETWORK_TYPE_LTE);
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE);
- reset(mDelegate);
-
- mMonitor.stop();
- verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor2.getValue()),
- eq(PhoneStateListener.LISTEN_NONE));
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- }
-
- /**
- * Verify that when IMSI suddenly changed for a given subId, the service will register a new
- * listener and unregister the old one, and report changes on updated IMSI. This is for modem
- * feature that may be enabled for certain carrier, which changes to use a different IMSI while
- * roaming on certain networks for multi-IMSI SIM cards, but the subId stays the same.
- */
- @Test
- public void testSubscriberIdChanged() {
- mMonitor.start();
- // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback
- // before changing RAT type.
- addTestSub(TEST_SUBID1, TEST_IMSI1);
- final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
- ArgumentCaptor.forClass(RatTypeListener.class);
- verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(),
- eq(PhoneStateListener.LISTEN_SERVICE_STATE));
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
-
- // Set RAT type of sim1 to UMTS.
- // Verify RAT type of sim1 changes accordingly.
- setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
- TelephonyManager.NETWORK_TYPE_UMTS);
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
- reset(mDelegate);
- clearInvocations(mTelephonyManager);
-
- // Simulate IMSI of sim1 changed to IMSI2. Verify the service will register with
- // another listener and remove the old one. The RAT type of new IMSI stays at
- // NETWORK_TYPE_UNKNOWN until received initial callback from telephony.
- final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor2 =
- ArgumentCaptor.forClass(RatTypeListener.class);
- updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI2);
- verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor2.capture(),
- eq(PhoneStateListener.LISTEN_SERVICE_STATE));
- verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()),
- eq(PhoneStateListener.LISTEN_NONE));
- assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- assertRatTypeNotChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- reset(mDelegate);
-
- // Set RAT type of sim1 to UMTS for new listener to simulate the initial callback received
- // from telephony after registration. Verify RAT type of sim1 changes with IMSI2
- // accordingly.
- setRatTypeForSub(ratTypeListenerCaptor2.getAllValues(), TEST_SUBID1,
- TelephonyManager.NETWORK_TYPE_UMTS);
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
- assertRatTypeChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UMTS);
- reset(mDelegate);
- }
-}
diff --git a/packages/Connectivity/tests/unit/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java b/packages/Connectivity/tests/unit/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
deleted file mode 100644
index ebbc0ef..0000000
--- a/packages/Connectivity/tests/unit/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
+++ /dev/null
@@ -1,70 +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.server.net.ipmemorystore;
-
-import static org.junit.Assert.assertEquals;
-
-import android.net.ipmemorystore.NetworkAttributes;
-import android.net.networkstack.aidl.quirks.IPv6ProvisioningLossQuirk;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.lang.reflect.Field;
-import java.net.Inet4Address;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-
-/** Unit tests for {@link NetworkAttributes}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class NetworkAttributesTest {
- private static final String WEIGHT_FIELD_NAME_PREFIX = "WEIGHT_";
- private static final float EPSILON = 0.0001f;
-
- // This is running two tests to make sure the total weight is the sum of all weights. To be
- // sure this is not fireproof, but you'd kind of need to do it on purpose to pass.
- @Test
- public void testTotalWeight() throws IllegalAccessException, UnknownHostException {
- // Make sure that TOTAL_WEIGHT is equal to the sum of the fields starting with WEIGHT_
- float sum = 0f;
- final Field[] fieldList = NetworkAttributes.class.getDeclaredFields();
- for (final Field field : fieldList) {
- if (!field.getName().startsWith(WEIGHT_FIELD_NAME_PREFIX)) continue;
- field.setAccessible(true);
- sum += (float) field.get(null);
- }
- assertEquals(sum, NetworkAttributes.TOTAL_WEIGHT, EPSILON);
-
- final IPv6ProvisioningLossQuirk ipv6ProvisioningLossQuirk =
- new IPv6ProvisioningLossQuirk(3, System.currentTimeMillis() + 7_200_000);
- // Use directly the constructor with all attributes, and make sure that when compared
- // to itself the score is a clean 1.0f.
- final NetworkAttributes na =
- new NetworkAttributes(
- (Inet4Address) Inet4Address.getByAddress(new byte[] {1, 2, 3, 4}),
- System.currentTimeMillis() + 7_200_000,
- "some hint",
- Arrays.asList(Inet4Address.getByAddress(new byte[] {5, 6, 7, 8}),
- Inet4Address.getByAddress(new byte[] {9, 0, 1, 2})),
- 98, ipv6ProvisioningLossQuirk);
- assertEquals(1.0f, na.getNetworkGroupSamenessConfidence(na), EPSILON);
- }
-}
diff --git a/packages/Connectivity/tests/unit/jni/Android.bp b/packages/Connectivity/tests/unit/jni/Android.bp
deleted file mode 100644
index 22a04f5..0000000
--- a/packages/Connectivity/tests/unit/jni/Android.bp
+++ /dev/null
@@ -1,32 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-cc_library_shared {
- name: "libnetworkstatsfactorytestjni",
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-unused-parameter",
- "-Wthread-safety",
- ],
-
- srcs: [
- ":lib_networkStatsFactory_native",
- "test_onload.cpp",
- ],
-
- shared_libs: [
- "libbpf_android",
- "liblog",
- "libnativehelper",
- "libnetdbpf",
- "libnetdutils",
- ],
-}
diff --git a/packages/Connectivity/tests/unit/jni/test_onload.cpp b/packages/Connectivity/tests/unit/jni/test_onload.cpp
deleted file mode 100644
index 5194ddb..0000000
--- a/packages/Connectivity/tests/unit/jni/test_onload.cpp
+++ /dev/null
@@ -1,44 +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.
- */
-
-/*
- * this is a mini native libaray for NetworkStatsFactoryTest to run properly. It
- * load all the native method related to NetworkStatsFactory when test run
- */
-#include <nativehelper/JNIHelp.h>
-#include "jni.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
-
-namespace android {
-int register_android_server_net_NetworkStatsFactory(JNIEnv* env);
-};
-
-using namespace android;
-
-extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
-{
- JNIEnv* env = NULL;
- jint result = -1;
-
- if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
- ALOGE("GetEnv failed!");
- return result;
- }
- ALOG_ASSERT(env, "Could not retrieve the env!");
- register_android_server_net_NetworkStatsFactory(env);
- return JNI_VERSION_1_4;
-}
diff --git a/packages/Connectivity/tests/unit/res/raw/history_v1 b/packages/Connectivity/tests/unit/res/raw/history_v1
deleted file mode 100644
index de79491..0000000
--- a/packages/Connectivity/tests/unit/res/raw/history_v1
+++ /dev/null
Binary files differ
diff --git a/packages/Connectivity/tests/unit/res/raw/net_dev_typical b/packages/Connectivity/tests/unit/res/raw/net_dev_typical
deleted file mode 100644
index 290bf03..0000000
--- a/packages/Connectivity/tests/unit/res/raw/net_dev_typical
+++ /dev/null
@@ -1,8 +0,0 @@
-Inter-| Receive | Transmit
- face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
- lo: 8308 116 0 0 0 0 0 0 8308 116 0 0 0 0 0 0
-rmnet0: 1507570 2205 0 0 0 0 0 0 489339 2237 0 0 0 0 0 0
- ifb0: 52454 151 0 151 0 0 0 0 0 0 0 0 0 0 0 0
- ifb1: 52454 151 0 151 0 0 0 0 0 0 0 0 0 0 0 0
- sit0: 0 0 0 0 0 0 0 0 0 0 148 0 0 0 0 0
-ip6tnl0: 0 0 0 0 0 0 0 0 0 0 151 151 0 0 0 0
diff --git a/packages/Connectivity/tests/unit/res/raw/netstats_uid_v4 b/packages/Connectivity/tests/unit/res/raw/netstats_uid_v4
deleted file mode 100644
index e75fc1c..0000000
--- a/packages/Connectivity/tests/unit/res/raw/netstats_uid_v4
+++ /dev/null
Binary files differ
diff --git a/packages/Connectivity/tests/unit/res/raw/netstats_v1 b/packages/Connectivity/tests/unit/res/raw/netstats_v1
deleted file mode 100644
index e80860a..0000000
--- a/packages/Connectivity/tests/unit/res/raw/netstats_v1
+++ /dev/null
Binary files differ
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_iface_fmt_typical b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_iface_fmt_typical
deleted file mode 100644
index 656d5bb..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_iface_fmt_typical
+++ /dev/null
@@ -1,4 +0,0 @@
-ifname total_skb_rx_bytes total_skb_rx_packets total_skb_tx_bytes total_skb_tx_packets
-rmnet2 4968 35 3081 39
-rmnet1 11153922 8051 190226 2468
-rmnet0 6824 16 5692 10
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_iface_typical b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_iface_typical
deleted file mode 100644
index 610723a..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_iface_typical
+++ /dev/null
@@ -1,6 +0,0 @@
-rmnet3 1 0 0 0 0 20822 501 1149991 815
-rmnet2 1 0 0 0 0 1594 15 1313 15
-rmnet1 1 0 0 0 0 207398 458 166918 565
-rmnet0 1 0 0 0 0 2112 24 700 10
-test1 1 1 2 3 4 5 6 7 8
-test2 0 1 2 3 4 5 6 7 8
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_typical b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_typical
deleted file mode 100644
index c1b0d25..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_typical
+++ /dev/null
@@ -1,71 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 wlan0 0x0 0 0 18621 96 2898 44 312 6 15897 58 2412 32 312 6 1010 16 1576 22
-3 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-4 wlan0 0x0 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-5 wlan0 0x0 1000 1 1949 13 1078 14 0 0 1600 10 349 3 0 0 600 10 478 4
-6 wlan0 0x0 10005 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-7 wlan0 0x0 10005 1 32081 38 5315 50 32081 38 0 0 0 0 5315 50 0 0 0 0
-8 wlan0 0x0 10011 0 35777 53 5718 57 0 0 0 0 35777 53 0 0 0 0 5718 57
-9 wlan0 0x0 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-10 wlan0 0x0 10014 0 0 0 1098 13 0 0 0 0 0 0 0 0 0 0 1098 13
-11 wlan0 0x0 10014 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-12 wlan0 0x0 10021 0 562386 573 49228 549 0 0 0 0 562386 573 0 0 0 0 49228 549
-13 wlan0 0x0 10021 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-14 wlan0 0x0 10031 0 3425 5 586 6 0 0 0 0 3425 5 0 0 0 0 586 6
-15 wlan0 0x0 10031 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-16 wlan0 0x7fffff0100000000 10021 0 562386 573 49228 549 0 0 0 0 562386 573 0 0 0 0 49228 549
-17 wlan0 0x7fffff0100000000 10021 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-18 wlan0 0x7fffff0100000000 10031 0 3425 5 586 6 0 0 0 0 3425 5 0 0 0 0 586 6
-19 wlan0 0x7fffff0100000000 10031 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-20 rmnet2 0x0 0 0 547 5 118 2 40 1 243 1 264 3 0 0 62 1 56 1
-21 rmnet2 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-22 rmnet2 0x0 10001 0 1125899906842624 5 984 11 632 5 0 0 0 0 984 11 0 0 0 0
-23 rmnet2 0x0 10001 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-24 rmnet1 0x0 0 0 26736 174 7098 130 7210 97 18382 64 1144 13 2932 64 4054 64 112 2
-25 rmnet1 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-26 rmnet1 0x0 1000 0 75774 77 18038 78 75335 72 439 5 0 0 17668 73 370 5 0 0
-27 rmnet1 0x0 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-28 rmnet1 0x0 10007 0 269945 578 111632 586 269945 578 0 0 0 0 111632 586 0 0 0 0
-29 rmnet1 0x0 10007 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-30 rmnet1 0x0 10011 0 1741256 6918 769778 7019 1741256 6918 0 0 0 0 769778 7019 0 0 0 0
-31 rmnet1 0x0 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-32 rmnet1 0x0 10014 0 0 0 786 12 0 0 0 0 0 0 786 12 0 0 0 0
-33 rmnet1 0x0 10014 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-34 rmnet1 0x0 10021 0 433533 1454 393420 1604 433533 1454 0 0 0 0 393420 1604 0 0 0 0
-35 rmnet1 0x0 10021 1 21215 33 10278 33 21215 33 0 0 0 0 10278 33 0 0 0 0
-36 rmnet1 0x0 10036 0 6310 25 3284 29 6310 25 0 0 0 0 3284 29 0 0 0 0
-37 rmnet1 0x0 10036 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-38 rmnet1 0x0 10047 0 34264 47 3936 34 34264 47 0 0 0 0 3936 34 0 0 0 0
-39 rmnet1 0x0 10047 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-40 rmnet1 0x4e7700000000 10011 0 9187 27 4248 33 9187 27 0 0 0 0 4248 33 0 0 0 0
-41 rmnet1 0x4e7700000000 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-42 rmnet1 0x1000000000000000 10007 0 2109 4 791 4 2109 4 0 0 0 0 791 4 0 0 0 0
-43 rmnet1 0x1000000000000000 10007 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-44 rmnet1 0x1000000400000000 10007 0 9811 22 6286 22 9811 22 0 0 0 0 6286 22 0 0 0 0
-45 rmnet1 0x1000000400000000 10007 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-46 rmnet1 0x1010000000000000 10021 0 164833 426 135392 527 164833 426 0 0 0 0 135392 527 0 0 0 0
-47 rmnet1 0x1010000000000000 10021 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-48 rmnet1 0x1144000400000000 10011 0 10112 18 3334 17 10112 18 0 0 0 0 3334 17 0 0 0 0
-49 rmnet1 0x1144000400000000 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-50 rmnet1 0x1244000400000000 10011 0 1300 3 848 2 1300 3 0 0 0 0 848 2 0 0 0 0
-51 rmnet1 0x1244000400000000 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-52 rmnet1 0x3000000000000000 10007 0 10389 14 1521 12 10389 14 0 0 0 0 1521 12 0 0 0 0
-53 rmnet1 0x3000000000000000 10007 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-54 rmnet1 0x3000000400000000 10007 0 238070 380 93938 404 238070 380 0 0 0 0 93938 404 0 0 0 0
-55 rmnet1 0x3000000400000000 10007 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-56 rmnet1 0x3010000000000000 10021 0 219110 578 227423 676 219110 578 0 0 0 0 227423 676 0 0 0 0
-57 rmnet1 0x3010000000000000 10021 1 742 3 1265 3 742 3 0 0 0 0 1265 3 0 0 0 0
-58 rmnet1 0x3020000000000000 10021 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-59 rmnet1 0x3020000000000000 10021 1 20473 30 9013 30 20473 30 0 0 0 0 9013 30 0 0 0 0
-60 rmnet1 0x3144000400000000 10011 0 43963 92 34414 116 43963 92 0 0 0 0 34414 116 0 0 0 0
-61 rmnet1 0x3144000400000000 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-62 rmnet1 0x3244000400000000 10011 0 3486 8 1520 9 3486 8 0 0 0 0 1520 9 0 0 0 0
-63 rmnet1 0x3244000400000000 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-64 rmnet1 0x7fffff0100000000 10021 0 29102 56 8865 60 29102 56 0 0 0 0 8865 60 0 0 0 0
-65 rmnet1 0x7fffff0100000000 10021 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-66 rmnet1 0x7fffff0300000000 1000 0 995 13 14145 14 995 13 0 0 0 0 14145 14 0 0 0 0
-67 rmnet1 0x7fffff0300000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-68 rmnet0 0x0 0 0 4312 49 1288 23 0 0 0 0 4312 49 0 0 0 0 1288 23
-69 rmnet0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-70 rmnet0 0x0 10080 0 22266 30 20976 30 0 0 0 0 22266 30 0 0 0 0 20976 30
-71 rmnet0 0x0 10080 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_incorrect_iface b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_incorrect_iface
deleted file mode 100644
index fc92715..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_incorrect_iface
+++ /dev/null
@@ -1,3 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test1 0x0 1004 0 1100 100 1100 100 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying
deleted file mode 100644
index 1ef1889..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying
+++ /dev/null
@@ -1,5 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 2000 200 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test_nss_tun0 0x0 1002 0 1000 100 500 50 0 0 0 0 0 0 0 0 0 0 0 0
-4 test0 0x0 1004 0 3300 300 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-5 test0 0x0 1004 1 0 0 1650 150 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_compression b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_compression
deleted file mode 100644
index 6d6bf55..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_compression
+++ /dev/null
@@ -1,4 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test_nss_tun0 0x0 1002 0 3000 300 3000 300 0 0 0 0 0 0 0 0 0 0 0 0
-4 test0 0x0 1004 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic
deleted file mode 100644
index 2c2e5d2..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_own_traffic
+++ /dev/null
@@ -1,6 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 2000 200 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test_nss_tun0 0x0 1002 0 1000 100 500 50 0 0 0 0 0 0 0 0 0 0 0 0
-4 test_nss_tun0 0x0 1004 0 5000 500 6000 600 0 0 0 0 0 0 0 0 0 0 0 0
-5 test0 0x0 1004 0 8800 800 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-6 test0 0x0 1004 1 0 0 8250 750 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn
deleted file mode 100644
index eb0513b..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_one_underlying_two_vpn
+++ /dev/null
@@ -1,9 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 2000 200 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test_nss_tun0 0x0 1002 0 1000 100 500 50 0 0 0 0 0 0 0 0 0 0 0 0
-4 test_nss_tun1 0x0 1001 0 3000 300 700 70 0 0 0 0 0 0 0 0 0 0 0 0
-5 test_nss_tun1 0x0 1002 0 500 50 250 25 0 0 0 0 0 0 0 0 0 0 0 0
-6 test0 0x0 1004 0 3300 300 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-7 test0 0x0 1004 1 0 0 1650 150 0 0 0 0 0 0 0 0 0 0 0 0
-8 test1 0x0 1004 0 3850 350 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-9 test1 0x0 1004 1 0 0 1045 95 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_rewrite_through_self b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_rewrite_through_self
deleted file mode 100644
index afcdd71..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_rewrite_through_self
+++ /dev/null
@@ -1,6 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 2000 200 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test_nss_tun0 0x0 1002 0 1000 100 500 50 0 0 0 0 0 0 0 0 0 0 0 0
-4 test_nss_tun0 0x0 1004 0 0 0 1600 160 0 0 0 0 0 0 0 0 0 0 0 0
-5 test0 0x0 1004 1 0 0 1760 176 0 0 0 0 0 0 0 0 0 0 0 0
-6 test0 0x0 1004 0 3300 300 0 0 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_duplication b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_duplication
deleted file mode 100644
index d7c7eb9..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_duplication
+++ /dev/null
@@ -1,5 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test_nss_tun0 0x0 1002 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-4 test0 0x0 1004 0 2200 200 2200 200 0 0 0 0 0 0 0 0 0 0 0 0
-5 test1 0x0 1004 0 2200 200 2200 200 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_split b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_split
deleted file mode 100644
index 38a3dce..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_split
+++ /dev/null
@@ -1,4 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 500 50 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test0 0x0 1004 0 330 30 660 60 0 0 0 0 0 0 0 0 0 0 0 0
-4 test1 0x0 1004 0 220 20 440 40 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_split_compression b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_split_compression
deleted file mode 100644
index d35244b..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_two_underlying_split_compression
+++ /dev/null
@@ -1,4 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 1000 100 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test0 0x0 1004 0 600 60 600 60 0 0 0 0 0 0 0 0 0 0 0 0
-4 test1 0x0 1004 0 200 20 200 20 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_with_clat b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_with_clat
deleted file mode 100644
index 0d893d5..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_vpn_with_clat
+++ /dev/null
@@ -1,8 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 test_nss_tun0 0x0 1001 0 2000 200 1000 100 0 0 0 0 0 0 0 0 0 0 0 0
-3 test_nss_tun0 0x0 1002 0 1000 100 500 50 0 0 0 0 0 0 0 0 0 0 0 0
-4 v4-test0 0x0 1004 0 3300 300 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-5 v4-test0 0x0 1004 1 0 0 1650 150 0 0 0 0 0 0 0 0 0 0 0 0
-6 test0 0x0 0 0 9300 300 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-7 test0 0x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-8 test0 0x0 1029 0 0 0 4650 150 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat
deleted file mode 100644
index f04b32f..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat
+++ /dev/null
@@ -1,43 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 v4-wlan0 0x0 0 0 256 5 196 4 256 5 0 0 0 0 196 4 0 0 0 0
-3 v4-wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-4 v4-wlan0 0x0 1000 0 30312 25 1770 27 30236 24 76 1 0 0 1694 26 76 1 0 0
-5 v4-wlan0 0x0 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-6 v4-wlan0 0x0 10060 0 9398432 6717 169412 4235 9398432 6717 0 0 0 0 169412 4235 0 0 0 0
-7 v4-wlan0 0x0 10060 1 1448660 1041 31192 753 1448660 1041 0 0 0 0 31192 753 0 0 0 0
-8 v4-wlan0 0x0 10102 0 9702 16 2870 23 9702 16 0 0 0 0 2870 23 0 0 0 0
-9 v4-wlan0 0x0 10102 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-10 wlan0 0x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-11 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-12 wlan0 0x0 1000 0 6126 13 2013 16 5934 11 192 2 0 0 1821 14 192 2 0 0
-13 wlan0 0x0 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-14 wlan0 0x0 10013 0 0 0 144 2 0 0 0 0 0 0 144 2 0 0 0 0
-15 wlan0 0x0 10013 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-16 wlan0 0x0 10018 0 5980263 4715 167667 1922 5972583 4709 0 0 7680 6 167667 1922 0 0 0 0
-17 wlan0 0x0 10018 1 43995 37 2766 27 43995 37 0 0 0 0 2766 27 0 0 0 0
-18 wlan0 0x0 10060 0 134356 133 8705 74 134356 133 0 0 0 0 8705 74 0 0 0 0
-19 wlan0 0x0 10060 1 294709 326 26448 256 294709 326 0 0 0 0 26448 256 0 0 0 0
-20 wlan0 0x0 10079 0 10926 13 1507 13 10926 13 0 0 0 0 1507 13 0 0 0 0
-21 wlan0 0x0 10079 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-22 wlan0 0x0 10102 0 25038 42 8245 57 25038 42 0 0 0 0 8245 57 0 0 0 0
-23 wlan0 0x0 10102 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-24 wlan0 0x0 10103 0 0 0 192 2 0 0 0 0 0 0 0 0 192 2 0 0
-25 wlan0 0x0 10103 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-26 wlan0 0x1000040700000000 10018 0 831 6 655 5 831 6 0 0 0 0 655 5 0 0 0 0
-27 wlan0 0x1000040700000000 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-28 wlan0 0x1000040b00000000 10018 0 1714 8 1561 7 1714 8 0 0 0 0 1561 7 0 0 0 0
-29 wlan0 0x1000040b00000000 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-30 wlan0 0x1000120300000000 10018 0 8243 11 2234 12 8243 11 0 0 0 0 2234 12 0 0 0 0
-31 wlan0 0x1000120300000000 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-32 wlan0 0x1000180300000000 10018 0 56368 49 4790 39 56368 49 0 0 0 0 4790 39 0 0 0 0
-33 wlan0 0x1000180300000000 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-34 wlan0 0x1000300000000000 10018 0 9488 17 18813 25 1808 11 0 0 7680 6 18813 25 0 0 0 0
-35 wlan0 0x1000300000000000 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-36 wlan0 0x3000180400000000 10018 0 131262 103 7416 103 131262 103 0 0 0 0 7416 103 0 0 0 0
-37 wlan0 0x3000180400000000 10018 1 43995 37 2766 27 43995 37 0 0 0 0 2766 27 0 0 0 0
-38 wlan0 0xffffff0100000000 10018 0 5771986 4518 131190 1725 5771986 4518 0 0 0 0 131190 1725 0 0 0 0
-39 wlan0 0xffffff0100000000 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-40 dummy0 0x0 0 0 0 0 168 3 0 0 0 0 0 0 0 0 0 0 168 3
-41 dummy0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-42 lo 0x0 0 0 1288 16 1288 16 0 0 532 8 756 8 0 0 532 8 756 8
-43 lo 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat_100mb_download_after b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat_100mb_download_after
deleted file mode 100644
index 12d98ca..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat_100mb_download_after
+++ /dev/null
@@ -1,189 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 r_rmnet_data0 0x0 0 0 0 0 392 6 0 0 0 0 0 0 0 0 0 0 392 6
-3 r_rmnet_data0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-4 v4-wlan0 0x0 0 0 58952 2072 2888 65 264 6 0 0 58688 2066 132 3 0 0 2756 62
-5 v4-wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-6 v4-wlan0 0x0 10034 0 6192 11 1445 11 6192 11 0 0 0 0 1445 11 0 0 0 0
-7 v4-wlan0 0x0 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-8 v4-wlan0 0x0 10057 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-9 v4-wlan0 0x0 10057 1 728 7 392 7 0 0 728 7 0 0 0 0 392 7 0 0
-10 v4-wlan0 0x0 10106 0 2232 18 2232 18 0 0 2232 18 0 0 0 0 2232 18 0 0
-11 v4-wlan0 0x0 10106 1 432952718 314238 5442288 121260 432950238 314218 2480 20 0 0 5433900 121029 8388 231 0 0
-12 wlan0 0x0 0 0 330187296 250652 0 0 329106990 236273 226202 1255 854104 13124 0 0 0 0 0 0
-13 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-14 wlan0 0x0 1000 0 77113 272 56151 575 77113 272 0 0 0 0 19191 190 36960 385 0 0
-15 wlan0 0x0 1000 1 20227 80 8356 72 18539 74 1688 6 0 0 7562 66 794 6 0 0
-16 wlan0 0x0 10006 0 80755 92 9122 99 80755 92 0 0 0 0 9122 99 0 0 0 0
-17 wlan0 0x0 10006 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-18 wlan0 0x0 10015 0 4390 7 14824 252 4390 7 0 0 0 0 14824 252 0 0 0 0
-19 wlan0 0x0 10015 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-20 wlan0 0x0 10018 0 4928 11 1741 14 4928 11 0 0 0 0 1741 14 0 0 0 0
-21 wlan0 0x0 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-22 wlan0 0x0 10020 0 21163552 34395 2351650 15326 21162947 34390 605 5 0 0 2351045 15321 605 5 0 0
-23 wlan0 0x0 10020 1 13835740 12938 1548795 6365 13833754 12920 1986 18 0 0 1546809 6347 1986 18 0 0
-24 wlan0 0x0 10023 0 13405 40 5042 44 13405 40 0 0 0 0 5042 44 0 0 0 0
-25 wlan0 0x0 10023 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-26 wlan0 0x0 10034 0 436394741 342648 6237981 80442 436394741 342648 0 0 0 0 6237981 80442 0 0 0 0
-27 wlan0 0x0 10034 1 64860872 51297 1335539 15546 64860872 51297 0 0 0 0 1335539 15546 0 0 0 0
-28 wlan0 0x0 10044 0 17614444 14774 521004 5694 17329882 14432 284562 342 0 0 419974 5408 101030 286 0 0
-29 wlan0 0x0 10044 1 17701 33 3100 28 17701 33 0 0 0 0 3100 28 0 0 0 0
-30 wlan0 0x0 10057 0 12312074 9339 436098 5450 12248060 9263 64014 76 0 0 414224 5388 21874 62 0 0
-31 wlan0 0x0 10057 1 1332953195 954797 31849632 457698 1331933207 953569 1019988 1228 0 0 31702284 456899 147348 799 0 0
-32 wlan0 0x0 10060 0 32972 200 433705 380 32972 200 0 0 0 0 433705 380 0 0 0 0
-33 wlan0 0x0 10060 1 32106 66 37789 87 32106 66 0 0 0 0 37789 87 0 0 0 0
-34 wlan0 0x0 10061 0 7675 23 2509 22 7675 23 0 0 0 0 2509 22 0 0 0 0
-35 wlan0 0x0 10061 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-36 wlan0 0x0 10074 0 38355 82 10447 97 38355 82 0 0 0 0 10447 97 0 0 0 0
-37 wlan0 0x0 10074 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-38 wlan0 0x0 10078 0 49013 79 7167 69 49013 79 0 0 0 0 7167 69 0 0 0 0
-39 wlan0 0x0 10078 1 5872 8 1236 10 5872 8 0 0 0 0 1236 10 0 0 0 0
-40 wlan0 0x0 10082 0 8301 13 1981 15 8301 13 0 0 0 0 1981 15 0 0 0 0
-41 wlan0 0x0 10082 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-42 wlan0 0x0 10086 0 7001 14 1579 15 7001 14 0 0 0 0 1579 15 0 0 0 0
-43 wlan0 0x0 10086 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-44 wlan0 0x0 10090 0 24327795 20224 920502 14661 24327795 20224 0 0 0 0 920502 14661 0 0 0 0
-45 wlan0 0x0 10090 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-46 wlan0 0x0 10092 0 36849 78 12449 81 36849 78 0 0 0 0 12449 81 0 0 0 0
-47 wlan0 0x0 10092 1 60 1 103 1 60 1 0 0 0 0 103 1 0 0 0 0
-48 wlan0 0x0 10095 0 131962 223 37069 241 131962 223 0 0 0 0 37069 241 0 0 0 0
-49 wlan0 0x0 10095 1 12949 21 3930 21 12949 21 0 0 0 0 3930 21 0 0 0 0
-50 wlan0 0x0 10106 0 30899554 22679 632476 12296 30895334 22645 4220 34 0 0 628256 12262 4220 34 0 0
-51 wlan0 0x0 10106 1 88923475 64963 1606962 35612 88917201 64886 3586 29 2688 48 1602032 35535 4930 77 0 0
-52 wlan0 0x40700000000 10020 0 705732 10589 404428 5504 705732 10589 0 0 0 0 404428 5504 0 0 0 0
-53 wlan0 0x40700000000 10020 1 2376 36 1296 18 2376 36 0 0 0 0 1296 18 0 0 0 0
-54 wlan0 0x40800000000 10020 0 34624 146 122525 160 34624 146 0 0 0 0 122525 160 0 0 0 0
-55 wlan0 0x40800000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-56 wlan0 0x40b00000000 10020 0 22411 85 7364 57 22411 85 0 0 0 0 7364 57 0 0 0 0
-57 wlan0 0x40b00000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-58 wlan0 0x120300000000 10020 0 76641 241 32783 169 76641 241 0 0 0 0 32783 169 0 0 0 0
-59 wlan0 0x120300000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-60 wlan0 0x130100000000 10020 0 73101 287 23236 203 73101 287 0 0 0 0 23236 203 0 0 0 0
-61 wlan0 0x130100000000 10020 1 264 4 144 2 264 4 0 0 0 0 144 2 0 0 0 0
-62 wlan0 0x180300000000 10020 0 330648 399 24736 232 330648 399 0 0 0 0 24736 232 0 0 0 0
-63 wlan0 0x180300000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-64 wlan0 0x180400000000 10020 0 21865 59 5022 42 21865 59 0 0 0 0 5022 42 0 0 0 0
-65 wlan0 0x180400000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-66 wlan0 0x300000000000 10020 0 15984 65 26927 57 15984 65 0 0 0 0 26927 57 0 0 0 0
-67 wlan0 0x300000000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-68 wlan0 0x1065fff00000000 10020 0 131871 599 93783 445 131871 599 0 0 0 0 93783 445 0 0 0 0
-69 wlan0 0x1065fff00000000 10020 1 264 4 144 2 264 4 0 0 0 0 144 2 0 0 0 0
-70 wlan0 0x1b24f4600000000 10034 0 15445 42 23329 45 15445 42 0 0 0 0 23329 45 0 0 0 0
-71 wlan0 0x1b24f4600000000 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-72 wlan0 0x1000010000000000 10020 0 5542 9 1364 10 5542 9 0 0 0 0 1364 10 0 0 0 0
-73 wlan0 0x1000010000000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-74 wlan0 0x1000040100000000 10020 0 47196 184 213319 257 47196 184 0 0 0 0 213319 257 0 0 0 0
-75 wlan0 0x1000040100000000 10020 1 60 1 103 1 60 1 0 0 0 0 103 1 0 0 0 0
-76 wlan0 0x1000040700000000 10020 0 11599 50 10786 47 11599 50 0 0 0 0 10786 47 0 0 0 0
-77 wlan0 0x1000040700000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-78 wlan0 0x1000040800000000 10020 0 21902 145 174139 166 21902 145 0 0 0 0 174139 166 0 0 0 0
-79 wlan0 0x1000040800000000 10020 1 8568 88 105743 90 8568 88 0 0 0 0 105743 90 0 0 0 0
-80 wlan0 0x1000100300000000 10020 0 55213 118 194551 199 55213 118 0 0 0 0 194551 199 0 0 0 0
-81 wlan0 0x1000100300000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-82 wlan0 0x1000120300000000 10020 0 50826 74 21153 70 50826 74 0 0 0 0 21153 70 0 0 0 0
-83 wlan0 0x1000120300000000 10020 1 72 1 175 2 72 1 0 0 0 0 175 2 0 0 0 0
-84 wlan0 0x1000180300000000 10020 0 744198 657 65437 592 744198 657 0 0 0 0 65437 592 0 0 0 0
-85 wlan0 0x1000180300000000 10020 1 144719 132 10989 108 144719 132 0 0 0 0 10989 108 0 0 0 0
-86 wlan0 0x1000180600000000 10020 0 4599 8 1928 10 4599 8 0 0 0 0 1928 10 0 0 0 0
-87 wlan0 0x1000180600000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-88 wlan0 0x1000250000000000 10020 0 57740 98 13076 88 57740 98 0 0 0 0 13076 88 0 0 0 0
-89 wlan0 0x1000250000000000 10020 1 328 3 414 4 207 2 121 1 0 0 293 3 121 1 0 0
-90 wlan0 0x1000300000000000 10020 0 7675 30 31331 32 7675 30 0 0 0 0 31331 32 0 0 0 0
-91 wlan0 0x1000300000000000 10020 1 30173 97 101335 100 30173 97 0 0 0 0 101335 100 0 0 0 0
-92 wlan0 0x1000310200000000 10020 0 1681 9 2194 9 1681 9 0 0 0 0 2194 9 0 0 0 0
-93 wlan0 0x1000310200000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-94 wlan0 0x1000360000000000 10020 0 5606 20 2831 20 5606 20 0 0 0 0 2831 20 0 0 0 0
-95 wlan0 0x1000360000000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-96 wlan0 0x11065fff00000000 10020 0 18363 91 83367 104 18363 91 0 0 0 0 83367 104 0 0 0 0
-97 wlan0 0x11065fff00000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-98 wlan0 0x3000009600000000 10020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-99 wlan0 0x3000009600000000 10020 1 6163 18 2424 18 6163 18 0 0 0 0 2424 18 0 0 0 0
-100 wlan0 0x3000009800000000 10020 0 23337 46 8723 39 23337 46 0 0 0 0 8723 39 0 0 0 0
-101 wlan0 0x3000009800000000 10020 1 33744 93 72437 89 33744 93 0 0 0 0 72437 89 0 0 0 0
-102 wlan0 0x3000020000000000 10020 0 4124 11 8969 19 4124 11 0 0 0 0 8969 19 0 0 0 0
-103 wlan0 0x3000020000000000 10020 1 5993 11 3815 14 5993 11 0 0 0 0 3815 14 0 0 0 0
-104 wlan0 0x3000040100000000 10020 0 113809 342 135666 308 113809 342 0 0 0 0 135666 308 0 0 0 0
-105 wlan0 0x3000040100000000 10020 1 142508 642 500579 637 142508 642 0 0 0 0 500579 637 0 0 0 0
-106 wlan0 0x3000040700000000 10020 0 365815 5119 213340 2733 365815 5119 0 0 0 0 213340 2733 0 0 0 0
-107 wlan0 0x3000040700000000 10020 1 30747 130 18408 100 30747 130 0 0 0 0 18408 100 0 0 0 0
-108 wlan0 0x3000040800000000 10020 0 34672 112 68623 92 34672 112 0 0 0 0 68623 92 0 0 0 0
-109 wlan0 0x3000040800000000 10020 1 78443 199 140944 192 78443 199 0 0 0 0 140944 192 0 0 0 0
-110 wlan0 0x3000040b00000000 10020 0 14949 33 4017 26 14949 33 0 0 0 0 4017 26 0 0 0 0
-111 wlan0 0x3000040b00000000 10020 1 996 15 576 8 996 15 0 0 0 0 576 8 0 0 0 0
-112 wlan0 0x3000090000000000 10020 0 11826 67 7309 52 11826 67 0 0 0 0 7309 52 0 0 0 0
-113 wlan0 0x3000090000000000 10020 1 24805 41 4785 41 24805 41 0 0 0 0 4785 41 0 0 0 0
-114 wlan0 0x3000100300000000 10020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-115 wlan0 0x3000100300000000 10020 1 3112 10 1628 10 3112 10 0 0 0 0 1628 10 0 0 0 0
-116 wlan0 0x3000120300000000 10020 0 38249 107 20374 85 38249 107 0 0 0 0 20374 85 0 0 0 0
-117 wlan0 0x3000120300000000 10020 1 122581 174 36792 143 122581 174 0 0 0 0 36792 143 0 0 0 0
-118 wlan0 0x3000130100000000 10020 0 2700 41 1524 21 2700 41 0 0 0 0 1524 21 0 0 0 0
-119 wlan0 0x3000130100000000 10020 1 22515 59 8366 52 22515 59 0 0 0 0 8366 52 0 0 0 0
-120 wlan0 0x3000180200000000 10020 0 6411 18 14511 20 6411 18 0 0 0 0 14511 20 0 0 0 0
-121 wlan0 0x3000180200000000 10020 1 336 5 319 4 336 5 0 0 0 0 319 4 0 0 0 0
-122 wlan0 0x3000180300000000 10020 0 129301 136 17622 97 129301 136 0 0 0 0 17622 97 0 0 0 0
-123 wlan0 0x3000180300000000 10020 1 464787 429 41703 336 464787 429 0 0 0 0 41703 336 0 0 0 0
-124 wlan0 0x3000180400000000 10020 0 11014 39 2787 25 11014 39 0 0 0 0 2787 25 0 0 0 0
-125 wlan0 0x3000180400000000 10020 1 144040 139 7540 80 144040 139 0 0 0 0 7540 80 0 0 0 0
-126 wlan0 0x3000210100000000 10020 0 10278 44 4579 33 10278 44 0 0 0 0 4579 33 0 0 0 0
-127 wlan0 0x3000210100000000 10020 1 31151 73 14159 47 31151 73 0 0 0 0 14159 47 0 0 0 0
-128 wlan0 0x3000250000000000 10020 0 132 2 72 1 132 2 0 0 0 0 72 1 0 0 0 0
-129 wlan0 0x3000250000000000 10020 1 76614 143 17711 130 76080 137 534 6 0 0 17177 124 534 6 0 0
-130 wlan0 0x3000260100000000 10020 0 9426 26 3535 20 9426 26 0 0 0 0 3535 20 0 0 0 0
-131 wlan0 0x3000260100000000 10020 1 468 7 288 4 468 7 0 0 0 0 288 4 0 0 0 0
-132 wlan0 0x3000300000000000 10020 0 7241 29 12055 26 7241 29 0 0 0 0 12055 26 0 0 0 0
-133 wlan0 0x3000300000000000 10020 1 3273 23 11232 21 3273 23 0 0 0 0 11232 21 0 0 0 0
-134 wlan0 0x3000310000000000 10020 0 132 2 72 1 132 2 0 0 0 0 72 1 0 0 0 0
-135 wlan0 0x3000310000000000 10020 1 53425 64 8721 62 53425 64 0 0 0 0 8721 62 0 0 0 0
-136 wlan0 0x3000310500000000 10020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-137 wlan0 0x3000310500000000 10020 1 9929 16 3879 18 9929 16 0 0 0 0 3879 18 0 0 0 0
-138 wlan0 0x3000320100000000 10020 0 6844 14 3745 13 6844 14 0 0 0 0 3745 13 0 0 0 0
-139 wlan0 0x3000320100000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-140 wlan0 0x3000360000000000 10020 0 8855 43 4749 31 8855 43 0 0 0 0 4749 31 0 0 0 0
-141 wlan0 0x3000360000000000 10020 1 5597 19 2456 19 5597 19 0 0 0 0 2456 19 0 0 0 0
-142 wlan0 0x3010000000000000 10090 0 605140 527 38435 429 605140 527 0 0 0 0 38435 429 0 0 0 0
-143 wlan0 0x3010000000000000 10090 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-144 wlan0 0x31065fff00000000 10020 0 22011 67 29665 64 22011 67 0 0 0 0 29665 64 0 0 0 0
-145 wlan0 0x31065fff00000000 10020 1 10695 34 18347 35 10695 34 0 0 0 0 18347 35 0 0 0 0
-146 wlan0 0x32e544f900000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-147 wlan0 0x32e544f900000000 10034 1 40143 54 7299 61 40143 54 0 0 0 0 7299 61 0 0 0 0
-148 wlan0 0x58872a4400000000 10018 0 4928 11 1669 13 4928 11 0 0 0 0 1669 13 0 0 0 0
-149 wlan0 0x58872a4400000000 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-150 wlan0 0x5caeaa7b00000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-151 wlan0 0x5caeaa7b00000000 10034 1 74971 73 7103 75 74971 73 0 0 0 0 7103 75 0 0 0 0
-152 wlan0 0x9e00923800000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-153 wlan0 0x9e00923800000000 10034 1 72385 98 13072 110 72385 98 0 0 0 0 13072 110 0 0 0 0
-154 wlan0 0xb972bdd400000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-155 wlan0 0xb972bdd400000000 10034 1 15282 24 3034 27 15282 24 0 0 0 0 3034 27 0 0 0 0
-156 wlan0 0xc7c9f7ba00000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-157 wlan0 0xc7c9f7ba00000000 10034 1 194915 185 13316 138 194915 185 0 0 0 0 13316 138 0 0 0 0
-158 wlan0 0xc9395b2600000000 10034 0 6991 13 6215 14 6991 13 0 0 0 0 6215 14 0 0 0 0
-159 wlan0 0xc9395b2600000000 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-160 wlan0 0xdaddf21100000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-161 wlan0 0xdaddf21100000000 10034 1 928676 849 81570 799 928676 849 0 0 0 0 81570 799 0 0 0 0
-162 wlan0 0xe8d195d100000000 10020 0 516 8 288 4 516 8 0 0 0 0 288 4 0 0 0 0
-163 wlan0 0xe8d195d100000000 10020 1 5905 15 2622 15 5905 15 0 0 0 0 2622 15 0 0 0 0
-164 wlan0 0xe8d195d100000000 10034 0 236640 524 312523 555 236640 524 0 0 0 0 312523 555 0 0 0 0
-165 wlan0 0xe8d195d100000000 10034 1 319028 539 188776 553 319028 539 0 0 0 0 188776 553 0 0 0 0
-166 wlan0 0xffffff0100000000 10006 0 80755 92 9122 99 80755 92 0 0 0 0 9122 99 0 0 0 0
-167 wlan0 0xffffff0100000000 10006 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-168 wlan0 0xffffff0100000000 10020 0 17874405 14068 223987 3065 17874405 14068 0 0 0 0 223987 3065 0 0 0 0
-169 wlan0 0xffffff0100000000 10020 1 11011258 8672 177693 2407 11011258 8672 0 0 0 0 177693 2407 0 0 0 0
-170 wlan0 0xffffff0100000000 10034 0 436062595 341880 5843990 79630 436062595 341880 0 0 0 0 5843990 79630 0 0 0 0
-171 wlan0 0xffffff0100000000 10034 1 63201220 49447 1005882 13713 63201220 49447 0 0 0 0 1005882 13713 0 0 0 0
-172 wlan0 0xffffff0100000000 10044 0 17159287 13702 356212 4778 17159287 13702 0 0 0 0 356212 4778 0 0 0 0
-173 wlan0 0xffffff0100000000 10044 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-174 wlan0 0xffffff0100000000 10078 0 10439 17 1665 15 10439 17 0 0 0 0 1665 15 0 0 0 0
-175 wlan0 0xffffff0100000000 10078 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-176 wlan0 0xffffff0100000000 10090 0 23722655 19697 881995 14231 23722655 19697 0 0 0 0 881995 14231 0 0 0 0
-177 wlan0 0xffffff0100000000 10090 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-178 wlan0 0xffffff0500000000 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-179 wlan0 0xffffff0500000000 1000 1 1592 5 314 1 0 0 1592 5 0 0 0 0 314 1 0 0
-180 wlan0 0xffffff0600000000 1000 0 0 0 36960 385 0 0 0 0 0 0 0 0 36960 385 0 0
-181 wlan0 0xffffff0600000000 1000 1 96 1 480 5 0 0 96 1 0 0 0 0 480 5 0 0
-182 wlan0 0xffffff0700000000 1000 0 38732 229 16567 163 38732 229 0 0 0 0 16567 163 0 0 0 0
-183 wlan0 0xffffff0700000000 1000 1 18539 74 7562 66 18539 74 0 0 0 0 7562 66 0 0 0 0
-184 wlan0 0xffffff0900000000 1000 0 38381 43 2624 27 38381 43 0 0 0 0 2624 27 0 0 0 0
-185 wlan0 0xffffff0900000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-186 dummy0 0x0 0 0 0 0 168 3 0 0 0 0 0 0 0 0 0 0 168 3
-187 dummy0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-188 wlan0 0x0 1029 0 0 0 8524052 130894 0 0 0 0 0 0 7871216 121284 108568 1325 544268 8285
-189 wlan0 0x0 1029 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat_100mb_download_before b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat_100mb_download_before
deleted file mode 100644
index ce4bcc3..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat_100mb_download_before
+++ /dev/null
@@ -1,187 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 r_rmnet_data0 0x0 0 0 0 0 392 6 0 0 0 0 0 0 0 0 0 0 392 6
-3 r_rmnet_data0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-4 v4-wlan0 0x0 0 0 58848 2070 2836 64 160 4 0 0 58688 2066 80 2 0 0 2756 62
-5 v4-wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-6 v4-wlan0 0x0 10034 0 6192 11 1445 11 6192 11 0 0 0 0 1445 11 0 0 0 0
-7 v4-wlan0 0x0 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-8 v4-wlan0 0x0 10057 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-9 v4-wlan0 0x0 10057 1 728 7 392 7 0 0 728 7 0 0 0 0 392 7 0 0
-10 v4-wlan0 0x0 10106 0 1488 12 1488 12 0 0 1488 12 0 0 0 0 1488 12 0 0
-11 v4-wlan0 0x0 10106 1 323981189 235142 3509032 84542 323979453 235128 1736 14 0 0 3502676 84363 6356 179 0 0
-12 wlan0 0x0 0 0 330187296 250652 0 0 329106990 236273 226202 1255 854104 13124 0 0 0 0 0 0
-13 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-14 wlan0 0x0 1000 0 77113 272 56151 575 77113 272 0 0 0 0 19191 190 36960 385 0 0
-15 wlan0 0x0 1000 1 20227 80 8356 72 18539 74 1688 6 0 0 7562 66 794 6 0 0
-16 wlan0 0x0 10006 0 80755 92 9122 99 80755 92 0 0 0 0 9122 99 0 0 0 0
-17 wlan0 0x0 10006 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-18 wlan0 0x0 10015 0 4390 7 14824 252 4390 7 0 0 0 0 14824 252 0 0 0 0
-19 wlan0 0x0 10015 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-20 wlan0 0x0 10018 0 4928 11 1741 14 4928 11 0 0 0 0 1741 14 0 0 0 0
-21 wlan0 0x0 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-22 wlan0 0x0 10020 0 21141412 34316 2329881 15262 21140807 34311 605 5 0 0 2329276 15257 605 5 0 0
-23 wlan0 0x0 10020 1 13835740 12938 1548555 6362 13833754 12920 1986 18 0 0 1546569 6344 1986 18 0 0
-24 wlan0 0x0 10023 0 13405 40 5042 44 13405 40 0 0 0 0 5042 44 0 0 0 0
-25 wlan0 0x0 10023 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-26 wlan0 0x0 10034 0 436394741 342648 6237981 80442 436394741 342648 0 0 0 0 6237981 80442 0 0 0 0
-27 wlan0 0x0 10034 1 64860872 51297 1335539 15546 64860872 51297 0 0 0 0 1335539 15546 0 0 0 0
-28 wlan0 0x0 10044 0 17614444 14774 521004 5694 17329882 14432 284562 342 0 0 419974 5408 101030 286 0 0
-29 wlan0 0x0 10044 1 17701 33 3100 28 17701 33 0 0 0 0 3100 28 0 0 0 0
-30 wlan0 0x0 10057 0 12311735 9335 435954 5448 12247721 9259 64014 76 0 0 414080 5386 21874 62 0 0
-31 wlan0 0x0 10057 1 1332953195 954797 31849632 457698 1331933207 953569 1019988 1228 0 0 31702284 456899 147348 799 0 0
-32 wlan0 0x0 10060 0 32972 200 433705 380 32972 200 0 0 0 0 433705 380 0 0 0 0
-33 wlan0 0x0 10060 1 32106 66 37789 87 32106 66 0 0 0 0 37789 87 0 0 0 0
-34 wlan0 0x0 10061 0 7675 23 2509 22 7675 23 0 0 0 0 2509 22 0 0 0 0
-35 wlan0 0x0 10061 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-36 wlan0 0x0 10074 0 38355 82 10447 97 38355 82 0 0 0 0 10447 97 0 0 0 0
-37 wlan0 0x0 10074 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-38 wlan0 0x0 10078 0 49013 79 7167 69 49013 79 0 0 0 0 7167 69 0 0 0 0
-39 wlan0 0x0 10078 1 5872 8 1236 10 5872 8 0 0 0 0 1236 10 0 0 0 0
-40 wlan0 0x0 10082 0 8301 13 1981 15 8301 13 0 0 0 0 1981 15 0 0 0 0
-41 wlan0 0x0 10082 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-42 wlan0 0x0 10086 0 7001 14 1579 15 7001 14 0 0 0 0 1579 15 0 0 0 0
-43 wlan0 0x0 10086 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-44 wlan0 0x0 10090 0 24327795 20224 920502 14661 24327795 20224 0 0 0 0 920502 14661 0 0 0 0
-45 wlan0 0x0 10090 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-46 wlan0 0x0 10092 0 36849 78 12449 81 36849 78 0 0 0 0 12449 81 0 0 0 0
-47 wlan0 0x0 10092 1 60 1 103 1 60 1 0 0 0 0 103 1 0 0 0 0
-48 wlan0 0x0 10095 0 131962 223 37069 241 131962 223 0 0 0 0 37069 241 0 0 0 0
-49 wlan0 0x0 10095 1 12949 21 3930 21 12949 21 0 0 0 0 3930 21 0 0 0 0
-50 wlan0 0x0 10106 0 30899554 22679 632476 12296 30895334 22645 4220 34 0 0 628256 12262 4220 34 0 0
-51 wlan0 0x0 10106 1 88922349 64952 1605126 35599 88916075 64875 3586 29 2688 48 1600196 35522 4930 77 0 0
-52 wlan0 0x40700000000 10020 0 705732 10589 404428 5504 705732 10589 0 0 0 0 404428 5504 0 0 0 0
-53 wlan0 0x40700000000 10020 1 2376 36 1296 18 2376 36 0 0 0 0 1296 18 0 0 0 0
-54 wlan0 0x40800000000 10020 0 34624 146 122525 160 34624 146 0 0 0 0 122525 160 0 0 0 0
-55 wlan0 0x40800000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-56 wlan0 0x40b00000000 10020 0 22411 85 7364 57 22411 85 0 0 0 0 7364 57 0 0 0 0
-57 wlan0 0x40b00000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-58 wlan0 0x120300000000 10020 0 76641 241 32783 169 76641 241 0 0 0 0 32783 169 0 0 0 0
-59 wlan0 0x120300000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-60 wlan0 0x130100000000 10020 0 73101 287 23236 203 73101 287 0 0 0 0 23236 203 0 0 0 0
-61 wlan0 0x130100000000 10020 1 264 4 144 2 264 4 0 0 0 0 144 2 0 0 0 0
-62 wlan0 0x180300000000 10020 0 330648 399 24736 232 330648 399 0 0 0 0 24736 232 0 0 0 0
-63 wlan0 0x180300000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-64 wlan0 0x180400000000 10020 0 21865 59 5022 42 21865 59 0 0 0 0 5022 42 0 0 0 0
-65 wlan0 0x180400000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-66 wlan0 0x300000000000 10020 0 15984 65 26927 57 15984 65 0 0 0 0 26927 57 0 0 0 0
-67 wlan0 0x300000000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-68 wlan0 0x1065fff00000000 10020 0 131871 599 93783 445 131871 599 0 0 0 0 93783 445 0 0 0 0
-69 wlan0 0x1065fff00000000 10020 1 264 4 144 2 264 4 0 0 0 0 144 2 0 0 0 0
-70 wlan0 0x1b24f4600000000 10034 0 15445 42 23329 45 15445 42 0 0 0 0 23329 45 0 0 0 0
-71 wlan0 0x1b24f4600000000 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-72 wlan0 0x1000010000000000 10020 0 5542 9 1364 10 5542 9 0 0 0 0 1364 10 0 0 0 0
-73 wlan0 0x1000010000000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-74 wlan0 0x1000040100000000 10020 0 47196 184 213319 257 47196 184 0 0 0 0 213319 257 0 0 0 0
-75 wlan0 0x1000040100000000 10020 1 60 1 103 1 60 1 0 0 0 0 103 1 0 0 0 0
-76 wlan0 0x1000040700000000 10020 0 11599 50 10786 47 11599 50 0 0 0 0 10786 47 0 0 0 0
-77 wlan0 0x1000040700000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-78 wlan0 0x1000040800000000 10020 0 21902 145 174139 166 21902 145 0 0 0 0 174139 166 0 0 0 0
-79 wlan0 0x1000040800000000 10020 1 8568 88 105743 90 8568 88 0 0 0 0 105743 90 0 0 0 0
-80 wlan0 0x1000100300000000 10020 0 55213 118 194551 199 55213 118 0 0 0 0 194551 199 0 0 0 0
-81 wlan0 0x1000100300000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-82 wlan0 0x1000120300000000 10020 0 50826 74 21153 70 50826 74 0 0 0 0 21153 70 0 0 0 0
-83 wlan0 0x1000120300000000 10020 1 72 1 175 2 72 1 0 0 0 0 175 2 0 0 0 0
-84 wlan0 0x1000180300000000 10020 0 744198 657 65437 592 744198 657 0 0 0 0 65437 592 0 0 0 0
-85 wlan0 0x1000180300000000 10020 1 144719 132 10989 108 144719 132 0 0 0 0 10989 108 0 0 0 0
-86 wlan0 0x1000180600000000 10020 0 4599 8 1928 10 4599 8 0 0 0 0 1928 10 0 0 0 0
-87 wlan0 0x1000180600000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-88 wlan0 0x1000250000000000 10020 0 57740 98 13076 88 57740 98 0 0 0 0 13076 88 0 0 0 0
-89 wlan0 0x1000250000000000 10020 1 328 3 414 4 207 2 121 1 0 0 293 3 121 1 0 0
-90 wlan0 0x1000300000000000 10020 0 7675 30 31331 32 7675 30 0 0 0 0 31331 32 0 0 0 0
-91 wlan0 0x1000300000000000 10020 1 30173 97 101335 100 30173 97 0 0 0 0 101335 100 0 0 0 0
-92 wlan0 0x1000310200000000 10020 0 1681 9 2194 9 1681 9 0 0 0 0 2194 9 0 0 0 0
-93 wlan0 0x1000310200000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-94 wlan0 0x1000360000000000 10020 0 5606 20 2831 20 5606 20 0 0 0 0 2831 20 0 0 0 0
-95 wlan0 0x1000360000000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-96 wlan0 0x11065fff00000000 10020 0 18363 91 83367 104 18363 91 0 0 0 0 83367 104 0 0 0 0
-97 wlan0 0x11065fff00000000 10020 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-98 wlan0 0x3000009600000000 10020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-99 wlan0 0x3000009600000000 10020 1 6163 18 2424 18 6163 18 0 0 0 0 2424 18 0 0 0 0
-100 wlan0 0x3000009800000000 10020 0 23337 46 8723 39 23337 46 0 0 0 0 8723 39 0 0 0 0
-101 wlan0 0x3000009800000000 10020 1 33744 93 72437 89 33744 93 0 0 0 0 72437 89 0 0 0 0
-102 wlan0 0x3000020000000000 10020 0 4124 11 8969 19 4124 11 0 0 0 0 8969 19 0 0 0 0
-103 wlan0 0x3000020000000000 10020 1 5993 11 3815 14 5993 11 0 0 0 0 3815 14 0 0 0 0
-104 wlan0 0x3000040100000000 10020 0 106718 322 121557 287 106718 322 0 0 0 0 121557 287 0 0 0 0
-105 wlan0 0x3000040100000000 10020 1 142508 642 500579 637 142508 642 0 0 0 0 500579 637 0 0 0 0
-106 wlan0 0x3000040700000000 10020 0 365419 5113 213124 2730 365419 5113 0 0 0 0 213124 2730 0 0 0 0
-107 wlan0 0x3000040700000000 10020 1 30747 130 18408 100 30747 130 0 0 0 0 18408 100 0 0 0 0
-108 wlan0 0x3000040800000000 10020 0 34672 112 68623 92 34672 112 0 0 0 0 68623 92 0 0 0 0
-109 wlan0 0x3000040800000000 10020 1 78443 199 140944 192 78443 199 0 0 0 0 140944 192 0 0 0 0
-110 wlan0 0x3000040b00000000 10020 0 14949 33 4017 26 14949 33 0 0 0 0 4017 26 0 0 0 0
-111 wlan0 0x3000040b00000000 10020 1 996 15 576 8 996 15 0 0 0 0 576 8 0 0 0 0
-112 wlan0 0x3000090000000000 10020 0 4017 28 3610 25 4017 28 0 0 0 0 3610 25 0 0 0 0
-113 wlan0 0x3000090000000000 10020 1 24805 41 4545 38 24805 41 0 0 0 0 4545 38 0 0 0 0
-114 wlan0 0x3000100300000000 10020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-115 wlan0 0x3000100300000000 10020 1 3112 10 1628 10 3112 10 0 0 0 0 1628 10 0 0 0 0
-116 wlan0 0x3000120300000000 10020 0 38249 107 20374 85 38249 107 0 0 0 0 20374 85 0 0 0 0
-117 wlan0 0x3000120300000000 10020 1 122581 174 36792 143 122581 174 0 0 0 0 36792 143 0 0 0 0
-118 wlan0 0x3000130100000000 10020 0 2700 41 1524 21 2700 41 0 0 0 0 1524 21 0 0 0 0
-119 wlan0 0x3000130100000000 10020 1 22515 59 8366 52 22515 59 0 0 0 0 8366 52 0 0 0 0
-120 wlan0 0x3000180200000000 10020 0 6411 18 14511 20 6411 18 0 0 0 0 14511 20 0 0 0 0
-121 wlan0 0x3000180200000000 10020 1 336 5 319 4 336 5 0 0 0 0 319 4 0 0 0 0
-122 wlan0 0x3000180300000000 10020 0 129301 136 17622 97 129301 136 0 0 0 0 17622 97 0 0 0 0
-123 wlan0 0x3000180300000000 10020 1 464787 429 41703 336 464787 429 0 0 0 0 41703 336 0 0 0 0
-124 wlan0 0x3000180400000000 10020 0 11014 39 2787 25 11014 39 0 0 0 0 2787 25 0 0 0 0
-125 wlan0 0x3000180400000000 10020 1 144040 139 7540 80 144040 139 0 0 0 0 7540 80 0 0 0 0
-126 wlan0 0x3000210100000000 10020 0 10278 44 4579 33 10278 44 0 0 0 0 4579 33 0 0 0 0
-127 wlan0 0x3000210100000000 10020 1 31151 73 14159 47 31151 73 0 0 0 0 14159 47 0 0 0 0
-128 wlan0 0x3000250000000000 10020 0 132 2 72 1 132 2 0 0 0 0 72 1 0 0 0 0
-129 wlan0 0x3000250000000000 10020 1 76614 143 17711 130 76080 137 534 6 0 0 17177 124 534 6 0 0
-130 wlan0 0x3000260100000000 10020 0 9426 26 3535 20 9426 26 0 0 0 0 3535 20 0 0 0 0
-131 wlan0 0x3000260100000000 10020 1 468 7 288 4 468 7 0 0 0 0 288 4 0 0 0 0
-132 wlan0 0x3000300000000000 10020 0 7241 29 12055 26 7241 29 0 0 0 0 12055 26 0 0 0 0
-133 wlan0 0x3000300000000000 10020 1 3273 23 11232 21 3273 23 0 0 0 0 11232 21 0 0 0 0
-134 wlan0 0x3000310000000000 10020 0 132 2 72 1 132 2 0 0 0 0 72 1 0 0 0 0
-135 wlan0 0x3000310000000000 10020 1 53425 64 8721 62 53425 64 0 0 0 0 8721 62 0 0 0 0
-136 wlan0 0x3000310500000000 10020 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-137 wlan0 0x3000310500000000 10020 1 9929 16 3879 18 9929 16 0 0 0 0 3879 18 0 0 0 0
-138 wlan0 0x3000360000000000 10020 0 8855 43 4749 31 8855 43 0 0 0 0 4749 31 0 0 0 0
-139 wlan0 0x3000360000000000 10020 1 5597 19 2456 19 5597 19 0 0 0 0 2456 19 0 0 0 0
-140 wlan0 0x3010000000000000 10090 0 605140 527 38435 429 605140 527 0 0 0 0 38435 429 0 0 0 0
-141 wlan0 0x3010000000000000 10090 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-142 wlan0 0x31065fff00000000 10020 0 22011 67 29665 64 22011 67 0 0 0 0 29665 64 0 0 0 0
-143 wlan0 0x31065fff00000000 10020 1 10695 34 18347 35 10695 34 0 0 0 0 18347 35 0 0 0 0
-144 wlan0 0x32e544f900000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-145 wlan0 0x32e544f900000000 10034 1 40143 54 7299 61 40143 54 0 0 0 0 7299 61 0 0 0 0
-146 wlan0 0x58872a4400000000 10018 0 4928 11 1669 13 4928 11 0 0 0 0 1669 13 0 0 0 0
-147 wlan0 0x58872a4400000000 10018 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-148 wlan0 0x5caeaa7b00000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-149 wlan0 0x5caeaa7b00000000 10034 1 74971 73 7103 75 74971 73 0 0 0 0 7103 75 0 0 0 0
-150 wlan0 0x9e00923800000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-151 wlan0 0x9e00923800000000 10034 1 72385 98 13072 110 72385 98 0 0 0 0 13072 110 0 0 0 0
-152 wlan0 0xb972bdd400000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-153 wlan0 0xb972bdd400000000 10034 1 15282 24 3034 27 15282 24 0 0 0 0 3034 27 0 0 0 0
-154 wlan0 0xc7c9f7ba00000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-155 wlan0 0xc7c9f7ba00000000 10034 1 194915 185 13316 138 194915 185 0 0 0 0 13316 138 0 0 0 0
-156 wlan0 0xc9395b2600000000 10034 0 6991 13 6215 14 6991 13 0 0 0 0 6215 14 0 0 0 0
-157 wlan0 0xc9395b2600000000 10034 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-158 wlan0 0xdaddf21100000000 10034 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-159 wlan0 0xdaddf21100000000 10034 1 928676 849 81570 799 928676 849 0 0 0 0 81570 799 0 0 0 0
-160 wlan0 0xe8d195d100000000 10020 0 516 8 288 4 516 8 0 0 0 0 288 4 0 0 0 0
-161 wlan0 0xe8d195d100000000 10020 1 5905 15 2622 15 5905 15 0 0 0 0 2622 15 0 0 0 0
-162 wlan0 0xe8d195d100000000 10034 0 236640 524 312523 555 236640 524 0 0 0 0 312523 555 0 0 0 0
-163 wlan0 0xe8d195d100000000 10034 1 319028 539 188776 553 319028 539 0 0 0 0 188776 553 0 0 0 0
-164 wlan0 0xffffff0100000000 10006 0 80755 92 9122 99 80755 92 0 0 0 0 9122 99 0 0 0 0
-165 wlan0 0xffffff0100000000 10006 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-166 wlan0 0xffffff0100000000 10020 0 17874405 14068 223987 3065 17874405 14068 0 0 0 0 223987 3065 0 0 0 0
-167 wlan0 0xffffff0100000000 10020 1 11011258 8672 177693 2407 11011258 8672 0 0 0 0 177693 2407 0 0 0 0
-168 wlan0 0xffffff0100000000 10034 0 436062595 341880 5843990 79630 436062595 341880 0 0 0 0 5843990 79630 0 0 0 0
-169 wlan0 0xffffff0100000000 10034 1 63201220 49447 1005882 13713 63201220 49447 0 0 0 0 1005882 13713 0 0 0 0
-170 wlan0 0xffffff0100000000 10044 0 17159287 13702 356212 4778 17159287 13702 0 0 0 0 356212 4778 0 0 0 0
-171 wlan0 0xffffff0100000000 10044 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-172 wlan0 0xffffff0100000000 10078 0 10439 17 1665 15 10439 17 0 0 0 0 1665 15 0 0 0 0
-173 wlan0 0xffffff0100000000 10078 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-174 wlan0 0xffffff0100000000 10090 0 23722655 19697 881995 14231 23722655 19697 0 0 0 0 881995 14231 0 0 0 0
-175 wlan0 0xffffff0100000000 10090 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-176 wlan0 0xffffff0500000000 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-177 wlan0 0xffffff0500000000 1000 1 1592 5 314 1 0 0 1592 5 0 0 0 0 314 1 0 0
-178 wlan0 0xffffff0600000000 1000 0 0 0 36960 385 0 0 0 0 0 0 0 0 36960 385 0 0
-179 wlan0 0xffffff0600000000 1000 1 96 1 480 5 0 0 96 1 0 0 0 0 480 5 0 0
-180 wlan0 0xffffff0700000000 1000 0 38732 229 16567 163 38732 229 0 0 0 0 16567 163 0 0 0 0
-181 wlan0 0xffffff0700000000 1000 1 18539 74 7562 66 18539 74 0 0 0 0 7562 66 0 0 0 0
-182 wlan0 0xffffff0900000000 1000 0 38381 43 2624 27 38381 43 0 0 0 0 2624 27 0 0 0 0
-183 wlan0 0xffffff0900000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-184 dummy0 0x0 0 0 0 0 168 3 0 0 0 0 0 0 0 0 0 0 168 3
-185 dummy0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-186 wlan0 0x0 1029 0 0 0 5855801 94173 0 0 0 0 0 0 5208040 84634 103637 1256 544124 8283
-187 wlan0 0x0 1029 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat_simple b/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat_simple
deleted file mode 100644
index a1d6d411..0000000
--- a/packages/Connectivity/tests/unit/res/raw/xt_qtaguid_with_clat_simple
+++ /dev/null
@@ -1,4 +0,0 @@
-idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets
-2 v4-wlan0 0x0 10060 0 42600 213 4100 41 42600 213 0 0 0 0 4100 41 0 0 0 0
-3 v4-wlan0 0x0 10060 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-4 wlan0 0x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/packages/CtsShim/OWNERS b/packages/CtsShim/OWNERS
index ba9f2b9..9419771 100644
--- a/packages/CtsShim/OWNERS
+++ b/packages/CtsShim/OWNERS
@@ -1,2 +1,3 @@
ioffe@google.com
-toddke@google.com
\ No newline at end of file
+toddke@google.com
+patb@google.com
\ No newline at end of file
diff --git a/packages/PackageInstaller/OWNERS b/packages/PackageInstaller/OWNERS
index 8e1774b..c633113 100644
--- a/packages/PackageInstaller/OWNERS
+++ b/packages/PackageInstaller/OWNERS
@@ -1,5 +1,6 @@
svetoslavganov@google.com
toddke@google.com
+patb@google.com
suprabh@google.com
# For automotive related changes
diff --git a/packages/SettingsLib/AppPreference/res/layout/preference_app.xml b/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
index 657a12c..e65f7de 100644
--- a/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
+++ b/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
@@ -90,7 +90,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical|end"
- android:minWidth="64dp"
+ android:minWidth="@dimen/two_target_min_width"
android:orientation="vertical"/>
</LinearLayout>
diff --git a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
index 5bedd7a..9e39355 100644
--- a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
+++ b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java
@@ -73,11 +73,11 @@
throw new IllegalArgumentException();
}
- @ColorRes int getAccentColorResId() {
+ public @ColorRes int getAccentColorResId() {
return mAccentColorResId;
}
- @ColorRes int getBackgroundColorResId() {
+ public @ColorRes int getBackgroundColorResId() {
return mBackgroundColorResId;
}
}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/SettingsTransitionActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/SettingsTransitionActivity.java
index 4c45c5e..8c2621d 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/SettingsTransitionActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/SettingsTransitionActivity.java
@@ -16,6 +16,8 @@
package com.android.settingslib.collapsingtoolbar;
+import static com.android.settingslib.transition.SettingsTransitionHelper.EXTRA_PAGE_TRANSITION_TYPE;
+
import android.app.ActivityOptions;
import android.content.Intent;
import android.os.Bundle;
@@ -28,6 +30,7 @@
import androidx.fragment.app.FragmentActivity;
import com.android.settingslib.transition.SettingsTransitionHelper;
+import com.android.settingslib.transition.SettingsTransitionHelper.TransitionType;
/**
* A base Activity for Settings-specific page transition. Activities extending it will get
@@ -35,7 +38,6 @@
*/
public abstract class SettingsTransitionActivity extends FragmentActivity {
private static final String TAG = "SettingsTransitionActivity";
- private static final int DEFAULT_REQUEST = -1;
private Toolbar mToolbar;
@@ -58,45 +60,17 @@
}
@Override
- public void startActivity(Intent intent) {
- if (!isSettingsTransitionEnabled()) {
- super.startActivity(intent);
- return;
- }
-
- super.startActivity(intent, createActivityOptionsBundleForTransition(null));
- }
-
- @Override
- public void startActivity(Intent intent, @Nullable Bundle options) {
- if (!isSettingsTransitionEnabled()) {
- super.startActivity(intent, options);
- return;
- }
-
- super.startActivity(intent, createActivityOptionsBundleForTransition(options));
- }
-
- @Override
- public void startActivityForResult(Intent intent, int requestCode) {
- if (!isSettingsTransitionEnabled() || requestCode == DEFAULT_REQUEST) {
- super.startActivityForResult(intent, requestCode);
- return;
- }
-
- super.startActivityForResult(intent, requestCode, createActivityOptionsBundleForTransition(
- null));
- }
-
- @Override
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
- if (!isSettingsTransitionEnabled() || requestCode == DEFAULT_REQUEST) {
+ final int transitionType = intent.getIntExtra(EXTRA_PAGE_TRANSITION_TYPE,
+ TransitionType.TRANSITION_SHARED_AXIS);
+ if (!isSettingsTransitionEnabled() ||
+ transitionType == TransitionType.TRANSITION_NONE) {
super.startActivityForResult(intent, requestCode, options);
return;
}
- super.startActivityForResult(intent, requestCode, createActivityOptionsBundleForTransition(
- options));
+ super.startActivityForResult(intent, requestCode,
+ createActivityOptionsBundleForTransition(options));
}
protected boolean isSettingsTransitionEnabled() {
diff --git a/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml b/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
index 3b50acc..e586dbb 100644
--- a/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
+++ b/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
@@ -43,13 +43,27 @@
android:layout_height="wrap_content"/>
</LinearLayout>
- <com.android.settingslib.widget.LinkTextView
- android:id="@android:id/title"
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingBottom="16dp"
- android:paddingTop="16dp"
- android:textColor="?android:attr/textColorSecondary"
- android:ellipsize="marquee" />
+ android:orientation="vertical">
+ <com.android.settingslib.widget.LinkTextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="16dp"
+ android:paddingBottom="8dp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:ellipsize="marquee" />
+
+ <com.android.settingslib.widget.LinkTextView
+ android:id="@+id/settingslib_learn_more"
+ android:text="@string/settingslib_learn_more_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clickable="true"
+ android:visibility="gone"
+ style="@style/TextAppearance.Footer.Title.SettingsLib"/>
+ </LinearLayout>
</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml b/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml
index 87e8358..990860a 100644
--- a/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml
+++ b/packages/SettingsLib/FooterPreference/res/layout/preference_footer.xml
@@ -42,13 +42,27 @@
android:layout_height="wrap_content"/>
</LinearLayout>
- <com.android.settingslib.widget.LinkTextView
- android:id="@android:id/title"
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingBottom="16dp"
- android:paddingTop="16dp"
- android:textColor="?android:attr/textColorSecondary"
- android:ellipsize="marquee" />
+ android:orientation="vertical">
+ <com.android.settingslib.widget.LinkTextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="16dp"
+ android:paddingBottom="8dp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:ellipsize="marquee" />
+
+ <com.android.settingslib.widget.LinkTextView
+ android:id="@+id/settingslib_learn_more"
+ android:text="@string/settingslib_learn_more_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clickable="true"
+ android:visibility="gone"
+ style="@style/TextAppearance.Footer.Title.SettingsLib"/>
+ </LinearLayout>
</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/FooterPreference/res/values/strings.xml b/packages/SettingsLib/FooterPreference/res/values/strings.xml
new file mode 100644
index 0000000..9d5df12
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- learn more text of footer preference [CHAR LIMIT=NONE] -->
+ <string name="settingslib_learn_more_text">Learn more</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/FooterPreference/res/values/styles.xml b/packages/SettingsLib/FooterPreference/res/values/styles.xml
new file mode 100644
index 0000000..08dd359
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values/styles.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <style name="TextAppearance.Footer.Title.SettingsLib"
+ parent="@android:style/TextAppearance.DeviceDefault.Medium">
+ <item name="android:textSize">14sp</item>
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+ <item name="android:textColor">?android:attr/colorAccent</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
index feb3b01..33bf590 100644
--- a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
@@ -17,13 +17,17 @@
package com.android.settingslib.widget;
import android.content.Context;
+import android.text.SpannableString;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
+import android.text.style.UnderlineSpan;
import android.util.AttributeSet;
+import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
+import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
@@ -35,7 +39,10 @@
public static final String KEY_FOOTER = "footer_preference";
static final int ORDER_FOOTER = Integer.MAX_VALUE - 1;
+ @VisibleForTesting
+ View.OnClickListener mLearnMoreListener;
private CharSequence mContentDescription;
+ private CharSequence mLearnMoreContentDescription;
public FooterPreference(Context context, AttributeSet attrs) {
super(context, attrs, R.attr.footerPreferenceStyle);
@@ -53,7 +60,23 @@
title.setMovementMethod(new LinkMovementMethod());
title.setClickable(false);
title.setLongClickable(false);
- title.setContentDescription(mContentDescription);
+ if (!TextUtils.isEmpty(mContentDescription)) {
+ title.setContentDescription(mContentDescription);
+ }
+
+ TextView learnMore = holder.itemView.findViewById(R.id.settingslib_learn_more);
+ if (learnMore != null && mLearnMoreListener != null) {
+ learnMore.setVisibility(View.VISIBLE);
+ learnMore.setOnClickListener(mLearnMoreListener);
+ SpannableString learnMoreText = new SpannableString(learnMore.getText());
+ learnMoreText.setSpan(new UnderlineSpan(), 0, learnMoreText.length(), 0);
+ learnMore.setText(learnMoreText);
+ if (!TextUtils.isEmpty(mLearnMoreContentDescription)) {
+ learnMore.setContentDescription(mLearnMoreContentDescription);
+ }
+ } else {
+ learnMore.setVisibility(View.GONE);
+ }
}
@Override
@@ -87,10 +110,42 @@
/**
* Return the content description of footer preference.
*/
- public CharSequence getContentDescription() {
+ @VisibleForTesting
+ CharSequence getContentDescription() {
return mContentDescription;
}
+ /**
+ * To set content description of the learn more text. This can use for talkback
+ * environment if developer wants to have a customization content.
+ *
+ * @param learnMoreContentDescription The resource id of the content description.
+ */
+ public void setLearnMoreContentDescription(CharSequence learnMoreContentDescription) {
+ if (!TextUtils.equals(mContentDescription, learnMoreContentDescription)) {
+ mLearnMoreContentDescription = learnMoreContentDescription;
+ notifyChanged();
+ }
+ }
+
+ /**
+ * Return the content description of learn more link.
+ */
+ @VisibleForTesting
+ CharSequence getLearnMoreContentDescription() {
+ return mLearnMoreContentDescription;
+ }
+
+ /**
+ * Assign an action for the learn more link.
+ */
+ public void setLearnMoreAction(View.OnClickListener listener) {
+ if (mLearnMoreListener != listener) {
+ mLearnMoreListener = listener;
+ notifyChanged();
+ }
+ }
+
private void init() {
setLayoutResource(R.layout.preference_footer);
if (getIcon() == null) {
@@ -110,6 +165,7 @@
private String mKey;
private CharSequence mTitle;
private CharSequence mContentDescription;
+ private CharSequence mLearnMoreContentDescription;
public Builder(@NonNull Context context) {
mContext = context;
@@ -168,6 +224,30 @@
}
/**
+ * To set content description of the learn more text. This can use for talkback
+ * environment if developer wants to have a customization content.
+ *
+ * @param learnMoreContentDescription The resource id of the content description.
+ */
+ public Builder setLearnMoreContentDescription(CharSequence learnMoreContentDescription) {
+ mLearnMoreContentDescription = learnMoreContentDescription;
+ return this;
+ }
+
+ /**
+ * To set content description of the {@link FooterPreference}. This can use for talkback
+ * environment if developer wants to have a customization content.
+ *
+ * @param learnMoreContentDescriptionResId The resource id of the content description.
+ */
+ public Builder setLearnMoreContentDescription(
+ @StringRes int learnMoreContentDescriptionResId) {
+ mLearnMoreContentDescription = mContext.getText(learnMoreContentDescriptionResId);
+ return this;
+ }
+
+
+ /**
* To generate the {@link FooterPreference}.
*/
public FooterPreference build() {
@@ -184,6 +264,10 @@
if (!TextUtils.isEmpty(mContentDescription)) {
footerPreference.setContentDescription(mContentDescription);
}
+
+ if (!TextUtils.isEmpty(mLearnMoreContentDescription)) {
+ footerPreference.setLearnMoreContentDescription(mLearnMoreContentDescription);
+ }
return footerPreference;
}
}
diff --git a/packages/SettingsLib/MainSwitchPreference/Android.bp b/packages/SettingsLib/MainSwitchPreference/Android.bp
index 4ce854a..23ee49e 100644
--- a/packages/SettingsLib/MainSwitchPreference/Android.bp
+++ b/packages/SettingsLib/MainSwitchPreference/Android.bp
@@ -15,6 +15,7 @@
static_libs: [
"androidx.preference_preference",
+ "SettingsLibSettingsTheme",
],
sdk_version: "system_current",
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-night/colors.xml b/packages/SettingsLib/MainSwitchPreference/res/values-night/colors.xml
index 9ca3683..58ab992 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values-night/colors.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-night/colors.xml
@@ -18,13 +18,4 @@
<resources>
<color name="settingslib_switchbar_switch_track_tint">#82000000</color>
<color name="settingslib_switchbar_switch_thumb_tint">@android:color/black</color>
-
- <!-- Material next thumb off color-->
- <color name="settingslib_thumb_off_color">@android:color/system_neutral2_300</color>
-
- <!-- Material next track on color-->
- <color name="settingslib_track_on_color">@android:color/system_accent2_700</color>
-
- <!-- Material next track off color-->
- <color name="settingslib_track_off_color">@android:color/system_neutral1_700</color>
</resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/colors.xml b/packages/SettingsLib/MainSwitchPreference/res/values/colors.xml
index 2c73238..0c95a9e 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/colors.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/colors.xml
@@ -19,19 +19,4 @@
<color name="settingslib_switchbar_background_color">@*android:color/material_grey_600</color>
<color name="settingslib_switchbar_switch_track_tint">#BFFFFFFF</color>
<color name="settingslib_switchbar_switch_thumb_tint">@android:color/white</color>
-
- <!-- Material next state on color-->
- <color name="settingslib_state_on_color">?androidprv:attr/colorAccentPrimary</color>
-
- <!-- Material next state off color-->
- <color name="settingslib_state_off_color">?androidprv:attr/colorAccentSecondary</color>
-
- <!-- Material next thumb off color-->
- <color name="settingslib_thumb_off_color">@android:color/system_neutral2_100</color>
-
- <!-- Material next track on color-->
- <color name="settingslib_track_on_color">?androidprv:attr/colorAccentPrimaryVariant</color>
-
- <!-- Material next track off color-->
- <color name="settingslib_track_off_color">@android:color/system_neutral2_600</color>
</resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
index 123c477..91e1b93 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
@@ -150,6 +150,9 @@
public void setTitle(CharSequence text) {
if (mTextView != null) {
mTextView.setText(text);
+ if (mSwitch != null) {
+ mSwitch.setContentDescription(mTextView.getText());
+ }
}
}
diff --git a/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
index e92b671..b299061 100644
--- a/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
+++ b/packages/SettingsLib/RadioButtonPreference/res/layout/preference_radio.xml
@@ -58,13 +58,14 @@
android:layout_weight="1"
android:orientation="vertical"
android:paddingTop="16dp"
- android:paddingBottom="16dp">
+ android:paddingBottom="16dp"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:singleLine="true"
+ android:maxLines="2"
android:textAppearance="?android:attr/textAppearanceListItem"/>
<LinearLayout
@@ -109,12 +110,13 @@
android:background="?android:attr/dividerVertical" />
<ImageView
android:id="@+id/radio_extra_widget"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
+ android:minWidth="@dimen/two_target_min_width"
android:layout_height="fill_parent"
android:src="@drawable/ic_settings_accent"
android:contentDescription="@string/settings_label"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
+ android:paddingStart="24dp"
+ android:paddingEnd="24dp"
android:layout_gravity="center"
android:background="?android:attr/selectableItemBackground" />
</LinearLayout>
diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_switch_thumb_color.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_switch_thumb_color.xml
new file mode 100644
index 0000000..df3bad4
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_switch_thumb_color.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Disabled status of thumb -->
+ <item android:state_enabled="false"
+ android:color="@color/settingslib_thumb_off_color" />
+ <!-- Toggle off status of thumb -->
+ <item android:state_checked="false"
+ android:color="@color/settingslib_thumb_off_color" />
+ <!-- Enabled or toggle on status of thumb -->
+ <item android:color="@color/settingslib_state_on_color" />
+</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_switch_track_color.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_switch_track_color.xml
new file mode 100644
index 0000000..9568f52
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_switch_track_color.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Disabled status of thumb -->
+ <item android:state_enabled="false"
+ android:color="@color/settingslib_track_off_color"
+ android:alpha="?android:attr/disabledAlpha" />
+ <!-- Toggle off status of thumb -->
+ <item android:state_checked="false"
+ android:color="@color/settingslib_track_off_color" />
+ <!-- Enabled or toggle on status of thumb -->
+ <item android:color="@color/settingslib_track_on_color" />
+</selector>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v31/settingslib_switch_thumb.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v31/settingslib_switch_thumb.xml
new file mode 100644
index 0000000..87c6dea
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v31/settingslib_switch_thumb.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:top="4dp"
+ android:left="4dp"
+ android:right="4dp"
+ android:bottom="4dp">
+ <shape android:shape="oval" >
+ <size android:height="20dp" android:width="20dp" />
+ <solid android:color="@color/settingslib_switch_thumb_color" />
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v31/settingslib_switch_track.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v31/settingslib_switch_track.xml
new file mode 100644
index 0000000..cb8f3f0
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v31/settingslib_switch_track.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle"
+ android:width="52dp"
+ android:height="28dp">
+
+ <solid android:color="@color/settingslib_switch_track_color" />
+ <corners android:radius="35dp" />
+</shape>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
new file mode 100644
index 0000000..df0e3e1d
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <!-- Material next thumb off color-->
+ <color name="settingslib_thumb_off_color">@android:color/system_neutral2_300</color>
+
+ <!-- Material next track on color-->
+ <color name="settingslib_track_on_color">@android:color/system_accent2_700</color>
+
+ <!-- Material next track off color-->
+ <color name="settingslib_track_off_color">@android:color/system_neutral1_700</color>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
new file mode 100644
index 0000000..c9bc583
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<resources xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <!-- Material next state on color-->
+ <color name="settingslib_state_on_color">?androidprv:attr/colorAccentPrimary</color>
+
+ <!-- Material next state off color-->
+ <color name="settingslib_state_off_color">?androidprv:attr/colorAccentSecondary</color>
+
+ <!-- Material next thumb off color-->
+ <color name="settingslib_thumb_off_color">@android:color/system_neutral2_100</color>
+
+ <!-- Material next track on color-->
+ <color name="settingslib_track_on_color">?androidprv:attr/colorAccentPrimaryVariant</color>
+
+ <!-- Material next track off color-->
+ <color name="settingslib_track_off_color">@android:color/system_neutral2_600</color>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index 83a259e..e3a0239 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
@@ -22,4 +22,10 @@
<style name="TextAppearance.CategoryTitle.SettingsLib"
parent="@*android:style/TextAppearance.DeviceDefault.Body2" />
+
+ <style name="Switch.SettingsLib" parent="@android:style/Widget.Material.CompoundButton.Switch">
+ <item name="android:switchMinWidth">52dp</item>
+ <item name="android:track">@drawable/settingslib_switch_track</item>
+ <item name="android:thumb">@drawable/settingslib_switch_thumb</item>
+ </style>
</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
index 69649e0..adf506d 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
@@ -22,6 +22,7 @@
<item name="android:listPreferredItemPaddingStart">24dp</item>
<item name="android:listPreferredItemPaddingEnd">16dp</item>
<item name="preferenceTheme">@style/PreferenceTheme.SettingsLib</item>
+ <item name="android:switchStyle">@style/Switch.SettingsLib</item>
</style>
<!-- Using in SubSettings page including injected settings page -->
diff --git a/packages/SettingsLib/SettingsTheme/res/values/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
index 3f473a3..25f9514 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
@@ -19,4 +19,5 @@
<dimen name="secondary_app_icon_size">32dp</dimen>
<dimen name="app_preference_padding_start">?android:attr/listPreferredItemPaddingStart</dimen>
<dimen name="app_icon_min_width">56dp</dimen>
+ <dimen name="two_target_min_width">72dp</dimen>
</resources>
diff --git a/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java b/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java
index ed447f8..4612861 100644
--- a/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java
+++ b/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java
@@ -16,6 +16,7 @@
package com.android.settingslib.transition;
+import androidx.annotation.IntDef;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
@@ -29,11 +30,33 @@
import com.google.android.material.transition.platform.MaterialSharedAxis;
import com.google.android.material.transition.platform.SlideDistanceProvider;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* A helper class to apply Settings Transition
*/
public class SettingsTransitionHelper {
+ /**
+ * Flags indicating the type of the transition.
+ */
+ @IntDef({
+ TransitionType.TRANSITION_NONE,
+ TransitionType.TRANSITION_SHARED_AXIS,
+ TransitionType.TRANSITION_SLIDE,
+ TransitionType.TRANSITION_FADE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TransitionType {
+ int TRANSITION_NONE = -1;
+ int TRANSITION_SHARED_AXIS = 0;
+ int TRANSITION_SLIDE = 1;
+ int TRANSITION_FADE = 2;
+ }
+
+ public static final String EXTRA_PAGE_TRANSITION_TYPE = "page_transition_type";
+
private static final String TAG = "SettingsTransitionHelper";
private static final long DURATION = 450L;
private static final float FADE_THROUGH_THRESHOLD = 0.22F;
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
index 52d2b3c..8f3e4bd 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java
@@ -19,7 +19,6 @@
import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_ORDER;
import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_PROFILE;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON;
-import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_URI;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY;
import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY_URI;
@@ -301,16 +300,8 @@
}
int iconResId = mMetaData.getInt(META_DATA_PREFERENCE_ICON);
- // Set the icon
- if (iconResId == 0) {
- // Only fallback to componentInfo.icon if metadata does not contain ICON_URI.
- // ICON_URI should be loaded in app UI when need the icon object. Handling IPC at this
- // level is too complex because we don't have a strong threading contract for this class
- if (!mMetaData.containsKey(META_DATA_PREFERENCE_ICON_URI)) {
- iconResId = getComponentIcon(componentInfo);
- }
- }
- if (iconResId != 0) {
+ // Set the icon. Skip the transparent color for backward compatibility since Android S.
+ if (iconResId != 0 && iconResId != android.R.color.transparent) {
final Icon icon = Icon.createWithResource(componentInfo.packageName, iconResId);
if (isIconTintable(context)) {
final TypedArray a = context.obtainStyledAttributes(new int[]{
diff --git a/packages/SettingsLib/TwoTargetPreference/res/layout/preference_two_target.xml b/packages/SettingsLib/TwoTargetPreference/res/layout/preference_two_target.xml
index 7978e73..2c2756b 100644
--- a/packages/SettingsLib/TwoTargetPreference/res/layout/preference_two_target.xml
+++ b/packages/SettingsLib/TwoTargetPreference/res/layout/preference_two_target.xml
@@ -63,7 +63,7 @@
android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:minWidth="64dp"
+ android:minWidth="@dimen/two_target_min_width"
android:gravity="center"
android:orientation="vertical" />
diff --git a/packages/SettingsLib/res/layout/preference_access_point.xml b/packages/SettingsLib/res/layout/preference_access_point.xml
index 9dc87de..f3f43ac 100644
--- a/packages/SettingsLib/res/layout/preference_access_point.xml
+++ b/packages/SettingsLib/res/layout/preference_access_point.xml
@@ -24,6 +24,8 @@
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:gravity="center_vertical"
android:background="?android:attr/selectableItemBackground"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:clipToPadding="false">
<LinearLayout
@@ -31,9 +33,7 @@
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="start|center_vertical"
- android:clipToPadding="false"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+ android:clipToPadding="false">
<LinearLayout
android:id="@+id/icon_frame"
@@ -89,7 +89,7 @@
android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:minWidth="64dp"
+ android:minWidth="@dimen/two_target_min_width"
android:gravity="center"
android:orientation="vertical" />
@@ -97,7 +97,7 @@
android:id="@+id/icon_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:minWidth="64dp"
+ android:minWidth="@dimen/two_target_min_width"
android:minHeight="@dimen/min_tap_target_size"
android:layout_gravity="center"
android:background="?android:attr/selectableItemBackground"
diff --git a/packages/SettingsLib/res/layout/preference_checkable_two_target.xml b/packages/SettingsLib/res/layout/preference_checkable_two_target.xml
index 1ae1c89..e4f7242 100644
--- a/packages/SettingsLib/res/layout/preference_checkable_two_target.xml
+++ b/packages/SettingsLib/res/layout/preference_checkable_two_target.xml
@@ -24,6 +24,8 @@
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:gravity="center_vertical"
android:background="@android:color/transparent"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:clipToPadding="false">
<LinearLayout
@@ -32,9 +34,7 @@
android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:gravity="start|center_vertical"
- android:clipToPadding="false"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+ android:clipToPadding="false">
<LinearLayout
android:id="@+id/checkbox_container"
@@ -86,7 +86,7 @@
android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:minWidth="64dp"
+ android:minWidth="@dimen/two_target_min_width"
android:gravity="center"
android:orientation="vertical" />
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 4e30f38..8b703f6 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -515,7 +515,7 @@
<string name="alarms_and_reminders_footer_title" product="device" msgid="349578867821273761">"يمكنك السماح لهذا التطبيق بضبط المنبّهات وجدولة الإجراءات الأخرى. قد يتم استخدام هذا التطبيق عند عدم استخدامك للجهاز، مما قد يستهلك المزيد من شحن البطارية. إذا كان هذا الإذن غير مفعّل، قد لا يعمل هذا التطبيق بشكل طبيعي ولن تعمل المنبّهات فيه كما هو مقرر."</string>
<string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"جدول زمني، جدولة، منبّه، تذكير، ساعة"</string>
<string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"تفعيل"</string>
- <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"تفعيل وضع \"الرجاء عدم الإزعاج\""</string>
+ <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"تفعيل ميزة \"عدم الإزعاج\""</string>
<string name="zen_mode_settings_summary_off" msgid="3832876036123504076">"مطلقًا"</string>
<string name="zen_interruption_level_priority" msgid="5392140786447823299">"الأولوية فقط"</string>
<string name="zen_mode_and_condition" msgid="8877086090066332516">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 36bdf47..e5aa95d 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afficher les options pour la certification d\'affichage sans fil"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Détailler davantage les données Wi-Fi, afficher par SSID RSSI dans sélect. Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Réduit l\'utilisation de la pile et améliore les performances réseau"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Lorsque ce mode est activé, l\'adresse MAC de cet appareil pourrait changer chaque fois qu\'il se connecter à un réseau sur lequel la sélection aléatoire des adresses MAC est activée."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Lorsque ce mode est activé, l\'adresse MAC de cet appareil pourrait changer chaque fois qu\'il se connecte à un réseau sur lequel la sélection aléatoire des adresses MAC est activée."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Facturé à l\'usage"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Non mesuré"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tailles des mémoires tampons d\'enregistreur"</string>
@@ -376,7 +376,7 @@
<string name="force_allow_on_external" msgid="9187902444231637880">"Forcer l\'autor. d\'applis sur stockage externe"</string>
<string name="force_allow_on_external_summary" msgid="8525425782530728238">"Rend possible l\'enregistrement de toute application sur un espace de stockage externe, indépendamment des valeurs du fichier manifeste"</string>
<string name="force_resizable_activities" msgid="7143612144399959606">"Forcer les activités à être redimensionnables"</string>
- <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permet de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string>
+ <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permet de redimensionner toutes les activités pour le mode multi-fenêtre, indépendamment des valeurs du fichier manifeste."</string>
<string name="enable_freeform_support" msgid="7599125687603914253">"Activer les fenêtres de forme libre"</string>
<string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activer la compatibilité avec les fenêtres de forme libre expérimentales."</string>
<string name="local_backup_password_title" msgid="4631017948933578709">"Mot de passe sauvegarde PC"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index da62ded..2dc05f4 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -474,7 +474,7 @@
<item msgid="7529124349186240216">"100%"</item>
</string-array>
<string name="charge_length_format" msgid="6941645744588690932">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
- <string name="remaining_length_format" msgid="4310625772926171089">"还需 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+ <string name="remaining_length_format" msgid="4310625772926171089">"还可以使用 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
<string name="screen_zoom_summary_small" msgid="6050633151263074260">"小"</string>
<string name="screen_zoom_summary_default" msgid="1888865694033865408">"默认"</string>
<string name="screen_zoom_summary_large" msgid="4706951482598978984">"大"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 404299a..af8cd1e 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1133,7 +1133,7 @@
<!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
<string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="time">%2$s</xliff:g> left until full</string>
<!-- [CHAR_LIMIT=80] Label for battery level chart when charge been limited -->
- <string name="power_charging_limited"><xliff:g id="level">%1$s</xliff:g> - Optimizing for battery health</string>
+ <string name="power_charging_limited"><xliff:g id="level">%1$s</xliff:g> - Charging temporarily limited</string>
<!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="battery_info_status_unknown">Unknown</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 4558a8a..fe92e26 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -1222,19 +1222,22 @@
*/
public Pair<Drawable, String> getDrawableWithDescription() {
Uri uri = BluetoothUtils.getUriMetaData(mDevice, BluetoothDevice.METADATA_MAIN_ICON);
+ Pair<Drawable, String> pair = BluetoothUtils.getBtClassDrawableWithDescription(
+ mContext, this);
+
if (BluetoothUtils.isAdvancedDetailsHeader(mDevice) && uri != null) {
BitmapDrawable drawable = mDrawableCache.get(uri.toString());
if (drawable != null) {
Resources resources = mContext.getResources();
return new Pair<>(new AdaptiveOutlineDrawable(
- resources, drawable.getBitmap()),
- BluetoothUtils.getBtClassDrawableWithDescription(mContext, this).second);
+ resources, drawable.getBitmap()), pair.second);
}
refresh();
}
- return BluetoothUtils.getBtRainbowDrawableWithDescription(mContext, this);
+ return new Pair<>(BluetoothUtils.buildBtRainbowDrawable(
+ mContext, pair.first, getAddress().hashCode()), pair.second);
}
void releaseLruCache() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
index bd0b9e9..6cb60d1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
@@ -98,7 +98,7 @@
/**
* Logs a simple action without page id or attribution
*/
- public void action(Context context, int category, Pair<Integer, Object>... taggedData) {
+ public void action(Context context, int category, Pair<Integer, Object>... taggedData) {
for (LogWriter writer : mLoggerWriters) {
writer.action(context, category, taggedData);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminController.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminController.java
index 8730af1..6d7f8df 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledByAdminController.java
@@ -16,11 +16,9 @@
package com.android.settingslib.enterprise;
-import android.app.Activity;
import android.content.Context;
import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog.Builder;
import com.android.settingslib.RestrictedLockUtils;
@@ -33,7 +31,7 @@
* Handles the adding and setting up of the learn more button. If button is not needed, then
* this method can be left empty.
*/
- void setupLearnMoreButton(Activity activity, Builder builder);
+ void setupLearnMoreButton(Context context, Object alertDialogBuilder);
/**
* Returns the admin support dialog's title resource id.
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledLearnMoreButtonLauncher.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledLearnMoreButtonLauncher.java
index 9d2df23..65b91f1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledLearnMoreButtonLauncher.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/ActionDisabledLearnMoreButtonLauncher.java
@@ -16,9 +16,7 @@
package com.android.settingslib.enterprise;
-import android.app.Activity;
-
-import androidx.appcompat.app.AlertDialog;
+import android.content.Context;
import com.android.settingslib.RestrictedLockUtils;
@@ -31,8 +29,8 @@
* Sets up a "learn more" button which shows a screen with device policy settings
*/
void setupLearnMoreButtonToShowAdminPolicies(
- Activity activity,
- AlertDialog.Builder builder,
+ Context context,
+ Object alertDialogBuilder,
int enforcementAdminUserId,
RestrictedLockUtils.EnforcedAdmin enforcedAdmin);
@@ -40,7 +38,7 @@
* Sets up a "learn more" button which launches a help page
*/
void setupLearnMoreButtonToLaunchHelpPage(
- Activity activity,
- AlertDialog.Builder builder,
+ Context context,
+ Object alertDialogBuilder,
String url);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/FinancedDeviceActionDisabledByAdminController.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/FinancedDeviceActionDisabledByAdminController.java
index 587979d..cd816e88 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/FinancedDeviceActionDisabledByAdminController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/FinancedDeviceActionDisabledByAdminController.java
@@ -19,11 +19,9 @@
import static java.util.Objects.requireNonNull;
import android.annotation.UserIdInt;
-import android.app.Activity;
import android.content.Context;
import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog.Builder;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
@@ -41,21 +39,22 @@
FinancedDeviceActionDisabledByAdminController(
ActionDisabledLearnMoreButtonLauncher helper,
DeviceAdminStringProvider deviceAdminStringProvider) {
- mHelper = requireNonNull(helper);
- mDeviceAdminStringProvider = requireNonNull(deviceAdminStringProvider);
+ mHelper = requireNonNull(helper, "helper cannot be null");
+ mDeviceAdminStringProvider = requireNonNull(deviceAdminStringProvider,
+ "deviceAdminStringProvider cannot be null");
}
@Override
public void updateEnforcedAdmin(EnforcedAdmin admin, int adminUserId) {
mEnforcementAdminUserId = adminUserId;
- mEnforcedAdmin = requireNonNull(admin);
+ mEnforcedAdmin = requireNonNull(admin, "admin cannot be null");
}
@Override
- public void setupLearnMoreButton(Activity activity, Builder builder) {
+ public void setupLearnMoreButton(Context context, Object alertDialogBuilder) {
mHelper.setupLearnMoreButtonToShowAdminPolicies(
- activity,
- builder,
+ context,
+ alertDialogBuilder,
mEnforcementAdminUserId,
mEnforcedAdmin);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java
index 624c88e..70e19f9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java
@@ -19,14 +19,11 @@
import static java.util.Objects.requireNonNull;
import android.annotation.UserIdInt;
-import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.os.UserManager;
import android.text.TextUtils;
-import androidx.appcompat.app.AlertDialog.Builder;
-
import com.android.settingslib.RestrictedLockUtils;
/**
@@ -49,20 +46,20 @@
@Override
public void updateEnforcedAdmin(RestrictedLockUtils.EnforcedAdmin admin, int adminUserId) {
mEnforcementAdminUserId = adminUserId;
- mEnforcedAdmin = requireNonNull(admin);
+ mEnforcedAdmin = requireNonNull(admin, "admin cannot be null");
}
@Override
- public void setupLearnMoreButton(Activity activity, Builder builder) {
+ public void setupLearnMoreButton(Context context, Object alertDialogBuilder) {
String url = mStringProvider.getLearnMoreHelpPageUrl();
if (TextUtils.isEmpty(url)) {
mHelper.setupLearnMoreButtonToShowAdminPolicies(
- activity,
- builder,
+ context,
+ alertDialogBuilder,
mEnforcementAdminUserId,
mEnforcedAdmin);
} else {
- mHelper.setupLearnMoreButtonToLaunchHelpPage(activity, builder, url);
+ mHelper.setupLearnMoreButtonToLaunchHelpPage(context, alertDialogBuilder, url);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 38172f7..f523354 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -31,7 +31,9 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
+import android.graphics.drawable.BitmapDrawable;
import android.media.AudioManager;
+import android.util.LruCache;
import com.android.settingslib.R;
import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
@@ -961,6 +963,10 @@
@Test
public void getDrawableWithDescription_isAdvancedDevice_returnAdvancedIcon() {
+ LruCache lruCache = mock(LruCache.class);
+ mCachedDevice.mDrawableCache = lruCache;
+ BitmapDrawable drawable = mock(BitmapDrawable.class);
+ when(lruCache.get("fake_uri")).thenReturn(drawable);
when(mDevice.getMetadata(BluetoothDevice.METADATA_MAIN_ICON))
.thenReturn("fake_uri".getBytes());
when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ActivityTileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ActivityTileTest.java
index 4f8ecf8..aa6b0bf 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ActivityTileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/ActivityTileTest.java
@@ -105,11 +105,10 @@
}
@Test
- public void getIcon_noIconMetadata_returnActivityIcon() {
- mActivityInfo.metaData.putInt(META_DATA_PREFERENCE_ICON, 0);
+ public void getIcon_transparentColorInMetadata_returnNull() {
+ mActivityInfo.metaData.putInt(META_DATA_PREFERENCE_ICON, android.R.color.transparent);
- assertThat(mTile.getIcon(RuntimeEnvironment.application).getResId())
- .isEqualTo(mActivityInfo.icon);
+ assertThat(mTile.getIcon(RuntimeEnvironment.application)).isNull();
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerTestUtils.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerTestUtils.java
index e0c9424..4b51790 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerTestUtils.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/enterprise/ActionDisabledByAdminControllerTestUtils.java
@@ -19,6 +19,7 @@
import static com.google.common.truth.Truth.assertThat;
import android.app.Activity;
+import android.content.Context;
import androidx.appcompat.app.AlertDialog;
@@ -37,15 +38,15 @@
ActionDisabledLearnMoreButtonLauncher createLearnMoreButtonLauncher() {
return new ActionDisabledLearnMoreButtonLauncher() {
@Override
- public void setupLearnMoreButtonToShowAdminPolicies(Activity activity,
- AlertDialog.Builder builder, int enforcementAdminUserId,
+ public void setupLearnMoreButtonToShowAdminPolicies(Context context,
+ Object alertDialogBuilder, int enforcementAdminUserId,
RestrictedLockUtils.EnforcedAdmin enforcedAdmin) {
mLearnMoreButtonAction = LEARN_MORE_ACTION_SHOW_ADMIN_POLICIES;
}
@Override
- public void setupLearnMoreButtonToLaunchHelpPage(Activity activity,
- AlertDialog.Builder builder, String url) {
+ public void setupLearnMoreButtonToLaunchHelpPage(Context context,
+ Object alertDialogBuilder, String url) {
mLearnMoreButtonAction = LEARN_MORE_ACTION_LAUNCH_HELP_PAGE;
}
};
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
index 4503669..10ac829 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
@@ -69,4 +69,19 @@
assertThat(mFooterPreference.getContentDescription()).isEqualTo("test");
}
+
+ @Test
+ public void setLearnMoreContentDescription_contentSet_shouldGetSameContentDescription() {
+ mFooterPreference.setLearnMoreContentDescription("test");
+
+ assertThat(mFooterPreference.getLearnMoreContentDescription()).isEqualTo("test");
+ }
+
+ @Test
+ public void setLearnMoreAction_actionSet_shouldGetAction() {
+ mFooterPreference.setLearnMoreAction(v -> {
+ });
+
+ assertThat(mFooterPreference.mLearnMoreListener).isNotNull();
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java
index a807753..701a343 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchBarTest.java
@@ -59,6 +59,16 @@
}
@Test
+ public void setTitle_switchShouldHasContentDescription() {
+ final String title = "title";
+
+ mBar.setTitle(title);
+
+ final Switch switchObj = mBar.getSwitch();
+ assertThat(switchObj.getContentDescription()).isEqualTo(title);
+ }
+
+ @Test
public void getSwitch_shouldNotNull() {
final Switch switchObj = mBar.getSwitch();
diff --git a/packages/SettingsProvider/OWNERS b/packages/SettingsProvider/OWNERS
index cf9799c..6c61d4b9 100644
--- a/packages/SettingsProvider/OWNERS
+++ b/packages/SettingsProvider/OWNERS
@@ -4,3 +4,4 @@
svetoslavganov@google.com
schfan@google.com
toddke@google.com
+patb@google.com
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 2f54e21..e5eecb2 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -896,9 +896,6 @@
dumpSetting(s, p,
Settings.Global.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS,
GlobalSettingsProto.Location.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS);
- dumpSetting(s, p,
- Settings.Global.LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST,
- GlobalSettingsProto.Location.IGNORE_SETTINGS_PACKAGE_WHITELIST);
p.end(locationToken);
final long lpmToken = p.start(GlobalSettingsProto.LOW_POWER_MODE);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 3a82434..f538875 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -321,7 +321,6 @@
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
Settings.Global.LOCATION_ENABLE_STATIONARY_THROTTLE,
- Settings.Global.LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST,
Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
Settings.Global.LOCK_SOUND,
Settings.Global.LOOPER_STATS,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 6e256c1..d2947c6 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -528,6 +528,7 @@
<!-- Permission required for hotword detection service CTS tests -->
<uses-permission android:name="android.permission.MANAGE_HOTWORD_DETECTION" />
+ <uses-permission android:name="android.permission.BIND_HOTWORD_DETECTION_SERVICE" />
<uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION"/>
diff --git a/packages/Shell/OWNERS b/packages/Shell/OWNERS
index 6d738f8..177f86b 100644
--- a/packages/Shell/OWNERS
+++ b/packages/Shell/OWNERS
@@ -7,6 +7,7 @@
hackbod@google.com
yamasani@google.com
toddke@google.com
+patb@google.com
cbrubaker@google.com
omakoto@google.com
michaelwr@google.com
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 1cf0c5f..2b87737 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -4,12 +4,15 @@
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.app.ActivityManager
+import android.app.ActivityTaskManager
import android.app.PendingIntent
import android.content.Context
import android.graphics.Matrix
import android.graphics.Rect
+import android.graphics.RectF
import android.os.Looper
import android.os.RemoteException
+import android.util.Log
import android.util.MathUtils
import android.view.IRemoteAnimationFinishedCallback
import android.view.IRemoteAnimationRunner
@@ -30,6 +33,8 @@
* nicely into the starting window.
*/
class ActivityLaunchAnimator(context: Context) {
+ private val TAG = this::class.java.simpleName
+
companion object {
const val ANIMATION_DURATION = 500L
const val ANIMATION_DURATION_FADE_OUT_CONTENT = 183L
@@ -78,29 +83,49 @@
* If [controller] is null or [animate] is false, then the intent will be started and no
* animation will run.
*
+ * If possible, you should pass the [packageName] of the intent that will be started so that
+ * trampoline activity launches will also be animated.
+ *
* This method will throw any exception thrown by [intentStarter].
*/
@JvmOverloads
- inline fun startIntentWithAnimation(
+ fun startIntentWithAnimation(
controller: Controller?,
animate: Boolean = true,
+ packageName: String? = null,
intentStarter: (RemoteAnimationAdapter?) -> Int
) {
if (controller == null || !animate) {
+ Log.d(TAG, "Starting intent with no animation")
intentStarter(null)
controller?.callOnIntentStartedOnMainThread(willAnimate = false)
return
}
+ Log.d(TAG, "Starting intent with a launch animation")
val runner = Runner(controller)
val animationAdapter = RemoteAnimationAdapter(
runner,
ANIMATION_DURATION,
ANIMATION_DURATION - 150 /* statusBarTransitionDelay */
)
+
+ // Register the remote animation for the given package to also animate trampoline
+ // activity launches.
+ if (packageName != null) {
+ try {
+ ActivityTaskManager.getService().registerRemoteAnimationForNextActivityStart(
+ packageName, animationAdapter)
+ } catch (e: RemoteException) {
+ Log.w(TAG, "Unable to register the remote animation", e)
+ }
+ }
+
val launchResult = intentStarter(animationAdapter)
val willAnimate = launchResult == ActivityManager.START_TASK_TO_FRONT ||
launchResult == ActivityManager.START_SUCCESS
+
+ Log.d(TAG, "launchResult=$launchResult willAnimate=$willAnimate")
controller.callOnIntentStartedOnMainThread(willAnimate)
// If we expect an animation, post a timeout to cancel it in case the remote animation is
@@ -110,7 +135,6 @@
}
}
- @PublishedApi
internal fun Controller.callOnIntentStartedOnMainThread(willAnimate: Boolean) {
if (Looper.myLooper() != Looper.getMainLooper()) {
this.launchContainer.context.mainExecutor.execute {
@@ -125,15 +149,21 @@
* Same as [startIntentWithAnimation] but allows [intentStarter] to throw a
* [PendingIntent.CanceledException] which must then be handled by the caller. This is useful
* for Java caller starting a [PendingIntent].
+ *
+ * If possible, you should pass the [packageName] of the intent that will be started so that
+ * trampoline activity launches will also be animated.
*/
@Throws(PendingIntent.CanceledException::class)
@JvmOverloads
fun startPendingIntentWithAnimation(
controller: Controller?,
animate: Boolean = true,
+ packageName: String? = null,
intentStarter: PendingIntentStarter
) {
- startIntentWithAnimation(controller, animate) { intentStarter.startPendingIntent(it) }
+ startIntentWithAnimation(controller, animate, packageName) {
+ intentStarter.startPendingIntent(it)
+ }
}
/** Create a new animation [Runner] controlled by [controller]. */
@@ -278,11 +308,14 @@
@VisibleForTesting
inner class Runner(private val controller: Controller) : IRemoteAnimationRunner.Stub() {
private val launchContainer = controller.launchContainer
- @PublishedApi internal val context = launchContainer.context
+ private val context = launchContainer.context
private val transactionApplier = SyncRtSurfaceTransactionApplier(launchContainer)
private var animator: ValueAnimator? = null
+ private val matrix = Matrix()
+ private val invertMatrix = Matrix()
private var windowCrop = Rect()
+ private var windowCropF = RectF()
private var timedOut = false
private var cancelled = false
@@ -294,7 +327,6 @@
// posting it.
private var onTimeout = Runnable { onAnimationTimedOut() }
- @PublishedApi
internal fun postTimeout() {
launchContainer.postDelayed(onTimeout, LAUNCH_TIMEOUT)
}
@@ -336,11 +368,13 @@
remoteAnimationNonAppTargets: Array<out RemoteAnimationTarget>,
iCallback: IRemoteAnimationFinishedCallback
) {
+ Log.d(TAG, "Remote animation started")
val window = remoteAnimationTargets.firstOrNull {
it.mode == RemoteAnimationTarget.MODE_OPENING
}
if (window == null) {
+ Log.d(TAG, "Aborting the animation as no window is opening")
removeTimeout()
invokeCallback(iCallback)
controller.onLaunchAnimationCancelled()
@@ -399,10 +433,12 @@
animator.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationStart(animation: Animator?, isReverse: Boolean) {
+ Log.d(TAG, "Animation started")
controller.onLaunchAnimationStart(isExpandingFullyAbove)
}
override fun onAnimationEnd(animation: Animator?) {
+ Log.d(TAG, "Animation ended")
invokeCallback(iCallback)
controller.onLaunchAnimationEnd(isExpandingFullyAbove)
}
@@ -447,19 +483,52 @@
}
private fun applyStateToWindow(window: RemoteAnimationTarget, state: State) {
- val m = Matrix()
- m.postTranslate(0f, (state.top - window.sourceContainerBounds.top).toFloat())
- windowCrop.set(state.left, 0, state.right, state.height)
+ val screenBounds = window.screenSpaceBounds
+ val centerX = (screenBounds.left + screenBounds.right) / 2f
+ val centerY = (screenBounds.top + screenBounds.bottom) / 2f
+ val width = screenBounds.right - screenBounds.left
+ val height = screenBounds.bottom - screenBounds.top
- val cornerRadius = minOf(state.topCornerRadius, state.bottomCornerRadius)
+ // Scale the window. We use the max of (widthRatio, heightRatio) so that there is no
+ // blank space on any side.
+ val widthRatio = state.width.toFloat() / width
+ val heightRatio = state.height.toFloat() / height
+ val scale = maxOf(widthRatio, heightRatio)
+ matrix.reset()
+ matrix.setScale(scale, scale, centerX, centerY)
+
+ // Align it to the top and center it in the x-axis.
+ val heightChange = height * scale - height
+ val translationX = state.centerX - centerX
+ val translationY = state.top - screenBounds.top + heightChange / 2f
+ matrix.postTranslate(translationX, translationY)
+
+ // Crop it. The matrix will also be applied to the crop, so we apply the inverse
+ // operation. Given that we only scale (by factor > 0) then translate, we can assume
+ // that the matrix is invertible.
+ val cropX = state.left.toFloat() - screenBounds.left
+ val cropY = state.top.toFloat() - screenBounds.top
+ windowCropF.set(cropX, cropY, cropX + state.width, cropY + state.height)
+ matrix.invert(invertMatrix)
+ invertMatrix.mapRect(windowCropF)
+ windowCrop.set(
+ windowCropF.left.roundToInt(),
+ windowCropF.top.roundToInt(),
+ windowCropF.right.roundToInt(),
+ windowCropF.bottom.roundToInt()
+ )
+
+ // The scale will also be applied to the corner radius, so we divide by the scale to
+ // keep the original radius.
+ val cornerRadius = minOf(state.topCornerRadius, state.bottomCornerRadius) / scale
val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(window.leash)
- .withAlpha(1f)
- .withMatrix(m)
- .withWindowCrop(windowCrop)
- .withLayer(window.prefixOrderIndex)
- .withCornerRadius(cornerRadius)
- .withVisibility(true)
- .build()
+ .withAlpha(1f)
+ .withMatrix(matrix)
+ .withWindowCrop(windowCrop)
+ .withLayer(window.prefixOrderIndex)
+ .withCornerRadius(cornerRadius)
+ .withVisibility(true)
+ .build()
transactionApplier.scheduleApply(params)
}
@@ -474,12 +543,13 @@
val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(navigationBar.leash)
if (fadeInProgress > 0) {
- val m = Matrix()
- m.postTranslate(0f, (state.top - navigationBar.sourceContainerBounds.top).toFloat())
+ matrix.reset()
+ matrix.setTranslate(
+ 0f, (state.top - navigationBar.sourceContainerBounds.top).toFloat())
windowCrop.set(state.left, 0, state.right, state.height)
params
.withAlpha(NAV_FADE_IN_INTERPOLATOR.getInterpolation(fadeInProgress))
- .withMatrix(m)
+ .withMatrix(matrix)
.withWindowCrop(windowCrop)
.withVisibility(true)
} else {
@@ -496,6 +566,7 @@
return
}
+ Log.d(TAG, "Remote animation timed out")
timedOut = true
controller.onLaunchAnimationCancelled()
}
@@ -505,6 +576,7 @@
return
}
+ Log.d(TAG, "Remote animation was cancelled")
cancelled = true
removeTimeout()
context.mainExecutor.execute {
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
index 044b5ed..e1f72c1 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
@@ -96,13 +96,18 @@
/**
* Interpolate alpha for notifications background scrim during shade expansion.
* @param fraction Shade expansion fraction
+ * @param forNotification If we want the alpha of the notification shade or the scrim.
*/
- public static float getNotificationScrimAlpha(float fraction) {
+ public static float getNotificationScrimAlpha(float fraction, boolean forNotification) {
+ if (!forNotification) {
+ fraction = MathUtils.saturate(1.7f * fraction);
+ }
fraction = fraction * 1.2f - 0.2f;
if (fraction <= 0) {
return 0;
} else {
- return (float) (1f - 0.5f * (1f - Math.cos(3.14159f * Math.pow(1f - fraction, 2f))));
+ final float oneMinusFrac = 1f - fraction;
+ return (float) (1f - 0.5f * (1f - Math.cos(3.14159f * oneMinusFrac * oneMinusFrac)));
}
}
}
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index b3c4374..989010e 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -114,6 +114,11 @@
* Set or clear next alarm information
*/
void setNextAlarm(@Nullable Drawable image, @Nullable String description);
+
+ /**
+ * Set or clear device media playing
+ */
+ void setMediaTarget(@Nullable SmartspaceTarget target);
}
/** Interface for launching Intents, which can differ on the lockscreen */
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index 83a0a32..2742ac3 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -22,7 +22,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="514691256816366517">"Teklatu-babeslea"</string>
<string name="keyguard_password_enter_pin_code" msgid="8582296866585566671">"Idatzi PIN kodea"</string>
- <string name="keyguard_password_enter_puk_code" msgid="3813154965969758868">"Idatzi SIM txartelaren PUK kodea eta PIN kode berria"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="3813154965969758868">"Idatzi SIM txartelaren PUKa eta PIN berria"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="3529260761374385243">"SIM txartelaren PUK kodea"</string>
<string name="keyguard_password_enter_pin_prompt" msgid="2304037870481240781">"SIM txartelaren PIN berria"</string>
<string name="keyguard_password_entry_touch_hint" msgid="6180028658339706333"><font size="17">"Pasahitza idazteko, sakatu hau"</font></string>
@@ -31,7 +31,7 @@
<string name="keyguard_enter_your_pin" msgid="5429932527814874032">"Idatzi PIN kodea"</string>
<string name="keyguard_enter_your_pattern" msgid="351503370332324745">"Marraztu eredua"</string>
<string name="keyguard_enter_your_password" msgid="7225626204122735501">"Idatzi pasahitza"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"PIN kode hori ez da zuzena."</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="3514267777289393046">"PINa ez da zuzena."</string>
<string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Txartelak ez du balio."</string>
<string name="keyguard_charged" msgid="5478247181205188995">"Kargatuta"</string>
<string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hari gabe kargatzen"</string>
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index d6fdfaf..88c52d9 100644
--- a/packages/SystemUI/res-keyguard/values-lv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml
@@ -39,7 +39,7 @@
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Notiek ātrā uzlāde"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Notiek lēnā uzlāde"</string>
<string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Akumulatora darbības optimizēšana"</string>
- <string name="keyguard_low_battery" msgid="1868012396800230904">"Pievienojiet uzlādes ierīci."</string>
+ <string name="keyguard_low_battery" msgid="1868012396800230904">"Pievienojiet lādētāju."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Lai atbloķētu, nospiediet izvēlnes ikonu."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Tīkls ir bloķēts."</string>
<string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nav SIM kartes."</string>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 4b662137..caa2166 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -79,8 +79,8 @@
is not fully charged, and it's plugged into a slow charger, say that it's charging slowly. -->
<string name="keyguard_plugged_in_charging_slowly"><xliff:g id="percentage">%s</xliff:g> • Charging slowly</string>
- <!-- When the lock screen is showing and the phone plugged in, and the defend mode is triggered, say that it's optimizing for battery health. -->
- <string name="keyguard_plugged_in_charging_limited"><xliff:g id="percentage">%s</xliff:g> • Optimizing for battery health</string>
+ <!-- When the lock screen is showing and the phone plugged in, and the defend mode is triggered, say that it's charging temporarily limited. -->
+ <string name="keyguard_plugged_in_charging_limited"><xliff:g id="percentage">%s</xliff:g> • Charging temporarily limited</string>
<!-- When the lock screen is showing and the battery is low, warn user to plug
in the phone soon. -->
diff --git a/packages/SystemUI/res/drawable/action_chip_background.xml b/packages/SystemUI/res/drawable/action_chip_background.xml
index ac227a6..0e1453c 100644
--- a/packages/SystemUI/res/drawable/action_chip_background.xml
+++ b/packages/SystemUI/res/drawable/action_chip_background.xml
@@ -16,12 +16,12 @@
-->
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:color="@color/global_screenshot_button_ripple">
<item android:id="@android:id/background">
<shape android:shape="rectangle">
- <stroke android:width="1dp" android:color="@color/global_screenshot_button_border"/>
- <solid android:color="@color/global_screenshot_button_background"/>
+ <solid android:color="?androidprv:attr/colorAccentSecondary"/>
<corners android:radius="@dimen/screenshot_button_corner_radius"/>
</shape>
</item>
-</ripple>
\ No newline at end of file
+</ripple>
diff --git a/packages/SystemUI/res/drawable/action_chip_container_background.xml b/packages/SystemUI/res/drawable/action_chip_container_background.xml
index 095213e..72767a1 100644
--- a/packages/SystemUI/res/drawable/action_chip_container_background.xml
+++ b/packages/SystemUI/res/drawable/action_chip_container_background.xml
@@ -14,8 +14,10 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="@color/global_screenshot_button_background"/>
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorSurface"/>
<corners android:radius="@dimen/screenshot_action_container_corner_radius"/>
-</shape>
\ No newline at end of file
+</shape>
diff --git a/packages/SystemUI/res/drawable/ic_cake.xml b/packages/SystemUI/res/drawable/ic_cake.xml
new file mode 100644
index 0000000..9c83b43
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_cake.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M19,14v-4c0,-1.1 -0.9,-2 -2,-2h-4L13,6.55c0.15,-0.09 0.29,-0.18 0.41,-0.31 0.39,-0.39 0.59,-0.92 0.59,-1.42s-0.2,-1.02 -0.59,-1.41L12,2l-1.41,1.41c-0.39,0.39 -0.59,0.91 -0.59,1.41s0.2,1.03 0.59,1.42c0.13,0.13 0.27,0.22 0.41,0.31L11,8L7,8c-1.1,0 -2,0.9 -2,2v4c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-4c0,-1.1 -0.9,-2 -2,-2zM7,10h10v4L7,14v-4zM19,20L5,20v-4h14v4z"
+ android:fillColor="#FFFFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_celebration.xml b/packages/SystemUI/res/drawable/ic_celebration.xml
new file mode 100644
index 0000000..10fe406
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_celebration.xml
@@ -0,0 +1,37 @@
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M2,22l14,-5L7,8L2,22zM12.35,16.18L5.3,18.7l2.52,-7.05L12.35,16.18z"
+ android:fillColor="#FFFFFFFF"/>
+ <path
+ android:pathData="M14.53,12.53l5.59,-5.59c0.49,-0.49 1.28,-0.49 1.77,0l0.59,0.59l1.06,-1.06l-0.59,-0.59c-1.07,-1.07 -2.82,-1.07 -3.89,0l-5.59,5.59L14.53,12.53z"
+ android:fillColor="#FFFFFFFF"/>
+ <path
+ android:pathData="M10.06,6.88L9.47,7.47l1.06,1.06l0.59,-0.59c1.07,-1.07 1.07,-2.82 0,-3.89l-0.59,-0.59L9.47,4.53l0.59,0.59C10.54,5.6 10.54,6.4 10.06,6.88z"
+ android:fillColor="#FFFFFFFF"/>
+ <path
+ android:pathData="M17.06,11.88l-1.59,1.59l1.06,1.06l1.59,-1.59c0.49,-0.49 1.28,-0.49 1.77,0l1.61,1.61l1.06,-1.06l-1.61,-1.61C19.87,10.81 18.13,10.81 17.06,11.88z"
+ android:fillColor="#FFFFFFFF"/>
+ <path
+ android:pathData="M15.06,5.88l-3.59,3.59l1.06,1.06l3.59,-3.59c1.07,-1.07 1.07,-2.82 0,-3.89l-1.59,-1.59l-1.06,1.06l1.59,1.59C15.54,4.6 15.54,5.4 15.06,5.88z"
+ android:fillColor="#FFFFFFFF"/>
+</vector>
+
diff --git a/packages/SystemUI/res/drawable/ic_gift.xml b/packages/SystemUI/res/drawable/ic_gift.xml
new file mode 100644
index 0000000..fab36c3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_gift.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M22,5h-5.18C16.93,4.69 17,4.35 17,4c0,-1.65 -1.35,-3 -3,-3c-0.77,0 -1.47,0.3 -2,0.78C11.47,1.3 10.77,1 10,1C8.35,1 7,2.35 7,4c0,0.35 0.07,0.69 0.18,1H2v6h2v11h16V11h2V5zM14,3c0.55,0 1,0.45 1,1s-0.45,1 -1,1s-1,-0.45 -1,-1S13.45,3 14,3zM9,4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1s-0.45,1 -1,1S9,4.55 9,4zM4,7h7v2H4V7zM6,11h5v9H6V11zM18,20h-5v-9h5V20zM20,9h-7V7h7V9z"
+ android:fillColor="#FFFFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_pages.xml b/packages/SystemUI/res/drawable/ic_pages.xml
new file mode 100644
index 0000000..9cd076d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_pages.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M19,5v14L5,19L5,5h14m0,-2L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM12,17l1.57,-3.43L17,12l-3.43,-1.57L12,7l-1.57,3.43L7,12l3.43,1.57L12,17z"
+ android:fillColor="#FFFFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_play_games.xml b/packages/SystemUI/res/drawable/ic_play_games.xml
new file mode 100644
index 0000000..20096f4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_play_games.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M20.47,8c-0.39,-2.3 -2.4,-4 -4.81,-4L8.34,4C5.93,4 3.93,5.7 3.53,8 3.53,8 2,16.8 2,16.93 2,18.07 2.93,19 4.07,19c0.57,0 1.09,-0.2 1.47,-0.58L9,15h6l3.46,3.42c0.38,0.38 0.89,0.58 1.47,0.58 1.15,0 2.07,-0.93 2.07,-2.07C22,16.8 20.47,8 20.47,8zM11,10L9,10v2L8,12v-2L6,10L6,9h2L8,7h1v2h2v1zM13.8,10.3c-0.44,0 -0.8,-0.36 -0.8,-0.8 0,-0.44 0.36,-0.8 0.8,-0.8 0.44,0 0.8,0.36 0.8,0.8 0,0.44 -0.36,0.8 -0.8,0.8zM15.49,12c-0.44,0 -0.8,-0.36 -0.8,-0.8 0,-0.44 0.36,-0.8 0.8,-0.8 0.44,0 0.8,0.36 0.8,0.8 0,0.44 -0.36,0.8 -0.8,0.8zM15.49,8.6c-0.44,0 -0.8,-0.36 -0.8,-0.8s0.36,-0.8 0.8,-0.8c0.44,0 0.8,0.36 0.8,0.8s-0.36,0.8 -0.8,0.8zM17.2,10.3c-0.44,0 -0.8,-0.36 -0.8,-0.8 0,-0.44 0.36,-0.8 0.8,-0.8s0.8,0.36 0.8,0.8c0,0.44 -0.36,0.8 -0.8,0.8z"
+ android:fillColor="#FFFFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_video.xml b/packages/SystemUI/res/drawable/ic_video.xml
new file mode 100644
index 0000000..3668338
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_video.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M9,7v8l7,-4zM21,3L3,3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h5v2h8v-2h5c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,17L3,17L3,5h18v12z"
+ android:fillColor="#FFFFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/volume_background.xml b/packages/SystemUI/res/drawable/screenshot_border.xml
similarity index 63%
copy from packages/SystemUI/res/drawable/volume_background.xml
copy to packages/SystemUI/res/drawable/screenshot_border.xml
index 66f1d0d..bb858db 100644
--- a/packages/SystemUI/res/drawable/volume_background.xml
+++ b/packages/SystemUI/res/drawable/screenshot_border.xml
@@ -12,15 +12,12 @@
~ 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
+ ~ limitations under the License.
-->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
- <item>
- <shape>
- <size android:width="@dimen/volume_dialog_panel_width" />
- <solid android:color="?androidprv:attr/colorSurface" />
- <corners android:radius="@dimen/volume_dialog_panel_width_half"/>
- </shape>
- </item>
-</layer-list>
\ No newline at end of file
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorSurface"/>
+ <corners android:radius="20dp"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/screenshot_cancel.xml b/packages/SystemUI/res/drawable/screenshot_cancel.xml
index f0dfd21..65b4354 100644
--- a/packages/SystemUI/res/drawable/screenshot_cancel.xml
+++ b/packages/SystemUI/res/drawable/screenshot_cancel.xml
@@ -15,14 +15,15 @@
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:width="48dp"
android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
+ android:viewportWidth="32.0"
+ android:viewportHeight="32.0">
<path
- android:fillColor="@color/global_screenshot_dismiss_background"
- android:pathData="M24,24m-16,0a16,16 0,1 1,32 0a16,16 0,1 1,-32 0"/>
+ android:fillColor="?androidprv:attr/colorAccentSecondary"
+ android:pathData="M16,16m-16,0a16,16 0,1 1,32 0a16,16 0,1 1,-32 0"/>
<path
- android:fillColor="@color/global_screenshot_dismiss_foreground"
- android:pathData="M31,18.41L29.59,17 24,22.59 18.41,17 17,18.41 22.59,24 17,29.59 18.41,31 24,25.41 29.59,31 31,29.59 25.41,24z"/>
-</vector>
\ No newline at end of file
+ android:fillColor="?android:attr/textColorPrimary"
+ android:pathData="M23,10.41L21.59,9 16,14.59 10.41,9 9,10.41 14.59,16 9,21.59 10.41,23 16,17.41 21.59,23 23,21.59 17.41,16z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/screenshot_preview_background.xml b/packages/SystemUI/res/drawable/screenshot_preview_background.xml
new file mode 100644
index 0000000..5adfaa13
--- /dev/null
+++ b/packages/SystemUI/res/drawable/screenshot_preview_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <corners android:radius="20dp"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/system_animation_ongoing_dot.xml b/packages/SystemUI/res/drawable/system_animation_ongoing_dot.xml
index 9f81b0d..09af6d2 100644
--- a/packages/SystemUI/res/drawable/system_animation_ongoing_dot.xml
+++ b/packages/SystemUI/res/drawable/system_animation_ongoing_dot.xml
@@ -20,7 +20,7 @@
<solid
android:color="@color/privacy_chip_background"/>
<size
- android:width="6dp"
- android:height="6dp"
+ android:width="@dimen/ongoing_appops_dot_diameter"
+ android:height="@dimen/ongoing_appops_dot_diameter"
/>
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/volume_background.xml b/packages/SystemUI/res/drawable/volume_background_bottom.xml
similarity index 67%
copy from packages/SystemUI/res/drawable/volume_background.xml
copy to packages/SystemUI/res/drawable/volume_background_bottom.xml
index 66f1d0d..ae3d159 100644
--- a/packages/SystemUI/res/drawable/volume_background.xml
+++ b/packages/SystemUI/res/drawable/volume_background_bottom.xml
@@ -14,13 +14,10 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
- <item>
- <shape>
- <size android:width="@dimen/volume_dialog_panel_width" />
- <solid android:color="?androidprv:attr/colorSurface" />
- <corners android:radius="@dimen/volume_dialog_panel_width_half"/>
- </shape>
- </item>
-</layer-list>
\ No newline at end of file
+ <size android:width="@dimen/volume_dialog_panel_width" />
+ <solid android:color="?androidprv:attr/colorSurface" />
+ <corners android:bottomLeftRadius="@dimen/volume_dialog_panel_width_half"
+ android:bottomRightRadius="@dimen/volume_dialog_panel_width_half"/>
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/volume_background.xml b/packages/SystemUI/res/drawable/volume_background_top.xml
similarity index 85%
rename from packages/SystemUI/res/drawable/volume_background.xml
rename to packages/SystemUI/res/drawable/volume_background_top.xml
index 66f1d0d..3cd87fc 100644
--- a/packages/SystemUI/res/drawable/volume_background.xml
+++ b/packages/SystemUI/res/drawable/volume_background_top.xml
@@ -20,7 +20,8 @@
<shape>
<size android:width="@dimen/volume_dialog_panel_width" />
<solid android:color="?androidprv:attr/colorSurface" />
- <corners android:radius="@dimen/volume_dialog_panel_width_half"/>
+ <corners android:topLeftRadius="@dimen/volume_dialog_panel_width_half"
+ android:topRightRadius="@dimen/volume_dialog_panel_width_half"/>
</shape>
</item>
</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/volume_background.xml b/packages/SystemUI/res/drawable/volume_background_top_rounded.xml
similarity index 75%
copy from packages/SystemUI/res/drawable/volume_background.xml
copy to packages/SystemUI/res/drawable/volume_background_top_rounded.xml
index 66f1d0d..77382e1 100644
--- a/packages/SystemUI/res/drawable/volume_background.xml
+++ b/packages/SystemUI/res/drawable/volume_background_top_rounded.xml
@@ -20,7 +20,10 @@
<shape>
<size android:width="@dimen/volume_dialog_panel_width" />
<solid android:color="?androidprv:attr/colorSurface" />
- <corners android:radius="@dimen/volume_dialog_panel_width_half"/>
+ <corners android:topLeftRadius="@dimen/volume_dialog_panel_width_half"
+ android:topRightRadius="@dimen/volume_dialog_panel_width_half"
+ android:bottomLeftRadius="@dimen/volume_dialog_panel_width_half"
+ android:bottomRightRadius="@dimen/volume_dialog_panel_width_half"/>
</shape>
</item>
</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/volume_background.xml b/packages/SystemUI/res/drawable/volume_row_rounded_background.xml
similarity index 67%
copy from packages/SystemUI/res/drawable/volume_background.xml
copy to packages/SystemUI/res/drawable/volume_row_rounded_background.xml
index 66f1d0d..95ba73d 100644
--- a/packages/SystemUI/res/drawable/volume_background.xml
+++ b/packages/SystemUI/res/drawable/volume_row_rounded_background.xml
@@ -14,13 +14,10 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
- <item>
- <shape>
- <size android:width="@dimen/volume_dialog_panel_width" />
- <solid android:color="?androidprv:attr/colorSurface" />
- <corners android:radius="@dimen/volume_dialog_panel_width_half"/>
- </shape>
- </item>
-</layer-list>
\ No newline at end of file
+ <size android:width="@dimen/volume_dialog_panel_width" />
+ <solid android:color="?androidprv:attr/colorSurface" />
+ <corners android:radius="@dimen/volume_dialog_panel_width_half"/>
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog.xml b/packages/SystemUI/res/layout-land-television/volume_dialog.xml
index 8adc6eb..6b5629f 100644
--- a/packages/SystemUI/res/layout-land-television/volume_dialog.xml
+++ b/packages/SystemUI/res/layout-land-television/volume_dialog.xml
@@ -32,7 +32,7 @@
android:clipToPadding="false">
<LinearLayout
- android:id="@+id/main"
+ android:id="@+id/volume_dialog_rows_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
diff --git a/packages/SystemUI/res/layout-land/volume_dialog.xml b/packages/SystemUI/res/layout-land/volume_dialog.xml
index 237dc02..f1cda27 100644
--- a/packages/SystemUI/res/layout-land/volume_dialog.xml
+++ b/packages/SystemUI/res/layout-land/volume_dialog.xml
@@ -16,6 +16,7 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:sysui="http://schemas.android.com/apk/res-auto"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/volume_dialog_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -24,64 +25,28 @@
android:background="@android:color/transparent"
android:theme="@style/volume_dialog_theme">
- <FrameLayout
+ <!-- right-aligned to be physically near volume button -->
+ <LinearLayout
android:id="@+id/volume_dialog"
- android:minWidth="@dimen/volume_dialog_panel_width"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:layout_gravity="right"
- android:background="@android:color/transparent"
- android:paddingRight="@dimen/volume_dialog_stream_padding"
- android:paddingLeft="@dimen/volume_dialog_panel_transparent_padding"
- android:clipToPadding="false">
+ android:layout_marginRight="@dimen/volume_dialog_panel_transparent_padding_right"
+ android:orientation="vertical"
+ android:clipToPadding="false"
+ android:clipChildren="false">
- <!--
- Container for a) the ringer drawer and the caption button next to b) the volume rows.
- -->
+
<LinearLayout
+ android:id="@+id/volume_dialog_top_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="horizontal"
+ android:orientation="vertical"
android:clipChildren="false"
- android:clipToPadding="false">
+ android:gravity="right">
- <!-- The ringer drawer and the caption button. -->
- <FrameLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingRight="@dimen/volume_dialog_stream_padding"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:orientation="vertical">
-
- <include layout="@layout/volume_ringer_drawer"
- android:layout_gravity="top|right"/>
-
- <FrameLayout
- android:id="@+id/odi_captions"
- android:layout_width="@dimen/volume_dialog_caption_size"
- android:layout_height="@dimen/volume_dialog_caption_size"
- android:gravity="center"
- android:layout_gravity="bottom|right"
- android:layout_marginBottom="@dimen/volume_dialog_tap_target_size"
- android:clipToPadding="false">
-
- <com.android.systemui.volume.CaptionsToggleImageButton
- android:id="@+id/odi_captions_icon"
- android:src="@drawable/ic_volume_odi_captions_disabled"
- style="@style/VolumeButtons"
- android:background="@drawable/rounded_ripple"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:tint="@color/caption_tint_color_selector"
- android:layout_gravity="center"
- android:soundEffectsEnabled="false"
- sysui:optedOut="false"/>
-
- </FrameLayout>
-
- </FrameLayout>
+ <include layout="@layout/volume_ringer_drawer" />
<FrameLayout
android:visibility="gone"
@@ -102,40 +67,42 @@
android:layout_height="match_parent"
android:scaleType="fitCenter"
android:padding="@dimen/volume_dialog_ringer_icon_padding"
- android:tint="@color/accent_tint_color_selector"
+ android:tint="?android:attr/textColorPrimary"
android:layout_gravity="center"
android:soundEffectsEnabled="false" />
<include layout="@layout/volume_dnd_icon"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginRight="@dimen/volume_dialog_stream_padding"
- android:layout_marginTop="6dp"/>
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="@dimen/volume_dialog_stream_padding"
+ android:layout_marginTop="6dp"/>
</FrameLayout>
<LinearLayout
- android:id="@+id/main"
+ android:id="@+id/volume_dialog_rows_container"
android:layout_width="wrap_content"
- android:minWidth="@dimen/volume_dialog_panel_width"
android:layout_height="wrap_content"
android:gravity="right"
android:layout_gravity="right"
android:orientation="vertical"
android:clipChildren="false"
- android:clipToPadding="false">
+ android:clipToPadding="false" >
<LinearLayout
android:id="@+id/volume_dialog_rows"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:minWidth="@dimen/volume_dialog_panel_width"
android:gravity="center"
android:orientation="horizontal">
<!-- volume rows added and removed here! :-) -->
</LinearLayout>
<FrameLayout
android:id="@+id/settings_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/volume_background_bottom"
+ android:paddingLeft="@dimen/volume_dialog_ringer_rows_padding"
+ android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding"
+ android:paddingRight="@dimen/volume_dialog_ringer_rows_padding">
<com.android.keyguard.AlphaOptimizedImageButton
android:id="@+id/settings"
android:src="@drawable/horizontal_ellipsis"
@@ -144,23 +111,43 @@
android:layout_gravity="center"
android:contentDescription="@string/accessibility_volume_settings"
android:background="@drawable/ripple_drawable_20dp"
- android:tint="?android:attr/colorBackgroundFloating"
+ android:tint="?androidprv:attr/colorAccent"
android:soundEffectsEnabled="false" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
- <ViewStub
- android:id="@+id/odi_captions_tooltip_stub"
- android:inflatedId="@+id/odi_captions_tooltip_view"
- android:layout="@layout/volume_tool_tip_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="@dimen/volume_tool_tip_right_margin"
- android:layout_marginTop="@dimen/volume_tool_tip_top_margin"
- android:layout_gravity="right"/>
+ <FrameLayout
+ android:id="@+id/odi_captions"
+ android:layout_width="@dimen/volume_dialog_caption_size"
+ android:layout_height="@dimen/volume_dialog_caption_size"
+ android:layout_marginTop="@dimen/volume_dialog_row_margin_bottom"
+ android:gravity="right"
+ android:layout_gravity="right"
+ android:clipToPadding="false"
+ android:clipToOutline="true"
+ android:background="@drawable/volume_row_rounded_background">
+ <com.android.systemui.volume.CaptionsToggleImageButton
+ android:id="@+id/odi_captions_icon"
+ android:src="@drawable/ic_volume_odi_captions_disabled"
+ style="@style/VolumeButtons"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:tint="?android:attr/colorAccent"
+ android:layout_gravity="center"
+ android:soundEffectsEnabled="false"
+ sysui:optedOut="false"/>
+ </FrameLayout>
+ </LinearLayout>
- </FrameLayout>
+ <ViewStub
+ android:id="@+id/odi_captions_tooltip_stub"
+ android:inflatedId="@+id/odi_captions_tooltip_view"
+ android:layout="@layout/volume_tool_tip_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom | right"
+ android:layout_marginRight="@dimen/volume_tool_tip_right_margin"/>
</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index 3c58d16..5bd181c 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -17,6 +17,7 @@
<com.android.systemui.screenshot.ScreenshotView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/global_screenshot_frame"
+ android:theme="@style/Screenshot"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
diff --git a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
index 1021186..aeae722 100644
--- a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
@@ -32,18 +32,15 @@
android:gravity="center">
<ImageView
android:id="@+id/screenshot_action_chip_icon"
- android:tint="@*android:color/accent_device_default"
+ android:tint="?android:attr/textColorPrimary"
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"/>
+ android:layout_height="@dimen/screenshot_action_chip_icon_size"/>
<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:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textSize="@dimen/screenshot_action_chip_text_size"
- android:textColor="@color/global_screenshot_button_text"/>
+ android:textColor="?android:attr/textColorPrimary"/>
</LinearLayout>
</com.android.systemui.screenshot.ScreenshotActionChip>
diff --git a/packages/SystemUI/res/layout/global_screenshot_preview.xml b/packages/SystemUI/res/layout/global_screenshot_preview.xml
deleted file mode 100644
index 100213b..0000000
--- a/packages/SystemUI/res/layout/global_screenshot_preview.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2011 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.
- -->
-<ImageView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/global_screenshot_preview"
- android:layout_width="@dimen/global_screenshot_x_scale"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:layout_marginStart="@dimen/screenshot_offset_x"
- android:layout_marginBottom="@dimen/screenshot_offset_y"
- android:scaleType="fitEnd"
- android:elevation="@dimen/screenshot_preview_elevation"
- android:visibility="invisible"
- android:background="@drawable/screenshot_rounded_corners"
- android:adjustViewBounds="true"
- android:contentDescription="@string/screenshot_edit_label"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml
index 9f63c43..60dbaf9 100644
--- a/packages/SystemUI/res/layout/global_screenshot_static.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_static.xml
@@ -37,7 +37,7 @@
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/screenshot_action_container_margin_horizontal"
android:layout_marginBottom="@dimen/screenshot_action_container_offset_y"
- android:paddingHorizontal="@dimen/screenshot_action_container_padding_right"
+ android:paddingEnd="@dimen/screenshot_action_container_padding_right"
android:paddingVertical="@dimen/screenshot_action_container_padding_vertical"
android:elevation="1dp"
android:scrollbars="none"
@@ -45,7 +45,7 @@
app:layout_constraintWidth_percent="1.0"
app:layout_constraintWidth_max="wrap"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toEndOf="@+id/global_screenshot_preview"
+ app:layout_constraintStart_toEndOf="@+id/global_screenshot_preview_border"
app:layout_constraintEnd_toEndOf="parent">
<LinearLayout
android:id="@+id/global_screenshot_actions"
@@ -60,7 +60,49 @@
android:visibility="gone" />
</LinearLayout>
</HorizontalScrollView>
- <include layout="@layout/global_screenshot_preview"/>
+ <View
+ android:id="@+id/global_screenshot_preview_border"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_marginStart="@dimen/screenshot_offset_x"
+ android:layout_marginBottom="@dimen/screenshot_offset_y"
+ android:elevation="@dimen/screenshot_preview_elevation"
+ android:alpha="0"
+ android:background="@drawable/screenshot_border"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@+id/screenshot_preview_end"
+ app:layout_constraintTop_toTopOf="@+id/screenshot_preview_top"/>
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/screenshot_preview_end"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:barrierMargin="4dp"
+ app:barrierDirection="end"
+ app:constraint_referenced_ids="global_screenshot_preview"/>
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/screenshot_preview_top"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:barrierDirection="top"
+ app:barrierMargin="-4dp"
+ app:constraint_referenced_ids="global_screenshot_preview"/>
+ <ImageView
+ android:id="@+id/global_screenshot_preview"
+ android:visibility="invisible"
+ android:layout_width="@dimen/global_screenshot_x_scale"
+ android:layout_marginStart="4dp"
+ android:layout_marginBottom="4dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:elevation="@dimen/screenshot_preview_elevation"
+ android:contentDescription="@string/screenshot_edit_label"
+ android:scaleType="fitEnd"
+ android:background="@drawable/screenshot_preview_background"
+ android:adjustViewBounds="true"
+ app:layout_constraintBottom_toBottomOf="@+id/global_screenshot_preview_border"
+ app:layout_constraintStart_toStartOf="@+id/global_screenshot_preview_border">
+ </ImageView>
<FrameLayout
android:id="@+id/global_screenshot_dismiss_button"
android:layout_width="@dimen/screenshot_dismiss_button_tappable_size"
diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml
index 9b3b39d..de33846 100644
--- a/packages/SystemUI/res/layout/long_screenshot.xml
+++ b/packages/SystemUI/res/layout/long_screenshot.xml
@@ -33,7 +33,7 @@
android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
android:backgroundTint="?androidprv:attr/colorAccentSecondary"
- android:textColor="?androidprv:attr/textColorSecondary"
+ android:textColor="?android:textColorSecondary"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/preview" />
@@ -117,7 +117,7 @@
android:backgroundTint="?androidprv:attr/colorAccentSecondary"
android:src="@drawable/ic_screenshot_edit"
android:contentDescription="@string/screenshot_edit_label"
- android:tint="?androidprv:attr/textColorSecondary"
+ android:tint="?android:textColorSecondary"
android:padding="16dp"
android:scaleType="fitCenter"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/packages/SystemUI/res/layout/media_carousel.xml b/packages/SystemUI/res/layout/media_carousel.xml
index 87acfd0..52132e8 100644
--- a/packages/SystemUI/res/layout/media_carousel.xml
+++ b/packages/SystemUI/res/layout/media_carousel.xml
@@ -22,6 +22,7 @@
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
+ android:forceHasOverlappingRendering="false"
android:theme="@style/MediaPlayer">
<com.android.systemui.media.MediaScrollView
android:id="@+id/media_carousel_scroller"
diff --git a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
index 5fb4819..9a57589 100644
--- a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
+++ b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
@@ -125,36 +125,43 @@
<!-- Long press menu -->
<TextView
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/qs_media_padding"
+ android:layout_marginTop="20dp"
android:layout_marginStart="@dimen/qs_media_padding"
android:layout_marginEnd="@dimen/qs_media_padding"
android:id="@+id/remove_text"
android:fontFamily="@*android:string/config_headlineFontFamily"
android:singleLine="true"
+ android:ellipsize="marquee"
+ android:marqueeRepeatLimit="marquee_forever"
android:text="@string/controls_media_close_session"
android:gravity="center_horizontal|top"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toTopOf="@id/settings"/>
+ app:layout_constraintBottom_toTopOf="@id/cancel"/>
<FrameLayout
android:id="@+id/settings"
android:background="@drawable/qs_media_light_source"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/qs_media_padding"
- android:paddingBottom="@dimen/qs_media_padding"
- android:minWidth="48dp"
- android:minHeight="48dp"
- app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginEnd="@dimen/qs_media_info_spacing"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="6dp"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintWidth_min="48dp"
+ app:layout_constraintHeight_min="48dp"
+ app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/cancel"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/remove_text">
<TextView
- android:layout_gravity="bottom"
+ android:id="@+id/settings_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/MediaPlayer.OutlineButton"
@@ -164,18 +171,21 @@
<FrameLayout
android:id="@+id/cancel"
android:background="@drawable/qs_media_light_source"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginEnd="8dp"
- android:paddingBottom="@dimen/qs_media_padding"
- android:minWidth="48dp"
- android:minHeight="48dp"
- app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginStart="@dimen/qs_media_info_spacing"
+ android:layout_marginEnd="@dimen/qs_media_info_spacing"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="6dp"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintWidth_min="48dp"
+ app:layout_constraintHeight_min="48dp"
+ app:layout_constraintStart_toEndOf="@id/settings"
app:layout_constraintEnd_toStartOf="@id/dismiss"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/remove_text">
<TextView
- android:layout_gravity="bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/MediaPlayer.OutlineButton"
@@ -185,23 +195,25 @@
<FrameLayout
android:id="@+id/dismiss"
android:background="@drawable/qs_media_light_source"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/qs_media_info_spacing"
android:layout_marginEnd="@dimen/qs_media_padding"
- android:paddingBottom="@dimen/qs_media_padding"
- android:minWidth="48dp"
- android:minHeight="48dp"
- app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="6dp"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintWidth_min="48dp"
+ app:layout_constraintHeight_min="48dp"
+ app:layout_constraintStart_toEndOf="@id/cancel"
app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/remove_text">
<TextView
- android:layout_gravity="bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/MediaPlayer.OutlineButton"
android:text="@string/controls_media_dismiss_button"
- />
+ />
</FrameLayout>
-
</com.android.systemui.util.animation.TransitionLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml
index e999872..10bdaaa 100644
--- a/packages/SystemUI/res/layout/media_view.xml
+++ b/packages/SystemUI/res/layout/media_view.xml
@@ -213,36 +213,43 @@
<!-- Long press menu -->
<TextView
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/qs_media_padding"
+ android:layout_marginTop="20dp"
android:layout_marginStart="@dimen/qs_media_padding"
android:layout_marginEnd="@dimen/qs_media_padding"
android:id="@+id/remove_text"
android:fontFamily="@*android:string/config_headlineFontFamily"
android:singleLine="true"
+ android:ellipsize="marquee"
+ android:marqueeRepeatLimit="marquee_forever"
android:text="@string/controls_media_close_session"
android:gravity="center_horizontal|top"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toTopOf="@id/settings"/>
+ app:layout_constraintBottom_toTopOf="@id/cancel"/>
<FrameLayout
android:id="@+id/settings"
android:background="@drawable/qs_media_light_source"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/qs_media_padding"
- android:paddingBottom="@dimen/qs_media_padding"
- android:minWidth="48dp"
- android:minHeight="48dp"
- app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginEnd="@dimen/qs_media_info_spacing"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="6dp"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintWidth_min="48dp"
+ app:layout_constraintHeight_min="48dp"
+ app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/cancel"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/remove_text">
<TextView
- android:layout_gravity="bottom"
+ android:id="@+id/settings_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/MediaPlayer.OutlineButton"
@@ -252,18 +259,21 @@
<FrameLayout
android:id="@+id/cancel"
android:background="@drawable/qs_media_light_source"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginEnd="8dp"
- android:paddingBottom="@dimen/qs_media_padding"
- android:minWidth="48dp"
- android:minHeight="48dp"
- app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginStart="@dimen/qs_media_info_spacing"
+ android:layout_marginEnd="@dimen/qs_media_info_spacing"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="6dp"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintWidth_min="48dp"
+ app:layout_constraintHeight_min="48dp"
+ app:layout_constraintStart_toEndOf="@id/settings"
app:layout_constraintEnd_toStartOf="@id/dismiss"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/remove_text">
<TextView
- android:layout_gravity="bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/MediaPlayer.OutlineButton"
@@ -273,18 +283,21 @@
<FrameLayout
android:id="@+id/dismiss"
android:background="@drawable/qs_media_light_source"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/qs_media_info_spacing"
android:layout_marginEnd="@dimen/qs_media_padding"
- android:paddingBottom="@dimen/qs_media_padding"
- android:minWidth="48dp"
- android:minHeight="48dp"
- app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="6dp"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintWidth_min="48dp"
+ app:layout_constraintHeight_min="48dp"
+ app:layout_constraintStart_toEndOf="@id/cancel"
app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/remove_text">
<TextView
- android:layout_gravity="bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/MediaPlayer.OutlineButton"
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index a2a14c7..5f59e78 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -22,11 +22,15 @@
android:id="@+id/navigation_bar_view"
android:layout_height="match_parent"
android:layout_width="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false"
android:background="@drawable/system_bar_background">
<com.android.systemui.navigationbar.NavigationBarInflaterView
android:id="@+id/navigation_inflater"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:clipToPadding="false" />
</com.android.systemui.navigationbar.NavigationBarView>
diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml
index 64c7422..46f238c 100644
--- a/packages/SystemUI/res/layout/navigation_layout.xml
+++ b/packages/SystemUI/res/layout/navigation_layout.xml
@@ -23,6 +23,8 @@
android:layout_marginEnd="@dimen/rounded_corner_content_padding"
android:paddingStart="@dimen/nav_content_padding"
android:paddingEnd="@dimen/nav_content_padding"
+ android:clipChildren="false"
+ android:clipToPadding="false"
android:id="@+id/horizontal">
<com.android.systemui.navigationbar.buttons.NearestTouchFrame
diff --git a/packages/SystemUI/res/layout/ongoing_call_chip.xml b/packages/SystemUI/res/layout/ongoing_call_chip.xml
index f8175d4..5389d9b 100644
--- a/packages/SystemUI/res/layout/ongoing_call_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_call_chip.xml
@@ -23,6 +23,7 @@
android:layout_gravity="center_vertical|start"
>
<LinearLayout
+ android:id="@+id/ongoing_call_chip_background"
android:layout_width="wrap_content"
android:layout_height="@dimen/ongoing_appops_chip_height"
android:layout_gravity="center_vertical"
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
index 676e492..8122776 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
@@ -32,6 +32,7 @@
android:paddingEnd="10dp"
android:gravity="center"
android:layout_gravity="center"
- android:minWidth="56dp"
+ android:minWidth="@dimen/ongoing_appops_chip_min_width"
+ android:maxWidth="@dimen/ongoing_appops_chip_max_width"
/>
</com.android.systemui.privacy.OngoingPrivacyChip>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/people_tile_large_with_content.xml b/packages/SystemUI/res/layout/people_tile_large_with_content.xml
index 4994c69..b7e86a3 100644
--- a/packages/SystemUI/res/layout/people_tile_large_with_content.xml
+++ b/packages/SystemUI/res/layout/people_tile_large_with_content.xml
@@ -14,6 +14,7 @@
~ limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
@@ -34,8 +35,6 @@
<ImageView
android:id="@+id/person_icon"
- android:layout_marginStart="-2dp"
- android:layout_marginTop="-2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
@@ -54,7 +53,7 @@
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?androidprv:attr/textColorOnAccent"
android:background="@drawable/people_space_messages_count_background"
android:textSize="14sp"
android:maxLines="1"
@@ -73,12 +72,12 @@
<include layout="@layout/people_tile_emoji_background_large" />
<TextView
- android:layout_gravity="top"
android:id="@+id/name"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/below_name_text_padding"
- android:gravity="start|top"
+ android:layout_gravity="start|center_vertical"
+ android:gravity="start|center_vertical"
android:singleLine="true"
android:ellipsize="end"
android:text="@string/empty_user_name"
@@ -103,7 +102,7 @@
<ImageView
android:id="@+id/predefined_icon"
- android:tint="?android:attr/colorAccent"
+ android:tint="?android:attr/textColorTertiary"
android:gravity="start|center_vertical"
android:layout_width="@dimen/regular_predefined_icon"
android:layout_height="@dimen/regular_predefined_icon" />
diff --git a/packages/SystemUI/res/layout/people_tile_medium_empty.xml b/packages/SystemUI/res/layout/people_tile_medium_empty.xml
index bebc872..8b2fddc 100644
--- a/packages/SystemUI/res/layout/people_tile_medium_empty.xml
+++ b/packages/SystemUI/res/layout/people_tile_medium_empty.xml
@@ -27,19 +27,23 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <ImageView
- android:id="@+id/person_icon"
- android:layout_marginTop="-2dp"
- android:layout_marginStart="-2dp"
- android:layout_width="64dp"
- android:layout_height="64dp" />
- <ImageView
- android:id="@+id/availability"
- android:gravity="top"
- android:layout_marginStart="-2dp"
- android:layout_width="10dp"
- android:layout_height="10dp"
- android:background="@drawable/availability_dot_10dp" />
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/person_icon"
+ android:layout_width="64dp"
+ android:layout_height="64dp" />
+ <ImageView
+ android:id="@+id/availability"
+ android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:gravity="top"
+ android:layout_gravity="top"
+ android:layout_marginStart="-2dp"
+ android:background="@drawable/availability_dot_10dp" />
+ </LinearLayout>
<LinearLayout
android:orientation="vertical"
android:paddingStart="4dp"
diff --git a/packages/SystemUI/res/layout/people_tile_medium_with_content.xml b/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
index a7a6354..1086a13 100644
--- a/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
+++ b/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
@@ -16,6 +16,7 @@
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:id="@+id/item"
android:background="@drawable/people_space_tile_view_card"
@@ -47,8 +48,6 @@
<ImageView
android:gravity="start"
android:id="@+id/person_icon"
- android:layout_marginStart="-2dp"
- android:layout_marginTop="-2dp"
android:layout_width="52dp"
android:layout_height="52dp" />
@@ -112,7 +111,8 @@
android:clipToOutline="true">
<TextView
android:id="@+id/name"
- android:gravity="center_vertical"
+ android:layout_gravity="start|center_vertical"
+ android:gravity="start|center_vertical"
android:layout_weight="1"
android:text="@string/empty_user_name"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
@@ -129,7 +129,7 @@
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?androidprv:attr/textColorOnAccent"
android:background="@drawable/people_space_messages_count_background"
android:textSize="14sp"
android:maxLines="1"
@@ -140,7 +140,7 @@
/>
<ImageView
android:id="@+id/predefined_icon"
- android:tint="?android:attr/colorAccent"
+ android:tint="?android:attr/textColorTertiary"
android:gravity="end|center_vertical"
android:layout_width="@dimen/regular_predefined_icon"
android:layout_height="@dimen/regular_predefined_icon" />
diff --git a/packages/SystemUI/res/layout/people_tile_small.xml b/packages/SystemUI/res/layout/people_tile_small.xml
index 4e5c04c..22fcd3b 100644
--- a/packages/SystemUI/res/layout/people_tile_small.xml
+++ b/packages/SystemUI/res/layout/people_tile_small.xml
@@ -14,6 +14,7 @@
~ limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -39,7 +40,7 @@
<ImageView
android:id="@+id/predefined_icon"
- android:tint="?android:attr/colorAccent"
+ android:tint="?android:attr/textColorTertiary"
android:layout_gravity="center"
android:layout_width="18dp"
android:layout_height="22dp" />
@@ -50,7 +51,7 @@
android:gravity="center"
android:paddingHorizontal="8dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?androidprv:attr/textColorOnAccent"
android:background="@drawable/people_space_messages_count_background"
android:textSize="@dimen/name_text_size_for_small"
android:maxLines="1"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 3543fd1..fb39d3e 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -64,10 +64,6 @@
android:clipToPadding="false"
android:clipChildren="false">
- <include
- layout="@layout/keyguard_status_view"
- android:visibility="gone"/>
-
<com.android.systemui.scrim.ScrimView
android:id="@+id/scrim_notifications"
android:layout_width="0dp"
@@ -78,7 +74,11 @@
systemui:layout_constraintEnd_toEndOf="parent"
systemui:layout_constraintTop_toTopOf="parent"
systemui:layout_constraintBottom_toBottomOf="parent"
- />
+ />
+
+ <include
+ layout="@layout/keyguard_status_view"
+ android:visibility="gone"/>
<include layout="@layout/dock_info_overlay" />
@@ -129,7 +129,22 @@
android:layout_marginTop="@dimen/status_bar_header_height_keyguard"
android:text="@string/report_rejected_touch"
android:visibility="gone" />
-
+ <com.android.systemui.statusbar.phone.TapAgainView
+ android:id="@+id/shade_falsing_tap_again"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ systemui:layout_constraintLeft_toLeftOf="parent"
+ systemui:layout_constraintRight_toRightOf="parent"
+ systemui:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginBottom="20dp"
+ android:paddingHorizontal="16dp"
+ android:minHeight="44dp"
+ android:elevation="4dp"
+ android:background="@drawable/rounded_bg_full"
+ android:gravity="center"
+ android:text="@string/tap_again"
+ android:visibility="gone"
+ />
</com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>
<FrameLayout
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index a39006c..51718d9 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -37,15 +37,13 @@
android:clipToPadding="false"
android:clipChildren="false">
-
<LinearLayout
- android:id="@+id/volume_dialog_ringer_and_rows_container"
+ android:id="@+id/volume_dialog_top_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:padding="7dp"
android:clipChildren="false"
- android:background="@drawable/volume_background">
+ android:orientation="vertical"
+ android:gravity="right">
<include layout="@layout/volume_ringer_drawer" />
@@ -80,7 +78,7 @@
</FrameLayout>
<LinearLayout
- android:id="@+id/main"
+ android:id="@+id/volume_dialog_rows_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
@@ -93,14 +91,17 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
- android:orientation="horizontal"
- android:layout_marginTop="@dimen/volume_row_slider_padding_start">
+ android:orientation="horizontal">
<!-- volume rows added and removed here! :-) -->
</LinearLayout>
<FrameLayout
android:id="@+id/settings_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/volume_background_bottom"
+ android:paddingLeft="@dimen/volume_dialog_ringer_rows_padding"
+ android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding"
+ android:paddingRight="@dimen/volume_dialog_ringer_rows_padding">
<com.android.keyguard.AlphaOptimizedImageButton
android:id="@+id/settings"
android:src="@drawable/horizontal_ellipsis"
@@ -122,9 +123,10 @@
android:layout_height="@dimen/volume_dialog_caption_size"
android:layout_marginTop="@dimen/volume_dialog_row_margin_bottom"
android:gravity="right"
- android:layout_gravity="center"
+ android:layout_gravity="right"
android:clipToPadding="false"
- android:background="@drawable/volume_background">
+ android:clipToOutline="true"
+ android:background="@drawable/volume_row_rounded_background">
<com.android.systemui.volume.CaptionsToggleImageButton
android:id="@+id/odi_captions_icon"
android:src="@drawable/ic_volume_odi_captions_disabled"
@@ -145,7 +147,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom | right"
- android:layout_marginRight="@dimen/volume_tool_tip_right_margin"
- android:layout_marginBottom="@dimen/volume_tool_tip_bottom_margin"/>
+ android:layout_marginRight="@dimen/volume_tool_tip_right_margin"/>
</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index 4b5a008..ee89b97 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -17,15 +17,18 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:tag="row"
android:layout_height="wrap_content"
- android:layout_width="@dimen/volume_dialog_slider_width"
+ android:layout_width="@dimen/volume_dialog_panel_width"
android:clipChildren="false"
android:clipToPadding="false"
- android:translationZ="@dimen/volume_dialog_elevation"
+ android:gravity="center"
+ android:paddingTop="@dimen/volume_dialog_ringer_rows_padding"
+ android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding"
+ android:background="@drawable/volume_row_rounded_background"
android:theme="@style/volume_dialog_theme">
<LinearLayout
android:layout_height="wrap_content"
- android:layout_width="@dimen/volume_dialog_slider_width"
+ android:layout_width="@dimen/volume_dialog_panel_width"
android:gravity="center"
android:layout_gravity="center"
android:orientation="vertical" >
@@ -57,6 +60,7 @@
android:thumb="@null"
android:splitTrack="false"
android:progressDrawable="@drawable/volume_row_seekbar"
+ android:background="@null"
android:layoutDirection="ltr"
android:rotation="270" />
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/volume_ringer_drawer.xml b/packages/SystemUI/res/layout/volume_ringer_drawer.xml
index 9d14ac4..9b6c92c 100644
--- a/packages/SystemUI/res/layout/volume_ringer_drawer.xml
+++ b/packages/SystemUI/res/layout/volume_ringer_drawer.xml
@@ -18,9 +18,16 @@
<!-- Contains the active ringer icon and a hidden drawer containing all three ringer options. -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/volume_ringer_and_drawer_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
+ android:paddingLeft="@dimen/volume_dialog_ringer_rows_padding"
+ android:paddingTop="@dimen/volume_dialog_ringer_rows_padding"
+ android:paddingRight="@dimen/volume_dialog_ringer_rows_padding"
+ android:paddingBottom="@dimen/volume_dialog_ringer_rows_padding"
+ android:background="@drawable/volume_background_top"
+ android:layoutDirection="ltr"
android:clipToPadding="false"
android:clipChildren="false">
diff --git a/packages/SystemUI/res/layout/volume_tool_tip_view.xml b/packages/SystemUI/res/layout/volume_tool_tip_view.xml
index 9fe885e..ee24969 100644
--- a/packages/SystemUI/res/layout/volume_tool_tip_view.xml
+++ b/packages/SystemUI/res/layout/volume_tool_tip_view.xml
@@ -17,6 +17,7 @@
<com.android.systemui.volume.VolumeToolTipView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/tooltip_view"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -35,7 +36,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:textColor="@android:color/white"
+ android:textColor="?android:attr/textColorPrimaryInverse"
android:text="@string/volume_odi_captions_tip"
android:textSize="14sp"/>
<ImageView
@@ -48,7 +49,7 @@
android:layout_marginEnd="2dp"
android:alpha="0.7"
android:src="@drawable/ic_remove_no_shadow"
- android:tint="@android:color/white"
+ android:tint="?android:attr/textColorPrimaryInverse"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/accessibility_volume_close_odi_captions_tip"/>
</LinearLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 55baa9d..b9c719f 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is gedeaktiveer"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is geaktiveer"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Skermopname"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Skermopname"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Begin"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblokkeer toestelmikrofoon?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Prioriteitgesprekke"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Onlangse gesprekke"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> dae gelede"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 week gelede"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 weke gelede"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Meer as 1 week gelede"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Meer as 2 weke gelede"</string>
<string name="birthday_status" msgid="2596961629465396761">"Verjaarsdag"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Dit is <xliff:g id="NAME">%1$s</xliff:g> se verjaarsdag"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Verjaar binnekort"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 587a91d..2170055 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"ኤንኤፍሲ"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"ኤንኤፍሲ ተሰናክሏል"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"ኤንኤፍሲ ነቅቷል"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"የማያ ገጽ ቀረጻ"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"የማያ ቀረጻ"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ጀምር"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"አቁም"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"የመሣሪያ ማይክሮፎን እገዳ ይነሳ?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"የቅድሚያ ውይይቶች"</string>
<string name="recent_conversations" msgid="8531874684782574622">"የቅርብ ጊዜ ውይይቶች"</string>
<string name="okay" msgid="6490552955618608554">"እሺ"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"ከ<xliff:g id="DURATION">%1$s</xliff:g> ቀኖች በፊት"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"ከ1 ሳምንት በፊት"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"ከ2 ሳምንታት በፊት"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"ከ1 ሳምንት በፊት"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"ከ2 ሳምንታት በላይ በፊት"</string>
<string name="birthday_status" msgid="2596961629465396761">"የልደት ቀን"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"የ<xliff:g id="NAME">%1$s</xliff:g> ልደት ቀን ነው"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"የልደት ቀን በቅርቡ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index b854eb7..31ff9c66 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -179,7 +179,7 @@
<string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"لقد استنفدت عدد المحاولات غير الصحيحة وسيتم حذف هذا المستخدم."</string>
<string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"لقد استنفدت عدد المحاولات غير الصحيحة وسيتم حذف الملف الشخصي للعمل وبياناته."</string>
<string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"إغلاق"</string>
- <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"المس زر استشعار بصمة الإصبع"</string>
+ <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"المس مستشعر بصمة الإصبع"</string>
<string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"رمز بصمة الإصبع"</string>
<string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"يتعذّر التعرّف على الوجه. استخدِم بصمة الإصبع بدلاً من ذلك."</string>
<string name="fingerprint_dialog_use_fingerprint" msgid="923777032861374285">"عليك استخدام بصمة الإصبع للمتابعة."</string>
@@ -431,7 +431,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"تم إيقاف الاتصال القريب المدى"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"تم تفعيل الاتصال القريب المدى"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"تسجيل الشاشة"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"تسجيل الشاشة"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"بدء"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"إيقاف"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"هل تريد إزالة حظر ميكروفون الجهاز؟"</string>
@@ -1136,16 +1136,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"المحادثات ذات الأولوية"</string>
<string name="recent_conversations" msgid="8531874684782574622">"المحادثات الحديثة"</string>
<string name="okay" msgid="6490552955618608554">"حسنًا"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"قبل <xliff:g id="DURATION">%1$s</xliff:g> يوم"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"قبل أسبوع واحد"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"قبل أسبوعين"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"قبل أكثر من أسبوع واحد"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"قبل أكثر من أسبوعين"</string>
<string name="birthday_status" msgid="2596961629465396761">"تاريخ الميلاد"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"إنه يوم ميلاد <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"تاريخ ميلاد قريب"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index b3c7e4e..a288d6f 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -408,8 +408,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> ব্যৱহৃত"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সীমা"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সকীয়নি"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"কৰ্মস্থানৰ এপ্"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"ৰাতিৰ পোহৰ"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"সূৰ্যাস্তত অন কৰক"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"সূৰ্যোদয়ৰ লৈকে"</string>
@@ -424,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC নিষ্ক্ৰিয় হৈ আছে"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC সক্ষম হৈ আছে"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"স্ক্ৰীন ৰেকর্ড"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"স্ক্ৰীন ৰেকৰ্ড কৰা"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"আৰম্ভ কৰক"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"বন্ধ কৰক"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ডিভাইচৰ মাইক্ৰ\'ফ\'ন অৱৰোধৰ পৰা আঁতৰাবনে?"</string>
@@ -1041,8 +1040,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"কাষলৈ নিয়ক আৰু লুকুৱাওক"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"কাষৰ বাহিৰলৈ নিয়ক আৰু দেখুৱাওক"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ট’গল কৰক"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"গৃহ নিয়ন্ত্ৰণ"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"নিয়ন্ত্ৰণসমূহ যোগ কৰিবলৈ এপ্ বাছনি কৰক"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> টা নিয়ন্ত্ৰণ যোগ কৰা হ’ল।</item>
@@ -1056,8 +1054,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"অপ্ৰিয়"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"<xliff:g id="NUMBER">%d</xliff:g> নম্বৰ অৱস্থানলৈ স্থানান্তৰিত কৰক"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"নিয়ন্ত্ৰণসমূহ"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"ক্ষিপ্ৰ ছেটিঙৰ পৰা এক্সেছ কৰিবলৈ নিয়ন্ত্ৰণসমূহ বাছনি কৰক"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"নিয়ন্ত্ৰণসমূহ পুনৰ সজাবলৈ ধৰি ৰাখক আৰু টানি আনি এৰক"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"সকলো নিয়ন্ত্ৰণ আঁতৰোৱা হৈছে"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"সালসলনিসমূহ ছেভ নহ’ল"</string>
@@ -1096,8 +1093,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"স্থিতি ল’ড কৰিব নোৱাৰি"</string>
<string name="controls_error_failed" msgid="960228639198558525">"আসোঁৱাহ হৈছে, আকৌ চেষ্টা কৰক"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"চলি আছে"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"নতুন নিয়ন্ত্ৰণসমূহ চাবলৈ ক্ষিপ্ৰ ছেটিং খোলক"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"নিয়ন্ত্ৰণসমূহ যোগ দিয়ক"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"নিয়ন্ত্ৰণসমূহ সম্পাদনা কৰক"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"আউটপুটসমূহ যোগ দিয়ক"</string>
@@ -1116,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"অগ্ৰাধিকাৰপ্ৰাপ্ত বাৰ্তালাপ"</string>
<string name="recent_conversations" msgid="8531874684782574622">"শেহতীয়া বাৰ্তালাপ"</string>
<string name="okay" msgid="6490552955618608554">"ঠিক আছে"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> দিন আগতে"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"১ সপ্তাহ আগতে"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"২ সপ্তাহ পূৰ্বে"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"১ সপ্তাহতকৈ বেছি আগতে"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"২ সপ্তাহতকৈ বেছি আগতে"</string>
<string name="birthday_status" msgid="2596961629465396761">"জন্মদিন"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"এয়া <xliff:g id="NAME">%1$s</xliff:g>ৰ জন্মদিন"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"জন্মদিন সোনকালে আহি আছে"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 1a33301..0e8cb57 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC deaktiv edilib"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC aktiv edilib"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ekran yazması"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Ekran yazması"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Başlayın"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Dayandırın"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Cihaz mikrofonu blokdan çıxarılsın?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Önəmli söhbətlər"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Son söhbətlər"</string>
<string name="okay" msgid="6490552955618608554">"Oldu"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> gün əvvəl"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 həftə əvvəl"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 həftə əvvəl"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"1 həftədən daha əvvəl"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"2 həftədən daha əvvəl"</string>
<string name="birthday_status" msgid="2596961629465396761">"Doğum günü"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> adlı şəxsin doğum günüdür"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Tezliklə doğum günü"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 9399e72..83c8513 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -425,7 +425,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je onemogućen"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je omogućen"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Snimak ekrana"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Snimanje ekrana"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Počnite"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zaustavite"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite da odblokirate mikrofon uređaja?"</string>
@@ -1118,16 +1118,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Prioritetne konverzacije"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Nedavne konverzacije"</string>
<string name="okay" msgid="6490552955618608554">"Važi"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Pre <xliff:g id="DURATION">%1$s</xliff:g> dana"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Pre nedelju dana"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Pre 2 nedelje"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Pre više od nedelju dana"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Pre više od 2 nedelje"</string>
<string name="birthday_status" msgid="2596961629465396761">"Rođendan"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> danas slavi rođendan"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Rođendan je uskoro"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index b23f3de..63ec926 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -412,8 +412,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"Выкарыстана <xliff:g id="DATA_USED">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Ліміт <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Папярэджанне: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Працоўныя праграмы"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Начная падсветка"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Уключаць увечары"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Да ўсходу сонца"</string>
@@ -428,7 +427,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC адключаны"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC уключаны"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Запіс экрана"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Запіс экрана"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Пачаць"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Спыніць"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Разблакіраваць мікрафон прылады?"</string>
@@ -1051,8 +1050,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Перамясціць на край і схаваць"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Перамясціць за край і паказаць"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"уключыць/выключыць"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"Элементы кіравання домам"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Выберыце праграму для дадавання элементаў кіравання"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one">Дададзены <xliff:g id="NUMBER_1">%s</xliff:g> элемент кіравання.</item>
@@ -1068,8 +1066,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"выдаліць з абранага"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"Перамясціць у пазіцыю <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Сродкі кіравання"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"Выберыце элементы кіравання, да якіх вы хочаце мець доступ з Хуткіх налад"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Каб змяніць парадак элементаў кіравання, утрымлівайце і перацягвайце іх"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Усе элементы кіравання выдалены"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Змяненні не захаваны"</string>
@@ -1108,8 +1105,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"Не ўдалося загрузіць стан"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Памылка, паўтарыце спробу"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Выконваецца"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"Каб убачыць новыя элементы кіравання, адкрыйце \"Хуткія налады\""</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Дадаць элементы кіравання"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Змяніць элементы кіравання"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Дадайце прылады вываду"</string>
@@ -1128,16 +1124,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Прыярытэтныя размовы"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Нядаўнія размовы"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> сут таму"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 тыдзень таму"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 тыдні таму"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Больш за 1 тыдзень таму"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Больш за 2 тыдні таму"</string>
<string name="birthday_status" msgid="2596961629465396761">"Дзень нараджэння"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> святкуе дзень нараджэння"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Хутка свята"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 534cedd..a064d10 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"КБП е деактивирана"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"КБП е активирана"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Записване на екрана"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Запис на екрана"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Старт"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Стоп"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Да се отблокира ли микрофонът на устройството?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Разговори с приоритет"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Скорошни разговори"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Преди <xliff:g id="DURATION">%1$s</xliff:g> дни"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Преди 1 седмица"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Преди 2 седмици"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Преди повече от 1 седмица"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Преди повече от 2 седмици"</string>
<string name="birthday_status" msgid="2596961629465396761">"Рожден ден"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Днес е рожденият ден на <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Предстоящ рожден ден"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 52a2b11..4400cfb 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -408,8 +408,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> ব্যবহৃত হয়েছে"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"সীমা <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সতর্কতা"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"অফিসের অ্যাপ"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"নাইট লাইট"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"সূর্যাস্তে চালু হবে"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"সূর্যোদয় পর্যন্ত"</string>
@@ -424,7 +423,8 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC অক্ষম করা আছে"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC সক্ষম করা আছে"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"স্ক্রিন রেকর্ড"</string>
+ <!-- no translation found for quick_settings_screen_record_label (8650355346742003694) -->
+ <skip />
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"শুরু করুন"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"বন্ধ করুন"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ডিভাইসের মাইক্রোফোন আনব্লক করতে চান?"</string>
@@ -1041,8 +1041,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"প্রান্তে যান ও আড়াল করুন"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"প্রান্ত থেকে সরান এবং দেখুন"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"টগল করুন"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"হোম কন্ট্রোল"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"কন্ট্রোল যোগ করতে অ্যাপ বেছে নিন"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g>টি কন্ট্রোল যোগ করা হয়েছে।</item>
@@ -1056,8 +1055,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"পছন্দসই থেকে সরান"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"<xliff:g id="NUMBER">%d</xliff:g> অবস্থানে সরান"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"নিয়ন্ত্রণ"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"যে কন্ট্রোল অ্যাক্সেস করতে চান তা \'দ্রুত সেটিংস\' থেকে বেছে নিন"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"কন্ট্রোলগুলিকে আবার সাজানোর জন্য ধরে রেখে টেনে আনুন"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"সমস্ত কন্ট্রোল সরানো হয়েছে"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"পরিবর্তন সেভ করা হয়নি"</string>
@@ -1096,8 +1094,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"স্ট্যাটাস লোড করা যাচ্ছে না"</string>
<string name="controls_error_failed" msgid="960228639198558525">"সমস্যা হয়েছে, আবার চেষ্টা করুন"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"চলছে"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"নতুন কন্ট্রোলগুলি দেখতে \'দ্রুত সেটিংস\' খুলুন"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"কন্ট্রোল যোগ করুন"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"কন্ট্রোল এডিট করুন"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"আউটপুট যোগ করুন"</string>
@@ -1116,16 +1113,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"গুরুত্বপূর্ণ কথোপকথন"</string>
<string name="recent_conversations" msgid="8531874684782574622">"সাম্প্রতিক কথোপকথন"</string>
<string name="okay" msgid="6490552955618608554">"ঠিক আছে"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> দিন আগে"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"১ সপ্তাহ আগে"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"২ সপ্তাহ আগে"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"১ সপ্তাহেরও আগে"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"২ সপ্তাহেরও আগে"</string>
<string name="birthday_status" msgid="2596961629465396761">"জন্মদিন"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"এটি হল <xliff:g id="NAME">%1$s</xliff:g>-এর জন্মদিন"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"জন্মদিন শীঘ্রই আসছে"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 15593a4..b0b012b 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -425,7 +425,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je onemogućen"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je omogućen"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Snimanje ekrana"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Snimanje ekrana"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Započnite"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zaustavite"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblokirati mikrofon uređaja?"</string>
@@ -1118,16 +1118,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Prioritetni razgovori"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Nedavni razgovori"</string>
<string name="okay" msgid="6490552955618608554">"Uredu"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Prije <xliff:g id="DURATION">%1$s</xliff:g> dana"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Prije 1 sedmicu"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Prije 2 sedmice"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Prije više od 1 sedmice"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Prije više od 2 sedmice"</string>
<string name="birthday_status" msgid="2596961629465396761">"Rođendan"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> slavi rođendan"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Rođendan je uskoro"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 3ff6de1..21cfd91 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"L\'NFC està desactivada"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"L\'NFC està activada"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Gravació de pantalla"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Gravació de pantalla"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Inicia"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Atura"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vols desbloquejar el micròfon del dispositiu?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Converses prioritàries"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Converses recents"</string>
<string name="okay" msgid="6490552955618608554">"D\'acord"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Fa <xliff:g id="DURATION">%1$s</xliff:g> dies"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Fa 1 setmana"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Fa 2 setmanes"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Fa més d\'1 setmana"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Fa més de 2 setmanes"</string>
<string name="birthday_status" msgid="2596961629465396761">"Aniversari"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Avui <xliff:g id="NAME">%1$s</xliff:g> fa anys"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Aniversari aviat"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 166c45a..06c2542 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -427,7 +427,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je vypnuto"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je zapnuto"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Záznam obrazovky"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Záznam obrazovky"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Spustit"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ukončit"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Odblokovat mikrofon zařízení?"</string>
@@ -1124,16 +1124,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Prioritní konverzace"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Poslední konverzace"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Před <xliff:g id="DURATION">%1$s</xliff:g> dny"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Před týdnem"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Před 2 týdny"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Před více než týdnem"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Před více než 2 týdny"</string>
<string name="birthday_status" msgid="2596961629465396761">"Narozeniny"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> má narozeniny"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Brzy má narozeniny"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index ac8f154..5fd3c03 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC er deaktiveret"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC er aktiveret"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Optag skærm"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Skærmoptagelse"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vil du fjerne blokeringen af enhedens mikrofone?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Prioriterede samtaler"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Seneste samtaler"</string>
<string name="okay" msgid="6490552955618608554">"Okay"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"For <xliff:g id="DURATION">%1$s</xliff:g> dage siden"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"For 1 uge siden"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"For 2 uger siden"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"For mere end 1 uge siden"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"For mere end 2 uger siden"</string>
<string name="birthday_status" msgid="2596961629465396761">"Fødselsdag"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> har fødselsdag i dag"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Fødselsdag snart"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 247cbf0..6220a48 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ist deaktiviert"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ist aktiviert"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Bildschirmaufnahme"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Bildschirmaufzeichnung"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Starten"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Beenden"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Blockierung des Gerätemikrofons aufheben?"</string>
@@ -1005,7 +1005,7 @@
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" und "</string>
<string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"Von <xliff:g id="APPLICATION_NAME">%1$s</xliff:g> verwendet"</string>
- <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Von <xliff:g id="APPLICATION_NAME">%1$s</xliff:g> zuletzt verwendet"</string>
+ <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Zuletzt von <xliff:g id="APPLICATION_NAME">%1$s</xliff:g> verwendet"</string>
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(geschäftlich)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonanruf"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(über <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Vorrangige Unterhaltungen"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Neueste Unterhaltungen"</string>
<string name="okay" msgid="6490552955618608554">"Ok"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Vor <xliff:g id="DURATION">%1$s</xliff:g> Tagen"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Vor 1 Woche"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Vor 2 Wochen"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Vor über 1 Woche"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Vor über 2 Wochen"</string>
<string name="birthday_status" msgid="2596961629465396761">"Geburtstag"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> hat heute Geburtstag"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Bald Geburtstag"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 8fc960e..bc58a78 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Το NFC είναι απενεργοποιημένο"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Το NFC είναι ενεργοποιημένο"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Εγγραφή οθόνης"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Εγγραφή οθόνης"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Έναρξη"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Διακοπή"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Κατάργηση αποκλεισμού μικροφώνου συσκευής;"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Συζητήσεις προτεραιότητας"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Πρόσφατες συζητήσεις"</string>
<string name="okay" msgid="6490552955618608554">"Εντάξει"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Πριν από <xliff:g id="DURATION">%1$s</xliff:g> ημέρες"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Πριν από 1 εβδομάδα"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Πριν από 2 εβδομάδες"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Πάνω από 1 εβδομάδα"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Πάνω από 2 εβδομάδες"</string>
<string name="birthday_status" msgid="2596961629465396761">"Γενέθλια"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Είναι τα γενέθλια του χρήστη <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Προσεχώς γενέθλια"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 9b2d941..63b54f9 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Screen record"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Screen record"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Priority conversations"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Recent conversations"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> days ago"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 week ago"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 weeks ago"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"More than 1 week ago"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"More than 2 weeks ago"</string>
<string name="birthday_status" msgid="2596961629465396761">"Birthday"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"It\'s <xliff:g id="NAME">%1$s</xliff:g>\'s birthday"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Birthday soon"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index e8e183fb..845ee5b 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Screen record"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Screen record"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Priority conversations"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Recent conversations"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> days ago"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 week ago"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 weeks ago"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"More than 1 week ago"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"More than 2 weeks ago"</string>
<string name="birthday_status" msgid="2596961629465396761">"Birthday"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"It\'s <xliff:g id="NAME">%1$s</xliff:g>\'s birthday"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Birthday soon"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 9b2d941..63b54f9 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Screen record"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Screen record"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Priority conversations"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Recent conversations"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> days ago"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 week ago"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 weeks ago"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"More than 1 week ago"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"More than 2 weeks ago"</string>
<string name="birthday_status" msgid="2596961629465396761">"Birthday"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"It\'s <xliff:g id="NAME">%1$s</xliff:g>\'s birthday"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Birthday soon"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 9b2d941..63b54f9 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Screen record"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Screen record"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Priority conversations"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Recent conversations"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> days ago"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 week ago"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 weeks ago"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"More than 1 week ago"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"More than 2 weeks ago"</string>
<string name="birthday_status" msgid="2596961629465396761">"Birthday"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"It\'s <xliff:g id="NAME">%1$s</xliff:g>\'s birthday"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Birthday soon"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index c55ccb6..7f99a79 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Screen Record"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Screen record"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stop"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Unblock device microphone?"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 392ad07..29c938b 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -352,7 +352,7 @@
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Ubicación desactivada"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Acceso a la cámara"</string>
- <string name="quick_settings_mic_label" msgid="8392773746295266375">"Acceso al micrófono"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Acceso al mic."</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponible"</string>
<string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloqueado"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo multimedia"</string>
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"La tecnología NFC está inhabilitada"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"La tecnología NFC está habilitada"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Grabar pantalla"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Grabación de pantalla"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Detener"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"¿Quieres desbloquear el micrófono del dispositivo?"</string>
@@ -535,7 +535,7 @@
<string name="quick_settings_disclosure_named_management_vpns" msgid="4046375645500668555">"Este dispositivo pertenece a <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> y está conectado a VPN"</string>
<string name="quick_settings_disclosure_managed_profile_monitoring" msgid="1423899084754272514">"Tu organización puede controlar el tráfico de red en tu perfil de trabajo"</string>
<string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8321469176706219860">"Es posible que <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> controle el tráfico de red en tu perfil de trabajo"</string>
- <string name="quick_settings_disclosure_managed_profile_network_activity" msgid="2636594621387832827">"El admin. de TI puede ver la actividad de red de tu perfil de trabajo"</string>
+ <string name="quick_settings_disclosure_managed_profile_network_activity" msgid="2636594621387832827">"El administrador de IT puede ver la actividad de red de tu perfil de trabajo"</string>
<string name="quick_settings_disclosure_monitoring" msgid="8548019955631378680">"Es posible que la red esté supervisada"</string>
<string name="quick_settings_disclosure_vpns" msgid="7213546797022280246">"Este dispositivo está conectado a VPN"</string>
<string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="8117568745060010789">"Tu perfil de trabajo está conectado a <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -1004,8 +1004,8 @@
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Hay aplicaciones que están usando tu <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" y "</string>
- <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"La app de <xliff:g id="APPLICATION_NAME">%1$s</xliff:g> lo está usando"</string>
- <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"La app de <xliff:g id="APPLICATION_NAME">%1$s</xliff:g> lo usó recientemente"</string>
+ <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"En uso en la app de <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
+ <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Uso reciente en app de <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(trabajo)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Llamada telefónica"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(a través de <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Conversaciones prioritarias"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Conversaciones recientes"</string>
<string name="okay" msgid="6490552955618608554">"Aceptar"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Hace <xliff:g id="DURATION">%1$s</xliff:g> días"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Hace 1 semana"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Hace 2 semanas"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Hace más de 1 semana"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Hace más de 2 semanas"</string>
<string name="birthday_status" msgid="2596961629465396761">"Cumpleaños"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Es el cumpleaños de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Cumpleaños pronto"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index ae65aff..0b09369 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -352,7 +352,7 @@
<string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Ubicación desactivada"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"Acceso a la cámara"</string>
- <string name="quick_settings_mic_label" msgid="8392773746295266375">"Acceso al micrófono"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Acceso micro."</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponible"</string>
<string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloqueado"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo multimedia"</string>
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"El NFC está desactivado"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"El NFC está activado"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Grabar pantalla"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Grabación de la pantalla"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Detener"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"¿Desbloquear el micrófono del dispositivo?"</string>
@@ -547,7 +547,7 @@
<string name="monitoring_title" msgid="4063890083735924568">"Supervisión de red"</string>
<string name="monitoring_subtitle_vpn" msgid="800485258004629079">"VPN"</string>
<string name="monitoring_subtitle_network_logging" msgid="2444199331891219596">"Registro de red"</string>
- <string name="monitoring_subtitle_ca_certificate" msgid="8588092029755175800">"Certificados de CA"</string>
+ <string name="monitoring_subtitle_ca_certificate" msgid="8588092029755175800">"Certificados AC"</string>
<string name="disable_vpn" msgid="482685974985502922">"Inhabilitar VPN"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"Desconectar VPN"</string>
<string name="monitoring_button_view_policies" msgid="3869724835853502410">"Ver políticas"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Conversaciones prioritarias"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Conversaciones recientes"</string>
<string name="okay" msgid="6490552955618608554">"Vale"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Hace <xliff:g id="DURATION">%1$s</xliff:g> días"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Hace 1 semana"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Hace 2 semanas"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Hace más de 1 semana"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Hace más de 2 semanas"</string>
<string name="birthday_status" msgid="2596961629465396761">"Cumpleaños"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Es el cumpleaños de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Cumpleaños en breve"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 80cf151..71ac583 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC on keelatud"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC on lubatud"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ekraanisalvestus"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Ekraanisalvestus"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Alustage"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Peatage"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Kas tühistada seadme mikrofoni blokeerimine?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Prioriteetsed vestlused"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Hiljutised vestlused"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> päeva tagasi"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 nädal tagasi"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 nädalat tagasi"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Üle 1 nädala tagasi"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Üle 2 nädala tagasi"</string>
<string name="birthday_status" msgid="2596961629465396761">"Sünnipäev"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"On kasutaja <xliff:g id="NAME">%1$s</xliff:g> sünnipäev"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Peagi on sünnipäev"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index bfe961a..04abe9d 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Desgaituta dago NFC"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Gaituta dago NFC"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Pantaila-grabaketa"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Pantaila-grabaketa"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Hasi"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Gelditu"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Gailuaren mikrofonoa desblokeatu nahi duzu?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Lehentasunezko elkarrizketak"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Azken elkarrizketak"</string>
<string name="okay" msgid="6490552955618608554">"Ados"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Duela <xliff:g id="DURATION">%1$s</xliff:g> egun"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Duela astebete"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Duela bi aste"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Duela astebete baino gehiago"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Duela bi aste baino gehiago"</string>
<string name="birthday_status" msgid="2596961629465396761">"Urtebetetzea"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzailearen urtebetetzea da"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Badator urtebetetzea"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index f1ff1db..0fb93cc 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC غیرفعال است"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC فعال است"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ضبط کردن صفحهنمایش"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ضبط کردن صفحهنمایش"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"شروع"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"توقف"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"میکروفون دستگاه لغو انسداد شود؟"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"مکالمههای اولویتدار"</string>
<string name="recent_conversations" msgid="8531874684782574622">"گفتگوهای اخیر"</string>
<string name="okay" msgid="6490552955618608554">"تأیید"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> روز قبل"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"۱ هفته قبل"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"۲ هفته قبل"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"بیشتر از ۱ هفته قبل"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"بیشتر از ۲ هفته قبل"</string>
<string name="birthday_status" msgid="2596961629465396761">"تاریخ تولد"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"امروز تولد <xliff:g id="NAME">%1$s</xliff:g> است"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"تاریخ تولد نزدیک است"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 79a9647..18e33e5 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC on poistettu käytöstä"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC on käytössä"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Tallennus"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Näytön tallennus"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Aloita"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Lopeta"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Kumotaanko laitteen mikrofonin esto?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Tärkeät keskustelut"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Uusimmat keskustelut"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> päivää sitten"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 viikko sitten"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 viikkoa sitten"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Yli 1 viikko sitten"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Yli 2 viikkoa sitten"</string>
<string name="birthday_status" msgid="2596961629465396761">"Syntymäpäivä"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> viettää tänään syntymäpäiväänsä"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Syntymäpäivä pian"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index f1a6c53..33b023b 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC désactivée"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC activée"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Enregistrement d\'écran"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Enregistrement de l\'écran"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Démarrer"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Arrêter"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Débloquer le microphone de l\'appareil?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Conversations prioritaires"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Conversations récentes"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Il y a <xliff:g id="DURATION">%1$s</xliff:g> jours"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Il y a 1 semaine"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Il y a 2 semaines"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Il y a plus de 1 semaine"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Il y a plus de 2 semaines"</string>
<string name="birthday_status" msgid="2596961629465396761">"Anniversaire"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"C\'est l\'anniversaire de naissance de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Anniversaire proche"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index b8563a9..b4a5843 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC désactivée"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"La technologie NFC est activée"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Enregistrement de l\'écran"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Enregistreur d\'écran"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Démarrer"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Arrêter"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Débloquer le micro de l\'appareil ?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Conversations prioritaires"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Conversations récentes"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Il y a <xliff:g id="DURATION">%1$s</xliff:g> jours"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Il y a 1 semaine"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Il y a 2 semaines"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Il y a plus de 1 semaine"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Il y a plus de 2 semaines"</string>
<string name="birthday_status" msgid="2596961629465396761">"Anniversaire"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"C\'est l\'anniversaire de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Anniversaire à venir"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 7ec711f..045143e 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -218,7 +218,7 @@
<string name="data_connection_hspa" msgid="6096234094857660873">"HSPA"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Itinerancia"</string>
<string name="accessibility_data_connection_wifi" msgid="4422160347472742434">"Wi-Fi"</string>
- <string name="accessibility_no_sim" msgid="1140839832913084973">"Sen SIM"</string>
+ <string name="accessibility_no_sim" msgid="1140839832913084973">"Non hai SIM"</string>
<string name="accessibility_cell_data" msgid="172950885786007392">"Datos móbiles"</string>
<string name="accessibility_cell_data_on" msgid="691666434519443162">"Os datos móbiles están activados"</string>
<string name="cell_data_off" msgid="4886198950247099526">"Desactivados"</string>
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"A opción NFC está desactivada"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"A opción NFC está activada"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Gravación da pantalla"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Gravación da pantalla"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Deter"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Queres desbloquear o micrófono do dispositivo?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Conversas prioritarias"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Conversas recentes"</string>
<string name="okay" msgid="6490552955618608554">"De acordo"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Hai <xliff:g id="DURATION">%1$s</xliff:g> días"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Hai 1 semana"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Hai 2 semanas"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Hai máis de 1 semana"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Hai máis de 2 semanas"</string>
<string name="birthday_status" msgid="2596961629465396761">"Aniversario"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> está de aniversario"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Aniversario a caer"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index d38fcff..815430c 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -409,8 +409,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> વાપર્યો"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> મર્યાદા"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ચેતવણી"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"ઑફિસ માટેની ઍપ"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"રાત્રિ પ્રકાશ"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"સૂર્યાસ્ત વખતે"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"સૂર્યોદય સુધી"</string>
@@ -425,7 +424,8 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC અક્ષમ કરેલ છે"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC સક્ષમ કરેલ છે"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"સ્ક્રીન રેકૉર્ડ કરો"</string>
+ <!-- no translation found for quick_settings_screen_record_label (8650355346742003694) -->
+ <skip />
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"શરૂ કરો"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"રોકો"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ડિવાઇસના માઇક્રોફોનને કરીએ?"</string>
@@ -669,12 +669,10 @@
<string name="wallet_title" msgid="5369767670735827105">"વૉલેટ"</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"બધું બતાવો"</string>
<string name="wallet_action_button_label_unlock" msgid="8663239748726774487">"ચુકવણી કરવા માટે અનલૉક કરો"</string>
- <!-- no translation found for wallet_secondary_label_no_card (1282609666895946317) -->
- <skip />
+ <string name="wallet_secondary_label_no_card" msgid="1282609666895946317">"કોઈ સેટઅપ કર્યું નથી"</string>
<string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"ઉપયોગ કરવા માટે અનલૉક કરો"</string>
<string name="wallet_error_generic" msgid="257704570182963611">"તમારા કાર્ડની માહિતી મેળવવામાં સમસ્યા આવી હતી, કૃપા કરીને થોડા સમય પછી ફરી પ્રયાસ કરો"</string>
- <!-- no translation found for wallet_lockscreen_settings_label (3539105300870383570) -->
- <skip />
+ <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"લૉક સ્ક્રીનના સેટિંગ"</string>
<string name="status_bar_work" msgid="5238641949837091056">"ઑફિસની પ્રોફાઇલ"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"એરપ્લેન મોડ"</string>
<string name="add_tile" msgid="6239678623873086686">"ટાઇલ ઉમેરો"</string>
@@ -864,8 +862,7 @@
<string name="switch_bar_on" msgid="1770868129120096114">"ચાલુ"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"બંધ"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"ઉપલબ્ધ નથી"</string>
- <!-- no translation found for tile_disabled (373212051546573069) -->
- <skip />
+ <string name="tile_disabled" msgid="373212051546573069">"બંધ છે"</string>
<string name="nav_bar" msgid="4642708685386136807">"નેવિગેશન બાર"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"લેઆઉટ"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"અતિરિક્ત ડાબો બટન પ્રકાર"</string>
@@ -1045,8 +1042,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"કિનારી પર ખસેડો અને છુપાવો"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"કિનારીથી ખસેડો અને બતાવો"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ટૉગલ કરો"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"ઘરેલું સાધનોનાં નિયંત્રણો"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"નિયંત્રણો ઉમેરવા માટે ઍપ પસંદ કરો"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> નિયંત્રણ ઉમેર્યું.</item>
@@ -1060,8 +1056,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"મનપસંદમાંથી કાઢી નાખો"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"સ્થાન <xliff:g id="NUMBER">%d</xliff:g> પર ખસેડો"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"નિયંત્રણો"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"ઝડપી સેટિંગમાંથી ઍક્સેસ કરવાના નિયંત્રણો પસંદ કરો"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"નિયંત્રણોને ફરીથી ગોઠવવા માટે તેમને હોલ્ડ કરીને ખેંચો"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"બધા નિયંત્રણો કાઢી નાખ્યા"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ફેરફારો સાચવ્યા નથી"</string>
@@ -1100,8 +1095,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"સ્ટેટસ લોડ કરી શકાતું નથી"</string>
<string name="controls_error_failed" msgid="960228639198558525">"ભૂલ, ફરીથી પ્રયાસ કરો"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"પ્રક્રિયા ચાલુ છે"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"નવા નિયંત્રણો જોવા માટે ઝડપી સેટિંગ ખોલો"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"નિયંત્રણો ઉમેરો"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"નિયંત્રણોમાં ફેરફાર કરો"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"આઉટપુટ ઉમેરો"</string>
@@ -1120,16 +1114,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"પ્રાધાન્યતા ધરાવતી વાતચીતો"</string>
<string name="recent_conversations" msgid="8531874684782574622">"તાજેતરની વાતચીતો"</string>
<string name="okay" msgid="6490552955618608554">"ઓકે"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> દિવસ પહેલાં"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 અઠવાડિયા પહેલાં"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 અઠવાડિયા પહેલાં"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"1 અઠવાડિયા કરતાં પહેલાંથી"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"2 અઠવાડિયા કરતાં પહેલાંથી"</string>
<string name="birthday_status" msgid="2596961629465396761">"જન્મદિવસ"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"આ તો <xliff:g id="NAME">%1$s</xliff:g>નો જન્મદિવસ છે"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"જલ્દી જ જન્મદિવસ છે"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 81389a37..f77db5c 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"एनएफ़सी"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC बंद है"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC चालू है"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"स्क्रीन रिकॉर्ड"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"स्क्रीन रिकॉर्डर"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"शुरू करें"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"रोकें"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"क्या आप डिवाइस के माइक्रोफ़ोन को अनब्लॉक करना चाहते हैं?"</string>
@@ -1004,8 +1004,8 @@
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ऐप्लिकेशन आपकी <xliff:g id="TYPES_LIST">%s</xliff:g> का इस्तेमाल कर रहे हैं."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" और "</string>
- <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"इसे <xliff:g id="APPLICATION_NAME">%1$s</xliff:g> इस्तेमाल कर रहा है"</string>
- <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"हाल ही में, इसे <xliff:g id="APPLICATION_NAME">%1$s</xliff:g> ने इस्तेमाल किया"</string>
+ <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"<xliff:g id="APPLICATION_NAME">%1$s</xliff:g> इस्तेमाल कर रहा है"</string>
+ <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"हाल ही में, <xliff:g id="APPLICATION_NAME">%1$s</xliff:g> ने इस्तेमाल किया"</string>
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ऑफ़िस)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"फ़ोन कॉल"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> की मदद से)"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"अहम बातचीत"</string>
<string name="recent_conversations" msgid="8531874684782574622">"हाल ही में की गई बातचीत"</string>
<string name="okay" msgid="6490552955618608554">"ठीक है"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> दिन पहले"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"एक हफ़्ता पहले"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"दो हफ़्ते पहले"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"एक हफ़्ते से भी पहले"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"दो हफ़्ते से भी पहले"</string>
<string name="birthday_status" msgid="2596961629465396761">"जन्मदिन"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> का जन्मदिन है"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"जन्मदिन आने वाला है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 2ef6fd1..66618b6 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -425,7 +425,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je onemogućen"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je omogućen"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Snimač zaslona"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Snimanje zaslona"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Početak"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zaustavi"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite li deblokirati mikrofon uređaja?"</string>
@@ -1118,16 +1118,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Prioritetni razgovori"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Nedavni razgovori"</string>
<string name="okay" msgid="6490552955618608554">"U redu"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Prije <xliff:g id="DURATION">%1$s</xliff:g> dan/a"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Prije tjedan dana"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Prije dva tjedna"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Prije više od tjedan dana"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Prije više od dva tjedna"</string>
<string name="birthday_status" msgid="2596961629465396761">"Rođendan"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> ima rođendan"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Rođendan uskoro"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index c9f9a29..540bd43 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Az NFC ki van kapcsolva"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Az NFC be van kapcsolva"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Képernyő rögzítése"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Képernyőrögzítés"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Indítás"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Leállítás"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Feloldja az eszközmikrofon letiltását?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Fontos beszélgetések"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Legutóbbi beszélgetések"</string>
<string name="okay" msgid="6490552955618608554">"Rendben"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> napja"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 hete"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 hete"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Több mint 1 hete"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Több mint 2 hete"</string>
<string name="birthday_status" msgid="2596961629465396761">"Születésnap"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Ma van <xliff:g id="NAME">%1$s</xliff:g> születésnapja"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Közelgő születésnap"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 7a66fc0..4f4afd6 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC-ն անջատված է"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC-ն միացված է"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Էկրանի ձայնագրում"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Էկրանի տեսագրում"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Սկսել"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Կանգնեցնել"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Արգելահանե՞լ սարքի խոսափողը"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Կարևոր զրույցներ"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Վերջին հաղորդագրությունները"</string>
<string name="okay" msgid="6490552955618608554">"Եղավ"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> օր առաջ"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 շաբաթ առաջ"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 շաբաթ առաջ"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Ավելի քան 1 շաբաթ առաջ"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Ավելի քան 2 շաբաթ առաջ"</string>
<string name="birthday_status" msgid="2596961629465396761">"Ծննդյան օր"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Այսօր <xliff:g id="NAME">%1$s</xliff:g>-ի տարեդարձն է"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Շուտով ծննդյանս օրն է"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 1db59de..8fc2e8a 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC dinonaktifkan"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC diaktifkan"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Rekaman Layar"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Perekam layar"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Mulai"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Berhenti"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Batalkan pemblokiran mikrofon perangkat?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Percakapan prioritas"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Percakapan terbaru"</string>
<string name="okay" msgid="6490552955618608554">"Oke"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> hari lalu"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 minggu lalu"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 minggu lalu"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Lebih dari 1 minggu lalu"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Lebih dari 2 minggu lalu"</string>
<string name="birthday_status" msgid="2596961629465396761">"Ulang Tahun"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Hari ini ulang tahun <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Ulang tahun segera"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 7aa9980..adaa7a7 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Slökkt á NFC"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Kveikt á NFC"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Skjáupptaka"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Skjáupptaka"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Hefja"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stöðva"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Opna fyrir hljóðnema tækisins?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Forgangssamtöl"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Nýleg samtöl"</string>
<string name="okay" msgid="6490552955618608554">"Í lagi"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Fyrir <xliff:g id="DURATION">%1$s</xliff:g> dögum"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Fyrir 1 viku"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Fyrir 2 vikum"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Fyrir meira en 1 viku"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Fyrir meira en 2 vikum"</string>
<string name="birthday_status" msgid="2596961629465396761">"Afmæli"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> á afmæli"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Afmæli á næstunni"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 04b45ec..31de7b2 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC non attiva"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC attiva"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Registrazione schermo"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Registrazione dello schermo"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Inizia"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Interrompi"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vuoi sbloccare il microfono del dispositivo?"</string>
@@ -1004,7 +1004,7 @@
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Le app stanno usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
- <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"Attualmente usato da <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
+ <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"Attualmente in uso per <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Usato di recente da <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(lavoro)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonata"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Conversazioni prioritarie"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Conversazioni recenti"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> giorni fa"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 settimana fa"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 settimane fa"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Più di 1 settimana fa"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Più di 2 settimane fa"</string>
<string name="birthday_status" msgid="2596961629465396761">"Compleanno"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"È il compleanno di <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Compleanno imminente"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 20578ba..12e4dc7 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -427,7 +427,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC מושבת"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC מופעל"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"הקלטת המסך"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"הקלטת המסך"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"התחלה"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"עצירה"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"לבטל את חסימת המיקרופון של המכשיר?"</string>
@@ -1050,7 +1050,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"העברה לשוליים והסתרה"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"העברה מהשוליים והצגה"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"החלפת מצב"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"בית חכם"</string>
+ <string name="quick_controls_title" msgid="7095074621086860062">"פקדי הבית החכם"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"יש לבחור אפליקציה כדי להוסיף פקדים"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="two">נוספו <xliff:g id="NUMBER_1">%s</xliff:g> פקדים.</item>
@@ -1124,16 +1124,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"שיחות בעדיפות גבוהה"</string>
<string name="recent_conversations" msgid="8531874684782574622">"שיחות אחרונות"</string>
<string name="okay" msgid="6490552955618608554">"בסדר"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"לפני <xliff:g id="DURATION">%1$s</xliff:g> ימים"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"לפני שבוע"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"לפני שבועיים"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"לפני יותר משבוע"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"לפני יותר משבועיים"</string>
<string name="birthday_status" msgid="2596961629465396761">"יום הולדת"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"זהו יום ההולדת של <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"יום הולדת יחול בקרוב"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index df44781..f093cad 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC は無効です"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC は有効です"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"スクリーン レコード"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"スクリーン レコード"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"開始"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"停止"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"デバイスのマイクのブロックを解除しますか?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"優先度の高い会話"</string>
<string name="recent_conversations" msgid="8531874684782574622">"最近の会話"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> 日前"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 週間前"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 週間前"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"1 週間以上前"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"2 週間以上前"</string>
<string name="birthday_status" msgid="2596961629465396761">"誕生日"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"今日は <xliff:g id="NAME">%1$s</xliff:g> さんのお誕生日です"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"もうすぐ誕生日"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 9bbb200..06a56bc 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC გათიშულია"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ჩართულია"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ეკრანის ჩანაწერი"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ეკრანის ჩანაწერი"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"დაწყება"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"შეწყვეტა"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"გსურთ მოწყობილობის მიკროფონის განბლოკვა?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"პრიორიტეტული საუბრები"</string>
<string name="recent_conversations" msgid="8531874684782574622">"ბოლო მიმოწერები"</string>
<string name="okay" msgid="6490552955618608554">"კარგი"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> დღის წინ"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 კვირის წინ"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 კვირის წინ"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"1 კვირაზე მეტი ხნის წინ"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"2 კვირაზე მეტი ხნის წინ"</string>
<string name="birthday_status" msgid="2596961629465396761">"დაბადების დღე"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> დღეს იუბილარია"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"მალე დაბადების დღეა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 474abd6..6d01251 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -351,8 +351,8 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Енгізу әдісі"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Локация"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Орын өшірулі"</string>
- <string name="quick_settings_camera_label" msgid="5612076679385269339">"Камераны пайдалану рұқсаты"</string>
- <string name="quick_settings_mic_label" msgid="8392773746295266375">"Микрофонды пайдалану рұқсаты"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Камера пайдалану"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Микрофон пайдалану"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Қолжетімді"</string>
<string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Бөгелген"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Meдиа құрылғысы"</string>
@@ -408,8 +408,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> пайдаланылған"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> шегі"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> туралы ескерту"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Жұмыс қолданбалары"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Түнгі жарық"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Күн батқанда қосу"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Күн шыққанға дейін"</string>
@@ -424,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC өшірулі"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC қосулы"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Экранды жазу"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Экранды жазу"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Бастау"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Тоқтату"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Құрылғы микрофонының бөгеуі алынсын ба?"</string>
@@ -1041,8 +1040,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Шетке жылжыту және жасыру"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Шетке жылжыту және көрсету"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ауыстыру"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"Үйді басқару элементтері"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Басқару элементтері қосылатын қолданбаны таңдаңыз"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> басқару элементі енгізілді.</item>
@@ -1056,8 +1054,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"таңдаулылардан алып тастау"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"<xliff:g id="NUMBER">%d</xliff:g> позициясына жылжыту"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Басқару элементтері"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"\"Жылдам параметрлер\" мәзірінен пайдалануға болатын басқару элементтерін таңдаңыз."</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Басқару элементтерінің ретін өзгерту үшін оларды басып тұрып сүйреңіз."</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Барлық басқару элементтері жойылды."</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Өзгерістер сақталмады."</string>
@@ -1096,8 +1093,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"Күйді жүктеу мүмкін емес."</string>
<string name="controls_error_failed" msgid="960228639198558525">"Қате шықты. Қайталап көріңіз."</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Орындалуда"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"Жаңа басқару элементтерін көру үшін \"Жылдам параметрлер\" мәзірін ашыңыз."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Басқару элементтерін қосу"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Басқару элементтерін өзгерту"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Шығыс сигналдарды қосу"</string>
@@ -1116,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Маңызды әңгімелер"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Соңғы әңгімелер"</string>
<string name="okay" msgid="6490552955618608554">"Жарайды"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> күн бұрын"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 апта бұрын"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 апта бұрын"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Кемінде 1 апта бұрын"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Кемінде 2 апта бұрын"</string>
<string name="birthday_status" msgid="2596961629465396761">"Туған күн"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Бүгін <xliff:g id="NAME">%1$s</xliff:g> туған күнін атап өтуде!"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Жақында туған күн"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index caedc3c..08045e3 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"បានបិទ NFC"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"បានបើក NFC"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ការថតវីដេអូអេក្រង់"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ការថតវីដេអូអេក្រង់"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ចាប់ផ្ដើម"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ឈប់"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ឈប់ទប់ស្កាត់មីក្រូហ្វូនរបស់ឧបករណ៍ឬ?"</string>
@@ -1005,7 +1005,7 @@
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" និង "</string>
<string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"កំពុងប្រើដោយ <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
- <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"បានលុបថ្មីៗដោយ <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
+ <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"បានប្រើនាពេលថ្មីៗដោយ <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ការងារ)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ការហៅទូរសព្ទ"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(តាមរយៈ <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"ការសន្ទនាអាទិភាព"</string>
<string name="recent_conversations" msgid="8531874684782574622">"ការសន្ទនាថ្មីៗ"</string>
<string name="okay" msgid="6490552955618608554">"យល់ព្រម"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> ថ្ងៃមុន"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 សប្ដាហ៍មុន"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 សប្ដាហ៍មុន"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"ជាង 1 សប្ដាហ៍មុន"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"ជាង 2 សប្ដាហ៍មុន"</string>
<string name="birthday_status" msgid="2596961629465396761">"ថ្ងៃកំណើត"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"នេះគឺជាថ្ងៃកំណើតរបស់ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"ថ្ងៃកំណើតឆាប់ៗនេះ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 7c95f00..211e943 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -136,8 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"ಕ್ಯಾಮರಾ"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ಫೋನ್"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ಧ್ವನಿ ಸಹಾಯಕ"</string>
- <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
- <skip />
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"Wallet"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"ಅನ್ಲಾಕ್"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"ಸಾಧನ ಲಾಕ್ ಆಗಿದೆ"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ಗಾಗಿ ನಿರೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ"</string>
@@ -409,8 +408,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> ಬಳಸಲಾಗಿದೆ"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ಮಿತಿ"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ಎಚ್ಚರಿಕೆ"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"ಕೆಲಸಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಆ್ಯಪ್ಗಳು"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"ನೈಟ್ ಲೈಟ್"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"ಸೂರ್ಯಾಸ್ತದಲ್ಲಿ"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"ಸೂರ್ಯೋದಯದವರೆಗೆ"</string>
@@ -425,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ಸಕ್ರಿಯಗೊಂಡಿದೆ"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡ್"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡ್"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ಪ್ರಾರಂಭಿಸಿ"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ನಿಲ್ಲಿಸಿ"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ಸಾಧನದ ಮೈಕ್ರೋಫೋನ್ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆಯಬೇಕೆ?"</string>
@@ -1006,8 +1004,8 @@
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ನಿಮ್ಮ <xliff:g id="TYPES_LIST">%s</xliff:g> ಅನ್ನು ಆ್ಯಪ್ಗಳು ಬಳಸುತ್ತಿವೆ."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ಮತ್ತು "</string>
- <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"<xliff:g id="APPLICATION_NAME">%1$s</xliff:g> ನಿಂದ ಬಳಸಲಾಗಿದೆ"</string>
- <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"ಇತ್ತೀಚೆಗೆ <xliff:g id="APPLICATION_NAME">%1$s</xliff:g> ನಿಂದ ಬಳಸಲಾಗಿದೆ"</string>
+ <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"<xliff:g id="APPLICATION_NAME">%1$s</xliff:g> ಇದನ್ನು ಬಳಸುತ್ತಿದೆ"</string>
+ <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"ಇತ್ತೀಚೆಗೆ <xliff:g id="APPLICATION_NAME">%1$s</xliff:g> ಇದನ್ನು ಬಳಸಿದೆ"</string>
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ಉದ್ಯೋಗ)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ಫೋನ್ ಕರೆ"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> ಮೂಲಕ)"</string>
@@ -1042,8 +1040,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ಅಂಚಿಗೆ ಸರಿಸಿ ಮತ್ತು ಮರೆಮಾಡಿ"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ಅಂಚನ್ನು ಸರಿಸಿ ಮತ್ತು ತೋರಿಸಿ"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ಟಾಗಲ್ ಮಾಡಿ"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"ಹೋಮ್ ನಿಯಂತ್ರಣಗಳು"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲು ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲಾಗಿದೆ.</item>
@@ -1057,8 +1054,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"ಮೆಚ್ಚಿನದಲ್ಲದ್ದು"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"ಸ್ಥಾನ <xliff:g id="NUMBER">%d</xliff:g> ಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"ನಿಯಂತ್ರಣಗಳು"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳಿಂದ ಪ್ರವೇಶಿಸಲು ನಿಯಂತ್ರಣಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"ನಿಯಂತ್ರಣಗಳನ್ನು ಮರುಹೊಂದಿಸಲು ಹೋಲ್ಡ್ ಮಾಡಿ ಮತ್ತು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"ಎಲ್ಲಾ ನಿಯಂತ್ರಣಗಳನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ಬದಲಾವಣೆಗಳನ್ನು ಉಳಿಸಲಾಗಿಲ್ಲ"</string>
@@ -1097,8 +1093,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"ಸ್ಥಿತಿ ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="controls_error_failed" msgid="960228639198558525">"ದೋಷ, ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"ಪ್ರಗತಿಯಲ್ಲಿದೆ"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"ಹೊಸ ನಿಯಂತ್ರಣಗಳನ್ನು ನೋಡಲು ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಿ"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"ನಿಯಂತ್ರಣಗಳನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"ಔಟ್ಪುಟ್ಗಳನ್ನು ಸೇರಿಸಿ"</string>
@@ -1117,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"ಆದ್ಯತೆಯ ಸಂಭಾಷಣೆಗಳು"</string>
<string name="recent_conversations" msgid="8531874684782574622">"ಇತ್ತೀಚಿನ ಸಂಭಾಷಣೆಗಳು"</string>
<string name="okay" msgid="6490552955618608554">"ಸರಿ"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> ದಿನಗಳ ಹಿಂದೆ"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 ವಾರದ ಹಿಂದೆ"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 ವಾರಗಳ ಹಿಂದೆ"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"1 ವಾರಕ್ಕಿಂತ ಹಿಂದೆ"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"2 ವಾರಗಳಿಗಿಂತ ಹಿಂದೆ"</string>
<string name="birthday_status" msgid="2596961629465396761">"ಜನ್ಮದಿನ"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರ ಜನ್ಮದಿನ"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"ಶೀಘ್ರದಲ್ಲಿ ಜನ್ಮದಿನವಿದೆ"</string>
@@ -1157,8 +1147,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"ದೃಢೀಕರಿಸಿ"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"ಸಾಧನವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ತೆರೆಯುವುದಕ್ಕಾಗಿ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ಬಳಸಿ"</string>
- <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
- <skip />
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ದೃಢೀಕರಣದ ಅವಶ್ಯಕತೆಯಿದೆ. ದೃಢೀಕರಿಸಲು ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಸ್ಪರ್ಶಿಸಿ."</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ಚಾಲ್ತಿಯಲ್ಲಿರುವ ಫೋನ್ ಕರೆ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index b613cc1..f32aeff 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 사용 중지됨"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 사용 설정됨"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"화면 녹화"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"화면 녹화"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"시작"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"중지"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"기기 마이크를 차단 해제하시겠습니까?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"우선순위 대화"</string>
<string name="recent_conversations" msgid="8531874684782574622">"최근 대화"</string>
<string name="okay" msgid="6490552955618608554">"확인"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g>일 전"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1주 전"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2주 전"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"1주 이상 전"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"2주 이상 전"</string>
<string name="birthday_status" msgid="2596961629465396761">"생일"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"오늘은 <xliff:g id="NAME">%1$s</xliff:g>님의 생일입니다."</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"다가오는 생일"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index abdb435..d997a7b 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -408,8 +408,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> колдонулду"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> чектөө"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> эскертүү"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Жумуш колдонмолору"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Түнкү режим"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Күн батканда күйөт"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Күн чыкканга чейин"</string>
@@ -424,15 +423,15 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC өчүрүлгөн"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC иштетилген"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Экранды жаздыруу"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Экрандан видео жаздырып алуу"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Баштадык"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Токтотуу"</string>
- <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Түзмөктүн микрофонунун кулпусу ачысынбы?"</string>
- <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Түзмөктүн камерасынын кулпусу ачылсынбы?"</string>
+ <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Түзмөктүн микрофонунун кулпусун ачасызбы?"</string>
+ <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Түзмөктүн камерасынын кулпусун ачасызбы?"</string>
<string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Түзмөктүн камерасы менен микрофону бөгөттөн чыгарылсынбы?"</string>
- <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Ушуну менен микрофонуңузду колдонууга уруксаты бар бардык колдонмолор менен кызматтар бөгөттөн чыгарылат."</string>
- <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Ушуну менен камераңызды колдонууга уруксаты бар бардык колдонмолор менен кызматтар бөгөттөн чыгарылат."</string>
- <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Ушуну менен камераңызды же микрофонуңузду колдонууга уруксаты бар бардык колдонмолор менен кызматтар бөгөттөн чыгарылат."</string>
+ <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Микрофонуңузду колдонууга уруксат алган бардык колдонмолор менен кызматтар бөгөттөн чыгат."</string>
+ <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Камераны колдонууга уруксат алган бардык колдонмолор менен кызматтар бөгөттөн чыгат."</string>
+ <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Камераңызды же микрофонуңузду колдонууга уруксат алган бардык колдонмолор менен кызматтар бөгөттөн чыгат."</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Түзмөк"</string>
<string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Башка колдонмого которулуу үчүн өйдө сүрүңүз"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Колдонмолорду тез которуштуруу үчүн, оңго сүйрөңүз"</string>
@@ -1041,8 +1040,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Ичине жылдырып, көрсөтүңүз"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Сыртка жылдырып, көрсөтүңүз"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"өчүрүү/күйгүзүү"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"Үйдү көзөмөлдөө каражаттары"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Башкаруу элементтери кошула турган колдонмону тандоо"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> көзөмөл кошулду.</item>
@@ -1056,8 +1054,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"сүйүктүүлөрдөн чыгаруу"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"<xliff:g id="NUMBER">%d</xliff:g>-позицияга жылдыруу"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Башкаруу элементтери"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"Ыкчам жөндөөлөрдөн кирүү үчүн көзөмөлдөө каражаттарын тандаңыз"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Башкаруу элементтеринин иретин өзгөртүү үчүн кармап туруп, сүйрөңүз"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Бардык башкаруу элементтери өчүрүлдү"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Өзгөртүүлөр сакталган жок"</string>
@@ -1096,8 +1093,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"Абалы жүктөлгөн жок"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Ката, кайталап көрүңүз"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Аткарылууда"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"Жаңы көзөмөлдөө каражаттарын көрүү үчүн Ыкчам жөндөөлөрдү ачыңыз"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Башкаруу элементтерин кошуу"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Башкаруу элементтерин түзөтүү"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Медиа түзмөктөрдү кошуу"</string>
@@ -1116,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Маанилүү сүйлөшүүлөр"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Акыркы сүйлөшүүлөр"</string>
<string name="okay" msgid="6490552955618608554">"Макул"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> күн мурун"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 апта мурун"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 апта мурда"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"1 аптадан ашык мурда"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"2 аптадан ашык мурда"</string>
<string name="birthday_status" msgid="2596961629465396761">"Туулган күн"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> бүгүн туулган күнүн белгилеп жатат"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Алдыдагы туулган күн"</string>
diff --git a/packages/SystemUI/res/values-land-television/dimens.xml b/packages/SystemUI/res/values-land-television/dimens.xml
index 220ed5c..a9bc9e5 100644
--- a/packages/SystemUI/res/values-land-television/dimens.xml
+++ b/packages/SystemUI/res/values-land-television/dimens.xml
@@ -23,6 +23,7 @@
<dimen name="volume_dialog_slider_width">4dp</dimen>
<dimen name="volume_dialog_slider_corner_radius">@dimen/volume_dialog_slider_width</dimen>
<dimen name="volume_dialog_background_blur_radius">100dp</dimen>
+ <dimen name="volume_tool_tip_right_margin">136dp</dimen>
<dimen name="tv_volume_dialog_bubble_size">36dp</dimen>
<dimen name="tv_volume_dialog_row_padding">6dp</dimen>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index c6931e8..9df9db6 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -43,8 +43,8 @@
<dimen name="qs_detail_margin_top">14dp</dimen>
- <dimen name="volume_tool_tip_right_margin">136dp</dimen>
<dimen name="volume_tool_tip_top_margin">12dp</dimen>
+ <dimen name="volume_row_slider_height">128dp</dimen>
<dimen name="controls_activity_view_top_offset">25dp</dimen>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 3790868..6a19532 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC is disabled"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC is enabled"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ການບັນທຶກໜ້າຈໍ"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ບັນທຶກໜ້າຈໍ"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ເລີ່ມ"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ຢຸດ"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ຍົກເລີກການບລັອກໄມໂຄຣໂຟນອຸປະກອນບໍ?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"ການສົນທະນາສຳຄັນ"</string>
<string name="recent_conversations" msgid="8531874684782574622">"ການສົນທະນາຫຼ້າສຸດ"</string>
<string name="okay" msgid="6490552955618608554">"ຕົກລົງ"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> ມື້ກ່ອນ"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 ອາທິດກ່ອນ"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 ອາທິດກ່ອນ"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"ເກີນ 1 ອາທິດກ່ອນ"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"ເກີນ 2 ອາທິດກ່ອນ"</string>
<string name="birthday_status" msgid="2596961629465396761">"ວັນເກີດ"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"ວັນເກີດຂອງ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"ວັນເກີດໃນໄວໆນີ້"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 8e533e6..ae4fd14 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -427,7 +427,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"ALR"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"ALR išjungtas"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"ALR įjungtas"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ekrano įrašas"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Ekrano įrašas"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Pradėti"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stabdyti"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Panaikinti įrenginio mikrofono blokavimą?"</string>
@@ -1124,16 +1124,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Svarbiausi pokalbiai"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Paskutiniai pokalbiai"</string>
<string name="okay" msgid="6490552955618608554">"Gerai"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Prieš <xliff:g id="DURATION">%1$s</xliff:g> d."</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Prieš 1 sav."</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Prieš 2 sav."</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Daugiau kaip prieš 1 sav."</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Daugiau kaip prieš 2 sav."</string>
<string name="birthday_status" msgid="2596961629465396761">"Gimimo diena"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> gimtadienis"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Netrukus gimtadienis"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 3c2d8ed..635baa0 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -29,9 +29,9 @@
<string name="battery_low_percent_format_hybrid" msgid="3985614339605686167">"Atlikušais laiks: <xliff:g id="PERCENTAGE">%1$s</xliff:g> — aptuveni <xliff:g id="TIME">%2$s</xliff:g> (ņemot vērā lietojumu)"</string>
<string name="battery_low_percent_format_hybrid_short" msgid="5917433188456218857">"Atlikušais laiks: <xliff:g id="PERCENTAGE">%1$s</xliff:g> — aptuveni <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"Atlikuši <xliff:g id="PERCENTAGE">%s</xliff:g>. Ir ieslēgts akumulatora enerģijas taupīšanas režīms."</string>
- <string name="invalid_charger" msgid="4370074072117767416">"Nevar veikt uzlādi, izmantojot USB. Izmantojiet ierīces komplektācijā iekļauto uzlādes ierīci."</string>
+ <string name="invalid_charger" msgid="4370074072117767416">"Nevar veikt uzlādi, izmantojot USB. Izmantojiet ierīces komplektācijā iekļauto lādētāju."</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Nevar veikt uzlādi, izmantojot USB"</string>
- <string name="invalid_charger_text" msgid="2339310107232691577">"Izmantojiet ierīces komplektācijā iekļauto uzlādes ierīci"</string>
+ <string name="invalid_charger_text" msgid="2339310107232691577">"Izmantojiet ierīces komplektācijā iekļauto lādētāju"</string>
<string name="battery_low_why" msgid="2056750982959359863">"Iestatījumi"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vai ieslēgt akumulatora enerģijas taupīšanas režīmu?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Par akumulatora enerģijas taupīšanas režīmu"</string>
@@ -425,7 +425,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ir atspējoti"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ir iespējoti"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ekrāna ierakstīšana"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Ekrāna ierakstīšana"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Sākt"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Apturēt"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vai vēlaties atbloķēt ierīces mikrofonu?"</string>
@@ -1118,16 +1118,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Prioritārās sarunas"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Jaunākās sarunas"</string>
<string name="okay" msgid="6490552955618608554">"Labi"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Pirms <xliff:g id="DURATION">%1$s</xliff:g> dienām"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Pirms 1 nedēļas"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Pirms 2 nedēļām"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Pirms vairāk nekā 1 nedēļas"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Pirms vairāk nekā 2 nedēļām"</string>
<string name="birthday_status" msgid="2596961629465396761">"Dzimšanas diena"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Ir lietotāja <xliff:g id="NAME">%1$s</xliff:g> dzimšanas diena"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Gaidāma dzimšanas diena"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 2e3847f..6a092d6 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC е оневозможено"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC е овозможено"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Снимање екран"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Снимање екран"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Започни"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Сопри"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Да се одблокира пристапот до микрофонот на уредот?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Приоритетни разговори"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Неодамнешни разговори"</string>
<string name="okay" msgid="6490552955618608554">"Во ред"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Пред <xliff:g id="DURATION">%1$s</xliff:g> ден"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Пред 1 седмица"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Пред 2 седмици"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Пред повеќе од 1 седмица"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Пред повеќе од 2 седмици"</string>
<string name="birthday_status" msgid="2596961629465396761">"Роденден"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Роденден е на <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Претстоен роденден"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 7c98ad8..292e1e1 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC പ്രവർത്തനക്ഷമമാക്കി"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"സ്ക്രീൻ റെക്കോർഡ്"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"സ്ക്രീൻ റെക്കോർഡ്"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ആരംഭിക്കുക"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"നിര്ത്തുക"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ഉപകരണ മൈക്രോഫോൺ അൺബ്ലോക്ക് ചെയ്യണോ?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"മുൻഗണനാ സംഭാഷണങ്ങൾ"</string>
<string name="recent_conversations" msgid="8531874684782574622">"അടുത്തിടെയുള്ള സംഭാഷണങ്ങൾ"</string>
<string name="okay" msgid="6490552955618608554">"ശരി"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> ദിവസം മുമ്പ്"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"ഒരാഴ്ച മുമ്പ്"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 ആഴ്ച മുമ്പ്"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"ഒരാഴ്ചയിൽ കൂടുതൽ"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"2 ആഴ്ചയിൽ കൂടുതൽ"</string>
<string name="birthday_status" msgid="2596961629465396761">"ജന്മദിനം"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"ഇന്ന് <xliff:g id="NAME">%1$s</xliff:g> എന്നയാളുടെ ജന്മദിനമാണ്"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"ഉടൻ വരുന്ന ജന്മദിനം"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 35bd180..2bcca67 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC-г цуцалсан"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC-г идэвхжүүлсэн"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Дэлгэцийн бичлэг хийх"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Дэлгэцийн үйлдэл бичих"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Эхлүүлэх"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Зогсоох"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Төхөөрөмжийн микрофоныг блокоос гаргах уу?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Чухал харилцан яриа"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Саяхны харилцан яриа"</string>
<string name="okay" msgid="6490552955618608554">"За"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> хоногийн өмнө"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 долоо хоногийн өмнө"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 долоо хоногийн өмнө"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"1 долоо хоног гаруйн өмнө"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"2 долоо хоног гаруйн өмнө"</string>
<string name="birthday_status" msgid="2596961629465396761">"Төрсөн өдөр"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Өнөөдөр <xliff:g id="NAME">%1$s</xliff:g>-н төрсөн өдөр болж байна"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Удахгүй болох төрсөн өдөр"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 2cf39f4..c69992b 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -408,8 +408,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> वापरले"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> मर्यादा"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावणी"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"कामाशी संबंधित अॅप्स"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"रात्रीचा प्रकाश"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"संध्याकाळी सुरू असते"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"सूर्योदयापर्यंत"</string>
@@ -424,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC अक्षम केले आहे"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC सक्षम केले आहे"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"स्क्रीन रेकॉर्ड"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"स्क्रीन रेकॉर्ड"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"सुरू"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"थांबा"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"डिव्हाइसचा मायक्रोफोन अनब्लॉक करायचा आहे का?"</string>
@@ -1041,8 +1040,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"एजवर हलवा आणि लपवा"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"एजवर हलवा आणि दाखवा"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"टॉगल करा"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"होम कंट्रोल"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"नियंत्रणे जोडण्यासाठी ॲप निवडा"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> नियंत्रणे जोडली.</item>
@@ -1056,8 +1054,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"नावडते"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"<xliff:g id="NUMBER">%d</xliff:g> स्थानावर हलवा"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"नियंत्रणे"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"क्विक सेटिंग्ज मधून अॅक्सेस करण्यासाठी नियंत्रणे निवडा"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"नियंत्रणांची पुनर्रचना करण्यासाठी धरून ठेवा आणि ड्रॅग करा"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"सर्व नियंत्रणे काढून टाकली आहेत"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"बदल सेव्ह केले गेले नाहीत"</string>
@@ -1096,8 +1093,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"स्थिती लोड करू शकत नाही"</string>
<string name="controls_error_failed" msgid="960228639198558525">"एरर, पुन्हा प्रयत्न करा"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"प्रगतीपथावर आहे"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"नवीन नियंत्रणे पाहण्यासाठी क्विक सेटिंग्ज उघडा"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"नियंत्रणे जोडा"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"नियंत्रणे व्यवस्थापित करा"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"आउटपुट जोडा"</string>
@@ -1116,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"प्राधान्य दिलेली संभाषणे"</string>
<string name="recent_conversations" msgid="8531874684782574622">"अलीकडील संभाषणे"</string>
<string name="okay" msgid="6490552955618608554">"ओके"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> दिवसांपूर्वी"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"१ आठवड्यापूर्वी"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"२ आठवड्यांपूर्वी"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"१ आठवड्यापेक्षा जास्त आधी"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"२ आठवड्यांपेक्षा जास्त आधी"</string>
<string name="birthday_status" msgid="2596961629465396761">"वाढदिवस"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"आज <xliff:g id="NAME">%1$s</xliff:g> यांचा वाढदिवस आहे"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"वाढदिवस लवकरच आहे"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index f56008ec..d2780b9 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC dilumpuhkan"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC didayakan"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Rakam Skrin"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Rakam skrin"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Mula"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Berhenti"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Nyahsekat mikrofon peranti?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Perbualan keutamaan"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Perbualan terbaharu"</string>
<string name="okay" msgid="6490552955618608554">"Okey"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> hari lalu"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 minggu yang lalu"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 minggu yang lalu"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Lebih 1 minggu yang lalu"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Lebih 2 minggu yang lalu"</string>
<string name="birthday_status" msgid="2596961629465396761">"Hari Lahir"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Hari ini hari lahir <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Hari lahir tak lama lagi"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 538c7b1..a8b5f08 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ကို ပိတ်ထားသည်"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ကို ဖွင့်ထားသည်"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ဖန်သားပြင် မှတ်တမ်းတင်ရန်"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ဖန်သားပြင် ရိုက်ကူးရန်"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"စတင်ရန်"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ရပ်ရန်"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"စက်၏မိုက်ခရိုဖုန်းကို ပြန်ဖွင့်မလား။"</string>
@@ -750,7 +750,7 @@
<string name="notification_multichannel_desc" msgid="7414593090056236179">"ဤအကြောင်းကြားချက်အုပ်စုကို ဤနေရာတွင် စီစဉ်သတ်မှတ်၍ မရပါ"</string>
<string name="notification_delegate_header" msgid="1264510071031479920">"ပရောက်စီထည့်ထားသော အကြောင်းကြားချက်"</string>
<string name="notification_channel_dialog_title" msgid="6856514143093200019">"<xliff:g id="APP_NAME">%1$s</xliff:g> အကြောင်းကြားချက်များ အားလုံး"</string>
- <string name="see_more_title" msgid="7409317011708185729">"ပိုပြရန်"</string>
+ <string name="see_more_title" msgid="7409317011708185729">"ပိုကြည့်ရန်"</string>
<string name="appops_camera" msgid="5215967620896725715">"ဤအက်ပ်က ကင်မရာကို အသုံးပြုနေသည်။"</string>
<string name="appops_microphone" msgid="8805468338613070149">"ဤအက်ပ်က မိုက်ခရိုဖုန်းကို အသုံးပြုနေသည်။"</string>
<string name="appops_overlay" msgid="4822261562576558490">"ဤအက်ပ်က ဖန်သားမျက်နှာပြင်ပေါ်ရှိ အခြားအက်ပ်များ အပေါ်မှ ထပ်ပြီး ပြသနေပါသည်။"</string>
@@ -1004,7 +1004,7 @@
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"အပလီကေးရှင်းများက သင်၏ <xliff:g id="TYPES_LIST">%s</xliff:g> ကို အသုံးပြုနေသည်။"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"၊ "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" နှင့် "</string>
- <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"<xliff:g id="APPLICATION_NAME">%1$s</xliff:g> က အသုံးပြုထားသည်"</string>
+ <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"<xliff:g id="APPLICATION_NAME">%1$s</xliff:g> က အသုံးပြုနေသည်"</string>
<string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"<xliff:g id="APPLICATION_NAME">%1$s</xliff:g> က မကြာသေးမီက အသုံးပြုထားသည်"</string>
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(လုပ်ငန်းသုံး)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ဖုန်းခေါ်ဆိုမှု"</string>
@@ -1039,7 +1039,7 @@
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ညာဘက်အောက်ခြေသို့ ရွှေ့ရန်"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"အစွန်းသို့ရွှေ့ပြီး ဝှက်ရန်"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"အစွန်းမှရွှေ့ပြီး ပြရန်"</string>
- <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ခလုတ်"</string>
+ <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ပြောင်းရန်"</string>
<string name="quick_controls_title" msgid="7095074621086860062">"ပင်မ ထိန်းချုပ်မှုများ"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ထိန်းချုပ်မှုများထည့်ရန် အက်ပ်ရွေးခြင်း"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
@@ -1075,7 +1075,7 @@
<string name="controls_pin_instructions_retry" msgid="1566667581012131046">"နောက်ပင်နံပါတ်တစ်ခု စမ်းကြည့်ရန်"</string>
<string name="controls_confirmation_confirming" msgid="2596071302617310665">"အတည်ပြုနေသည်…"</string>
<string name="controls_confirmation_message" msgid="7744104992609594859">"<xliff:g id="DEVICE">%s</xliff:g> အတွက် အပြောင်းအလဲကို အတည်ပြုပါ"</string>
- <string name="controls_structure_tooltip" msgid="4355922222944447867">"ပိုမိုကြည့်ရှုရန် ပွတ်ဆွဲပါ"</string>
+ <string name="controls_structure_tooltip" msgid="4355922222944447867">"ပိုကြည့်ရန် ပွတ်ဆွဲပါ"</string>
<string name="controls_seeding_in_progress" msgid="3033855341410264148">"အကြံပြုချက်များ ဖွင့်နေသည်"</string>
<string name="controls_media_title" msgid="1746947284862928133">"မီဒီယာ"</string>
<string name="controls_media_close_session" msgid="1193000643003066508">"ဤမီဒီယာစက်ရှင်ကို ဝှက်မလား။"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"ဦးစားပေး စကားဝိုင်းများ"</string>
<string name="recent_conversations" msgid="8531874684782574622">"မကြာသေးမီက စကားဝိုင်းများ"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"ပြီးခဲ့သော <xliff:g id="DURATION">%1$s</xliff:g> ရက်"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"ပြီးခဲ့သော 1 ပတ်"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"ပြီးခဲ့သော 2 ပတ်"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"ပြီးခဲ့သော 1 ပတ်ကျော်"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"ပြီးခဲ့သော 2 ပတ်ကျော်"</string>
<string name="birthday_status" msgid="2596961629465396761">"မွေးနေ့"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> ၏ မွေးနေ့ ဖြစ်ပါသည်"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"မကြာမီလာမည့် မွေးနေ့"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 3670e51..c7507c9 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC er slått av"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC er slått på"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Skjermopptak"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Skjermopptak"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Start"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stopp"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vil du oppheve blokkeringen av enhetsmikrofonen?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Prioriterte samtaler"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Nylige samtaler"</string>
<string name="okay" msgid="6490552955618608554">"Ok"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"For <xliff:g id="DURATION">%1$s</xliff:g> dager siden"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"For én uke siden"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"For to uker siden"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"For mer enn én uke siden"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"For mer enn to uker siden"</string>
<string name="birthday_status" msgid="2596961629465396761">"Bursdag"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> har bursdag"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Bursdag snart"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 933df50..b649eba 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -136,8 +136,7 @@
<string name="accessibility_camera_button" msgid="2938898391716647247">"क्यामेरा"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"फोन"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"आवाज सहायता"</string>
- <!-- no translation found for accessibility_wallet_button (1458258783460555507) -->
- <skip />
+ <string name="accessibility_wallet_button" msgid="1458258783460555507">"वालेट"</string>
<string name="accessibility_unlock_button" msgid="122785427241471085">"खोल्नुहोस्"</string>
<string name="accessibility_lock_icon" msgid="661492842417875775">"यन्त्र लक गरिएको छ"</string>
<string name="accessibility_waiting_for_fingerprint" msgid="5209142744692162598">"फिंगरप्रिन्ट कुर्दै"</string>
@@ -354,7 +353,7 @@
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"स्थान बन्द छ"</string>
<string name="quick_settings_camera_label" msgid="5612076679385269339">"क्यामेरा प्रयोग गर्ने अनुमति"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"माइक प्रयोग गर्ने अनुमति"</string>
- <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"उपलब्ध"</string>
+ <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"उपलब्ध छ"</string>
<string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"ब्लक गरिएको छ"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"मिडिया उपकरण"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
@@ -409,8 +408,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> प्रयोग गरियो"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> सीमा"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावनी दिँदै"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"कामसम्बन्धी एपहरू"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Night Light"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"सूर्यास्तमा सक्रिय"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"सूर्योदयसम्म"</string>
@@ -425,7 +423,8 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC लाई असक्षम पारिएको छ"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC लाई सक्षम पारिएको छ"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"स्क्रिन रेकर्ड"</string>
+ <!-- no translation found for quick_settings_screen_record_label (8650355346742003694) -->
+ <skip />
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"सुरु गर्नुहोस्"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"रोक्नुहोस्"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"डिभाइसको माइक्रोफोन अनब्लक गर्ने हो?"</string>
@@ -1042,8 +1041,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"किनारामा सार्नुहोस् र नदेखिने पार्नु…"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"किनाराबाट सार्नुहोस् र देखिने पार्नु…"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"टगल गर्नुहोस्"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"घरायसी उपकरणका नियन्त्रणहरू"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"नियन्त्रणहरू थप्नु पर्ने एप छान्नुहोस्"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> वटा नियन्त्र थपियो।</item>
@@ -1057,8 +1055,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"मन पर्ने कुराहरूको सूचीमा नराख्नुहोस्"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"<xliff:g id="NUMBER">%d</xliff:g>ले निर्देश गर्ने ठाउँमा सार्नुहोस्"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"नियन्त्रणहरू"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"आफूले द्रुत सेटिङबाट प्रयोग गर्न चाहेका नियन्त्रणहरू छान्नुहोस्"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"नियन्त्रणहरूको क्रम मिलाउन तिनलाई थिचेर ड्र्याग गर्नुहोस्"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"सबै नियन्त्रणहरू हटाइए"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"परिवर्तनहरू सुरक्षित गरिएका छैनन्"</string>
@@ -1097,8 +1094,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"वस्तुस्थिति लोड गर्न सकिएन"</string>
<string name="controls_error_failed" msgid="960228639198558525">"त्रुटि भयो, फेरि प्रयास गर्नु…"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"कार्य हुँदै छ"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"नयाँ नियन्त्रणहरू हेर्न द्रुत सेटिङ खोल्नुहोस्"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"नियन्त्रण सुविधाहरू थप्नुहोस्"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"नियन्त्रण सुविधाहरू सम्पादन गर्नु…"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"आउटपुट यन्त्रहरू थप्नुहोस्"</string>
@@ -1117,16 +1113,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"महत्त्वपूर्ण वार्तालापहरू"</string>
<string name="recent_conversations" msgid="8531874684782574622">"हालसालैका वार्तालापहरू"</string>
<string name="okay" msgid="6490552955618608554">"ठिक छ"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> दिनअघि"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"१ हप्ताअघि"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"२ हप्ताअघि"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"१ हप्ताभन्दा पहिले"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"२ हप्ताभन्दा पहिले"</string>
<string name="birthday_status" msgid="2596961629465396761">"जन्मदिन"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"आज <xliff:g id="NAME">%1$s</xliff:g> को जन्मदिन हो"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"आगामी जन्मदिन"</string>
@@ -1157,8 +1148,6 @@
<string name="accessibility_authenticate_hint" msgid="798914151813205721">"प्रमाणित गर्नुहोस्"</string>
<string name="accessibility_enter_hint" msgid="2617864063504824834">"डिभाइस हाल्नुहोस्"</string>
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"फिंगरप्रिन्ट प्रयोग गरी खोल्नुहोस्"</string>
- <!-- no translation found for accessibility_fingerprint_bouncer (7189102492498735519) -->
- <skip />
- <!-- no translation found for ongoing_phone_call_content_description (5332334388483099947) -->
- <skip />
+ <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"पुष्टि गर्नु पर्ने हुन्छ। पुष्टि गर्न फिंगरप्रिन्ट सेन्सर छुनुहोस्।"</string>
+ <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"जारी फोन कल"</string>
</resources>
diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml
index f03fe36..e6165ee 100644
--- a/packages/SystemUI/res/values-night/styles.xml
+++ b/packages/SystemUI/res/values-night/styles.xml
@@ -35,6 +35,11 @@
<item name="android:windowLightStatusBar">false</item>
<item name="android:windowLightNavigationBar">false</item>
<item name="android:navigationBarColor">?android:attr/colorBackgroundFloating</item>
+ <item name="android:textColorSecondary">?android:attr/textColorPrimaryInverse</item>
+ </style>
+
+ <style name="Screenshot" parent="@android:style/Theme.DeviceDefault.DayNight">
+ <item name="android:textColorPrimary">?android:attr/textColorPrimaryInverse</item>
</style>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 7b36e62..b0df16e 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC staat uit"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC staat aan"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Schermopname"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Schermopname"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Starten"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stoppen"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Blokkeren van apparaatmicrofoon opheffen?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Prioriteitsgesprekken"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Recente gesprekken"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> dagen geleden"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 week geleden"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 weken geleden"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Meer dan 1 week geleden"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Meer dan 2 weken geleden"</string>
<string name="birthday_status" msgid="2596961629465396761">"Verjaardag"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> is jarig"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Bijna jarig"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 61a082d..9b03506 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -408,8 +408,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> ବ୍ୟବହାର କରାଯାଇଛି"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ସୀମା"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ଚେତାବନୀ"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"ୱାର୍କ ଆପ୍ସ"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"ନାଇଟ୍ ଲାଇଟ୍"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"ସୂର୍ଯ୍ୟାସ୍ତ ବେଳେ ଅନ୍ ହେବ"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"ସୂର୍ଯ୍ୟୋଦୟ ପର୍ଯ୍ୟନ୍ତ"</string>
@@ -424,7 +423,8 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ଅକ୍ଷମ କରାଯାଇଛି"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ସକ୍ଷମ କରାଯାଇଛି"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ସ୍କ୍ରିନ୍ ରେକର୍ଡ"</string>
+ <!-- no translation found for quick_settings_screen_record_label (8650355346742003694) -->
+ <skip />
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ଆରମ୍ଭ କରନ୍ତୁ"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ଡିଭାଇସର ମାଇକ୍ରୋଫୋନକୁ ଅନବ୍ଲକ୍ କରିବେ?"</string>
@@ -1041,8 +1041,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ଧାରକୁ ମୁଭ୍ କରି ଲୁଚାନ୍ତୁ"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ଧାର ବାହାରକୁ ମୁଭ୍ କରି ଦେଖାନ୍ତୁ"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ଟୋଗଲ୍ କରନ୍ତୁ"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"ହୋମ୍ କଣ୍ଟ୍ରୋଲ୍"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଯୋଗ କରିବାକୁ ଆପ୍ ବାଛନ୍ତୁ"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g>ଟି ନିୟନ୍ତ୍ରଣ ଯୋଗ କରାଯାଇଛି।</item>
@@ -1056,8 +1055,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"ନାପସନ୍ଦ କରନ୍ତୁ"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"<xliff:g id="NUMBER">%d</xliff:g> ସ୍ଥିତିକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"କ୍ୱିକ୍ ସେଟିଂସରୁ ଆକ୍ସେସ୍ କରିବାକୁ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ବାଛନ୍ତୁ"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ପୁଣି ସଜାଇବାକୁ ସେଗୁଡ଼ିକୁ ଧରି ଟାଣନ୍ତୁ"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"ସମସ୍ତ ନିୟନ୍ତ୍ରଣ କାଢ଼ି ଦିଆଯାଇଛି"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ପରିବର୍ତ୍ତନଗୁଡ଼ିକ ସେଭ୍ କରାଯାଇନାହିଁ"</string>
@@ -1096,8 +1094,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"ସ୍ଥିତି ଲୋଡ୍ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="controls_error_failed" msgid="960228639198558525">"ତ୍ରୁଟି ହୋଇଛି, ପୁଣି ଚେଷ୍ଟା କର"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"ପ୍ରଗତିରେ ଅଛି"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"ନୂଆ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଦେଖିବାକୁ କ୍ୱିକ୍ ସେଟିଂସ୍ ଖୋଲନ୍ତୁ"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଯୋଗ କରନ୍ତୁ"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଏଡିଟ୍ କରନ୍ତୁ"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"ଆଉଟପୁଟ୍ ଯୋଗ କରନ୍ତୁ"</string>
@@ -1116,16 +1113,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"ପ୍ରାଥମିକତା ଦିଆଯାଇଥିବା ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ"</string>
<string name="recent_conversations" msgid="8531874684782574622">"ବର୍ତ୍ତମାନର ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ"</string>
<string name="okay" msgid="6490552955618608554">"ଠିକ୍ ଅଛି"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> ଦିନ ପୂର୍ବେ"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 ସପ୍ତାହ ପୂର୍ବେ"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 ସପ୍ତାହ ପୂର୍ବେ"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"1 ସପ୍ତାହରୁ ଅଧିକ ଦିନ ଆଗରୁ"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"2 ସପ୍ତାହରୁ ଅଧିକ ଦିନ ଆଗରୁ"</string>
<string name="birthday_status" msgid="2596961629465396761">"ଜନ୍ମଦିନ"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"ଆଜି <xliff:g id="NAME">%1$s</xliff:g>ଙ୍କର ଜନ୍ମଦିନ"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"ଜନ୍ମଦିନ ଶୀଘ୍ର ଆସୁଛି"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 0ac5f08..d9f4f96 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -354,7 +354,7 @@
<string name="quick_settings_camera_label" msgid="5612076679385269339">"ਕੈਮਰਾ ਪਹੁੰਚ"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"ਮਾਈਕ ਪਹੁੰਚ"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"ਉਪਲਬਧ"</string>
- <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"ਪਹੁੰਚ ਬਲਾਕ ਕੀਤੀ ਗਈ"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"ਬਲਾਕ ਕੀਤੀ ਗਈ"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"ਮੀਡੀਆ ਡੀਵਾਈਸ"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ਸਿਰਫ਼ ਸੰਕਟਕਾਲੀਨ ਕਾਲਾਂ"</string>
@@ -408,8 +408,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> ਵਰਤਿਆ"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ਸੀਮਾ"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ਚਿਤਾਵਨੀ"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"ਕੰਮ ਸੰਬੰਧੀ ਐਪਾਂ"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"ਰਾਤ ਦੀ ਰੋਸ਼ਨੀ"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"ਸੂਰਜ ਛਿਪਣ \'ਤੇ ਚਾਲੂ"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"ਸੂਰਜ ਚੜ੍ਹਨ ਤੱਕ"</string>
@@ -424,7 +423,8 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ਨੂੰ ਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ ਕਰੋ"</string>
+ <!-- no translation found for quick_settings_screen_record_label (8650355346742003694) -->
+ <skip />
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ਸ਼ੁਰੂ ਕਰੋ"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ਰੋਕੋ"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ਕੀ ਡੀਵਾਈਸ ਦੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਨੂੰ ਅਣਬਲਾਕ ਕਰਨਾ ਹੈ?"</string>
@@ -1041,8 +1041,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ਕਿਨਾਰੇ ਵਿੱਚ ਲਿਜਾ ਕੇ ਲੁਕਾਓ"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ਕਿਨਾਰੇ ਤੋਂ ਬਾਹਰ ਕੱਢ ਕੇ ਦਿਖਾਓ"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ਟੌਗਲ ਕਰੋ"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"ਹੋਮ ਕੰਟਰੋਲ"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਐਪ ਚੁਣੋ"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ।</item>
@@ -1056,8 +1055,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"ਮਨਪਸੰਦ ਵਿੱਚੋਂ ਹਟਾਓ"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"<xliff:g id="NUMBER">%d</xliff:g> ਸਥਾਨ \'ਤੇ ਲਿਜਾਓ"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"ਕੰਟਰੋਲ"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"ਪਹੁੰਚ ਕਰਨ ਲਈ ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਤੋਂ ਕੰਟਰੋਲ ਚੁਣੋ"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"ਕੰਟਰੋਲਾਂ ਨੂੰ ਮੁੜ-ਵਿਵਸਥਿਤ ਕਰਨ ਲਈ ਫੜ੍ਹ ਕੇ ਘਸੀਟੋ"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"ਸਾਰੇ ਕੰਟਰੋਲ ਹਟਾਏ ਗਏ"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"ਤਬਦੀਲੀਆਂ ਨੂੰ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਗਿਆ"</string>
@@ -1096,8 +1094,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"ਸਥਿਤੀ ਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
<string name="controls_error_failed" msgid="960228639198558525">"ਗੜਬੜ, ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"ਜਾਰੀ ਹੈ"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"ਨਵੇਂ ਕੰਟਰੋਲਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਨੂੰ ਖੋਲ੍ਹੋ"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"ਕੰਟਰੋਲਾਂ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"ਆਊਟਪੁੱਟ ਸ਼ਾਮਲ ਕਰੋ"</string>
@@ -1116,16 +1113,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"ਤਰਜੀਹੀ ਗੱਲਾਂਬਾਤਾਂ"</string>
<string name="recent_conversations" msgid="8531874684782574622">"ਹਾਲੀਆ ਗੱਲਾਂਬਾਤਾਂ"</string>
<string name="okay" msgid="6490552955618608554">"ਠੀਕ ਹੈ"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> ਦਿਨ ਪਹਿਲਾਂ"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 ਹਫ਼ਤਾ ਪਹਿਲਾਂ"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 ਹਫ਼ਤੇ ਪਹਿਲਾਂ"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"1 ਹਫ਼ਤੇ ਤੋਂ ਵੀ ਪਹਿਲਾਂ"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"2 ਹਫ਼ਤੇ ਤੋਂ ਵੀ ਪਹਿਲਾਂ"</string>
<string name="birthday_status" msgid="2596961629465396761">"ਜਨਮਦਿਨ"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"ਅੱਜ <xliff:g id="NAME">%1$s</xliff:g> ਦਾ ਜਨਮਦਿਨ ਹੈ"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"ਜਨਮਦਿਨ ਜਲਦ ਆ ਰਿਹਾ ਹੈ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index c686671..458bf0a 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -412,8 +412,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"Wykorzyst.: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Limit <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Ostrzeżenie: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Aplikacje służbowe"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Podświetlenie nocne"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Włącz o zachodzie"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Do wschodu słońca"</string>
@@ -428,7 +427,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"Komunikacja NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Komunikacja NFC jest wyłączona"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Komunikacja NFC jest włączona"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Nagrywanie ekranu"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Nagrywanie ekranu"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Rozpocznij"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zatrzymaj"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Odblokować mikrofon urządzenia?"</string>
@@ -542,7 +541,7 @@
<string name="quick_settings_disclosure_named_management_vpns" msgid="4046375645500668555">"To urządzenie należy do organizacji <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> i jest połączone z sieciami VPN"</string>
<string name="quick_settings_disclosure_managed_profile_monitoring" msgid="1423899084754272514">"Twoja organizacja może monitorować ruch w sieci w Twoim profilu służbowym"</string>
<string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8321469176706219860">"Organizacja <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> może monitorować ruch w sieci w Twoim profilu służbowym"</string>
- <string name="quick_settings_disclosure_managed_profile_network_activity" msgid="2636594621387832827">"Aktywność w sieci w profilu służbowym widoczna dla administratora IT"</string>
+ <string name="quick_settings_disclosure_managed_profile_network_activity" msgid="2636594621387832827">"Aktywność w sieci w profilu służbowym jest widoczna dla administratora IT"</string>
<string name="quick_settings_disclosure_monitoring" msgid="8548019955631378680">"Sieć może być monitorowana"</string>
<string name="quick_settings_disclosure_vpns" msgid="7213546797022280246">"To urządzenie jest połączone z sieciami VPN"</string>
<string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="8117568745060010789">"Twój profil służbowy jest połączony z siecią <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
@@ -1051,8 +1050,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Przenieś do krawędzi i ukryj"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Przenieś poza krawędź i pokaż"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"przełącz"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"Sterowanie domem"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Wybierz aplikację, do której chcesz dodać elementy sterujące"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="few">Dodano <xliff:g id="NUMBER_1">%s</xliff:g> elementy sterujące</item>
@@ -1068,8 +1066,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"usunąć z ulubionych"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"Przenieś w położenie <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Elementy sterujące"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"Wybierz elementy sterujące dostępne w Szybkich ustawieniach"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Przytrzymaj i przeciągnij, aby przestawić elementy sterujące"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Usunięto wszystkie elementy sterujące"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Zmiany nie zostały zapisane"</string>
@@ -1108,8 +1105,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"Nie udało się wczytać stanu"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Błąd, spróbuj ponownie"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"W toku"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"Otwórz Szybkie ustawienia, by zobaczyć nowe elementy sterujące"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Dodaj elementy sterujące"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Edytuj elementy sterujące"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Dodaj urządzenia wyjściowe"</string>
@@ -1128,16 +1124,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Rozmowy priorytetowe"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Ostatnie rozmowy"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> dni temu"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 tydzień temu"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 tygodnie temu"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Ponad tydzień temu"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Ponad 2 tygodnie temu"</string>
<string name="birthday_status" msgid="2596961629465396761">"Urodziny"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> ma urodziny"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Wkrótce urodziny"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 2f411cf..3e436d7 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -384,7 +384,7 @@
<string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverter cores"</string>
<string name="quick_settings_color_space_label" msgid="537528291083575559">"Modo de correção de cor"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Mais configurações"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Configurações do usuário"</string>
+ <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Config. do usuário"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Concluído"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fechar"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Conectado"</string>
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"A NFC está desativada"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"A NFC está ativada"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Gravação de tela"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Gravação de tela"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Parar"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Desbloquear o microfone do dispositivo?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Conversas prioritárias"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Conversas recentes"</string>
<string name="okay" msgid="6490552955618608554">"Ok"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Há <xliff:g id="DURATION">%1$s</xliff:g> dias"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Há 1 semana"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Há 2 semanas"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Há mais de 1 semana"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Há mais de 2 semanas"</string>
<string name="birthday_status" msgid="2596961629465396761">"Aniversário"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> faz aniversário hoje"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Aniversário chegando"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 5800423..0c6e681 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"O NFC está desativado"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"O NFC está ativado"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Gravação de ecrã"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Gravação do ecrã"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Parar"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Pretende desbloquear o microfone do dispositivo?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Conversas com prioridade"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Conversas recentes"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Há <xliff:g id="DURATION">%1$s</xliff:g> dias"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Há 1 semana"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Há 2 semanas"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Há mais de 1 semana"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Há mais de 2 semanas"</string>
<string name="birthday_status" msgid="2596961629465396761">"Aniversário"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"É o aniversário de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Aniversário em breve"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 2f411cf..3e436d7 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -384,7 +384,7 @@
<string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverter cores"</string>
<string name="quick_settings_color_space_label" msgid="537528291083575559">"Modo de correção de cor"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Mais configurações"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Configurações do usuário"</string>
+ <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Config. do usuário"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Concluído"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fechar"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Conectado"</string>
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"A NFC está desativada"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"A NFC está ativada"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Gravação de tela"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Gravação de tela"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Iniciar"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Parar"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Desbloquear o microfone do dispositivo?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Conversas prioritárias"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Conversas recentes"</string>
<string name="okay" msgid="6490552955618608554">"Ok"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Há <xliff:g id="DURATION">%1$s</xliff:g> dias"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Há 1 semana"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Há 2 semanas"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Há mais de 1 semana"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Há mais de 2 semanas"</string>
<string name="birthday_status" msgid="2596961629465396761">"Aniversário"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> faz aniversário hoje"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Aniversário chegando"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 1a287a0..bbe3cc0 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -425,7 +425,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Serviciul NFC este dezactivat"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Serviciul NFC este activat"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Înregistrarea ecranului"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Înregistrarea ecranului"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Începeți"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Opriți"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblocați microfonul dispozitivului?"</string>
@@ -1045,7 +1045,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mutați în afară și ascundeți"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mutați în afară și afișați"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"Activați / dezactivați"</string>
- <string name="quick_controls_title" msgid="7095074621086860062">"Controalele locuinței"</string>
+ <string name="quick_controls_title" msgid="7095074621086860062">"Comenzi pentru locuință"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Alegeți aplicația pentru a adăuga comenzi"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="few">S-au adăugat <xliff:g id="NUMBER_1">%s</xliff:g> comenzi.</item>
@@ -1118,16 +1118,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Conversații cu prioritate"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Conversații recente"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Acum <xliff:g id="DURATION">%1$s</xliff:g> zile"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Acum o săptămână"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Acum 2 săptămâni"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Cu mai mult de o săptămână în urmă"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Cu mai mult de 2 săptămâni în urmă"</string>
<string name="birthday_status" msgid="2596961629465396761">"Ziua de naștere"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> își serbează astăzi ziua de naștere"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Zi de naștere în curând"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index ac7f6be..80bf12a 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -427,7 +427,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"Модуль NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Модуль NFC отключен"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Модуль NFC включен"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Запись экрана"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Запись видео с экрана"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Начать"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Остановить"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Разблокировать микрофон устройства?"</string>
@@ -1124,16 +1124,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Важные разговоры"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Недавние разговоры"</string>
<string name="okay" msgid="6490552955618608554">"ОК"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> дн. назад"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 неделю назад"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 недели назад"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Более 1 недели назад"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Более 2 недель назад"</string>
<string name="birthday_status" msgid="2596961629465396761">"День рождения"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> празднует день рождения"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Скоро день рождения"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 24b8c03..8912727 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC අබලයි"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC සබලයි"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"තිර පටිගත කිරීම"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"තිර පටිගත කිරීම"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ආරම්භ කරන්න"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"නතර කරන්න"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"උපාංග මයික්රෆෝනය අවහිර කිරීම ඉවත් කරන්නද?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"ප්රමුඛතා සංවාද"</string>
<string name="recent_conversations" msgid="8531874684782574622">"මෑත සංවාද"</string>
<string name="okay" msgid="6490552955618608554">"හරි"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"දින <xliff:g id="DURATION">%1$s</xliff:g>කට පෙර"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"සති 1කට පෙර"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"සති 2කට පෙර"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"සති 1කට වඩා වැඩි කලකට පෙර"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"සති 2කට වඩා වැඩි කලකට පෙර"</string>
<string name="birthday_status" msgid="2596961629465396761">"උපන් දිනය"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"මේ <xliff:g id="NAME">%1$s</xliff:g>ගේ උපන් දිනයයි"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"උපන් දිනය ඉක්මනින්"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 805b4c0..dd36b29 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -427,7 +427,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC je deaktivované"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC je aktivované"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Záznam obrazovky"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Rekordér obrazovky"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Začať"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ukončiť"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Chcete odblokovať mikrofón zariadenia?"</string>
@@ -1124,16 +1124,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Prioritné konverzácie"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Nedávne konverzácie"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Pred <xliff:g id="DURATION">%1$s</xliff:g> dňami"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Pred týždňom"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Pred 2 týždňami"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Pred viac ako týždňom"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Pred viac ako 2 týždňami"</string>
<string name="birthday_status" msgid="2596961629465396761">"Narodeniny"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> má narodeniny"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Blížia sa narodeniny"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 7d31084..8ba5d79 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -412,8 +412,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"Preneseno: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Omejitev: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Opozorilo – <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Delovne aplikacije"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Nočna svetloba"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Ob sončnem zahodu"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Do sončnega vzhoda"</string>
@@ -428,7 +427,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Tehnologija NFC je onemogočena"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Tehnologija NFC je omogočena"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Snemanje zaslona"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Snemanje zaslona"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Začni"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ustavi"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite odblokirati mikrofon v napravi?"</string>
@@ -1051,8 +1050,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Premakni na rob in skrij"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Premakni z roba in pokaži"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"preklop"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"Kontrolniki za dom"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Izberite aplikacijo za dodajanje kontrolnikov"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> kontrolnik dodan.</item>
@@ -1068,8 +1066,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"odstranitev iz priljubljenih"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"Premakni na položaj <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Kontrolniki"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"Izbira kontrolnikov, dostopnih v hitrih nastavitvah"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Držite in povlecite, da prerazporedite kontrolnike."</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Vsi kontrolniki so bili odstranjeni."</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Spremembe niso shranjene"</string>
@@ -1108,8 +1105,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"Stanja ni mogoče naložiti"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Napaka, poskusite znova"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"V teku"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"Za ogled novih kontrolnikov odprite hitre nastavitve."</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrolnike"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Uredi kontrolnike"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Dodajanje izhodov"</string>
@@ -1128,16 +1124,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Prednostni pogovori"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Nedavni pogovori"</string>
<string name="okay" msgid="6490552955618608554">"V redu"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Pred več dnevi (<xliff:g id="DURATION">%1$s</xliff:g>)"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Pred 1 tednom"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Pred 2 tednoma"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Pred več kot 1 tednom"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Pred več kot 2 tednoma"</string>
<string name="birthday_status" msgid="2596961629465396761">"Rojstni dan"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> ima rojstni dan."</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Rojstni dan se bliža"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index c6df5bd..e17d517 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -408,8 +408,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"Të përdorura: <xliff:g id="DATA_USED">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Kufiri: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Paralajmërim për kufirin prej <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Aplikacionet e punës"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Drita e natës"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Në perëndim të diellit"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Deri në lindje të diellit"</string>
@@ -424,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC është çaktivizuar"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC është aktivizuar"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Regjistrimi i ekranit"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Regjistrimi i ekranit"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Nis"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ndalo"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Të zhbllokohet mikrofoni i pajisjes?"</string>
@@ -1041,8 +1040,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Zhvendose te skaji dhe fshihe"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Zhvendose jashtë skajit dhe shfaqe"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aktivizo/çaktivizo"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"Kontrollet e shtëpisë"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Zgjidh aplikacionin për të shtuar kontrollet"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">U shtuan <xliff:g id="NUMBER_1">%s</xliff:g> kontrolle.</item>
@@ -1056,8 +1054,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"ta heqësh nga të preferuarat"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"Zhvendose te pozicioni <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Kontrollet"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"Zgjidh kontrollet për t\'u qasur nga \"Cilësimet e shpejta\""</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Mbaje të shtypur dhe zvarrit për të risistemuar kontrollet"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Të gjitha kontrollet u hoqën"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Ndryshimet nuk u ruajtën"</string>
@@ -1096,8 +1093,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"Statusi nuk mund të ngarkohet"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Gabim, provo sërish"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Në vazhdim"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"Hap \"Cilësimet e shpejta\" për të shikuar kontrollet e reja"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Shto kontrollet"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Modifiko kontrollet"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Shto daljet"</string>
@@ -1116,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Bisedat me përparësi"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Bisedat e fundit"</string>
<string name="okay" msgid="6490552955618608554">"Në rregull"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> ditë më parë"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 javë më parë"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 javë më parë"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Mbi 1 javë më parë"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Mbi 2 javë më parë"</string>
<string name="birthday_status" msgid="2596961629465396761">"Ditëlindja"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> ka ditëlindjen"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Ditëlindje së shpejti"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 0ad1cb1..7ed0cd1 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -425,7 +425,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC је онемогућен"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC је омогућен"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Снимак екрана"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Снимање екрана"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Почните"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Зауставите"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Желите да одблокирате микрофон уређаја?"</string>
@@ -1118,16 +1118,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Приоритетне конверзације"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Недавне конверзације"</string>
<string name="okay" msgid="6490552955618608554">"Важи"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Пре <xliff:g id="DURATION">%1$s</xliff:g> дана"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Пре недељу дана"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Пре 2 недеље"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Пре више од недељу дана"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Пре више од 2 недеље"</string>
<string name="birthday_status" msgid="2596961629465396761">"Рођендан"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> данас слави рођендан"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Рођендан је ускоро"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index ffff14e..e7f6fe5 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -378,7 +378,7 @@
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Namnlös enhet"</string>
<string name="quick_settings_cast_device_default_description" msgid="2580520859212250265">"Redo att casta"</string>
<string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Inga tillgängliga enheter"</string>
- <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Inte ansluten till wifi"</string>
+ <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Ej ansluten till wifi"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ljusstyrka"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="2325362583903258677">"AUTO"</string>
<string name="quick_settings_inversion_label" msgid="5078769633069667698">"Invertera färger"</string>
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC är inaktiverat"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC är aktiverat"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Skärminspelning"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Skärminspelning"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Starta"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stoppa"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vill du återaktivera enhetens mikrofon?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Prioriterade konversationer"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Senaste konversationerna"</string>
<string name="okay" msgid="6490552955618608554">"Okej"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> dagar sedan"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 vecka sedan"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 veckor sedan"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Över 1 vecka sedan"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Över 2 veckor sedan"</string>
<string name="birthday_status" msgid="2596961629465396761">"Födelsedag"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> fyller år"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Födelsedag inom kort"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index c33d8cb..bbc7a75 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC imezimwa"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC imewashwa"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Rekodi ya Skrini"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Rekodi ya skrini"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Anza kurekodi"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Acha kurekodi"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Ungependa kuondoa kizuizi kwenye maikrofoni ya kifaa?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Mazungumzo yenye kipaumbele"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Mazungumzo ya hivi majuzi"</string>
<string name="okay" msgid="6490552955618608554">"Sawa"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"Siku <xliff:g id="DURATION">%1$s</xliff:g> zilizopita"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"Wiki moja iliyopita"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"Wiki mbili zilizopita"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Zaidi ya wiki moja iliyopita"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Zaidi ya wiki mbili zilizopita"</string>
<string name="birthday_status" msgid="2596961629465396761">"Siku ya kuzaliwa"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Ni siku ya kuzaliwa ya <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Siku ya kuzaliwa inakaribia"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 3bcd095..8c2649e 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC முடக்கப்பட்டது"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC இயக்கப்பட்டது"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"ஸ்கிரீன் ரெக்கார்டு"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"ஸ்கிரீன் ரெக்கார்டு"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"தொடங்கு"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"நிறுத்து"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"சாதனத்தின் மைக்ரோஃபோனுக்கான தடுப்பை நீக்கவா?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"முன்னுரிமை அளிக்கப்பட்ட உரையாடல்கள்"</string>
<string name="recent_conversations" msgid="8531874684782574622">"சமீபத்திய உரையாடல்கள்"</string>
<string name="okay" msgid="6490552955618608554">"சரி"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> நாட்களுக்கு முன்பு"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 வாரத்திற்கு முன்பு"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 வாரங்களுக்கு முன்பு"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"1 வாரத்திற்கும் முன்பு"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"2 வாரங்களுக்கும் முன்பு"</string>
<string name="birthday_status" msgid="2596961629465396761">"பிறந்தநாள்"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> இன் பிறந்தநாள்"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"விரைவில் பிறந்தநாள்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 4801435..407ab00 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -408,8 +408,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> వినియోగించబడింది"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> పరిమితి"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> హెచ్చరిక"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"వర్క్ యాప్లు"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"రాత్రి కాంతి"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"సూర్యాస్తమయానికి"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"సూర్యోదయం వరకు"</string>
@@ -424,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC నిలిపివేయబడింది"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ప్రారంభించబడింది"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"స్క్రీన్ రికార్డ్"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"స్క్రీన్ రికార్డ్"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"ప్రారంభించు"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"ఆపు"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"పరికరం మైక్రోఫోన్ను అన్బ్లాక్ చేయమంటారా?"</string>
@@ -1005,7 +1004,7 @@
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"అప్లికేషన్లు మీ <xliff:g id="TYPES_LIST">%s</xliff:g>ని ఉపయోగిస్తున్నాయి."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" మరియు "</string>
- <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"<xliff:g id="APPLICATION_NAME">%1$s</xliff:g> ద్వారా ఉపయోగించబడింది"</string>
+ <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"<xliff:g id="APPLICATION_NAME">%1$s</xliff:g> ద్వారా ఉపయోగించబడుతోంది"</string>
<string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"ఇటీవల <xliff:g id="APPLICATION_NAME">%1$s</xliff:g> ద్వారా ఉపయోగించారు"</string>
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ఆఫీస్)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ఫోన్ కాల్"</string>
@@ -1041,8 +1040,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"అంచుకు తరలించి దాచండి"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"అంచుని తరలించి చూపించు"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"టోగుల్ చేయి"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"హోమ్ కంట్రోల్స్"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"కంట్రోల్స్ను యాడ్ చేయడానికి యాప్ను ఎంచుకోండి"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> కంట్రోల్లు యాడ్ అయ్యాయి.</item>
@@ -1056,8 +1054,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"ఇష్టమైనదిగా పెట్టిన గుర్తును తీసివేయి"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"<xliff:g id="NUMBER">%d</xliff:g> పొజిషన్కు తరలించండి"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"నియంత్రణలు"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"త్వరిత సెట్టింగ్ల నుండి యాక్సెస్ చేయడానికి కంట్రోల్స్ను ఎంచుకోండి"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"కంట్రోల్స్ క్రమం మార్చడానికి దేనినైనా పట్టుకుని, లాగి వదిలేయండి"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"అన్ని కంట్రోల్స్ తీసివేయబడ్డాయి"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"మార్పులు సేవ్ చేయబడలేదు"</string>
@@ -1096,8 +1093,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"స్థితిని లోడ్ చేయడం సాధ్యపడదు"</string>
<string name="controls_error_failed" msgid="960228639198558525">"ఎర్రర్, మళ్లీ ప్రయత్నించండి"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"పురోగతిలో ఉంది"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"కొత్త కంట్రోల్స్ను చూడటానికి త్వరిత సెట్టింగ్లను తెరవండి"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"కంట్రోల్స్ను జోడించండి"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"కంట్రోల్స్ను ఎడిట్ చేయండి"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"అవుట్పుట్లను జోడించండి"</string>
@@ -1116,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"ప్రాధాన్య సంభాషణలు"</string>
<string name="recent_conversations" msgid="8531874684782574622">"ఇటీవలి సంభాషణలు"</string>
<string name="okay" msgid="6490552955618608554">"సరే"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> రోజుల క్రితం"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 వారం క్రితం"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 వారాల క్రితం"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"1 వారం క్రితం పైగా"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"2 వారాల క్రితం పైగా"</string>
<string name="birthday_status" msgid="2596961629465396761">"పుట్టినరోజు"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"ఈ రోజు <xliff:g id="NAME">%1$s</xliff:g> పుట్టిన రోజు"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"పుట్టినరోజు వస్తోంది"</string>
diff --git a/packages/SystemUI/res/values-television/styles.xml b/packages/SystemUI/res/values-television/styles.xml
index 5772f9d..00217fb 100644
--- a/packages/SystemUI/res/values-television/styles.xml
+++ b/packages/SystemUI/res/values-television/styles.xml
@@ -25,6 +25,7 @@
<style name="volume_dialog_theme" parent="Theme.SystemUI">
<item name="android:colorAccent">@color/tv_volume_dialog_accent</item>
+ <item name="android:textColorPrimaryInverse">@color/tv_volume_dialog_accent</item>
<item name="android:dialogCornerRadius">@dimen/volume_dialog_panel_width_half</item>
</style>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 7a2264c..1536d9a 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC ถูกปิดใช้งาน"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"เปิดใช้งาน NFC แล้ว"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"บันทึกหน้าจอ"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"บันทึกหน้าจอ"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"เริ่ม"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"หยุด"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"เลิกบล็อกไมโครโฟนของอุปกรณ์ใช่ไหม"</string>
@@ -859,7 +859,7 @@
<string name="accessibility_data_saver_off" msgid="58339669022107171">"โปรแกรมประหยัดอินเทอร์เน็ตปิดอยู่"</string>
<string name="switch_bar_on" msgid="1770868129120096114">"เปิด"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"ปิด"</string>
- <string name="tile_unavailable" msgid="3095879009136616920">"ไม่มี"</string>
+ <string name="tile_unavailable" msgid="3095879009136616920">"ไม่พร้อมใช้งาน"</string>
<string name="tile_disabled" msgid="373212051546573069">"ปิดใช้"</string>
<string name="nav_bar" msgid="4642708685386136807">"แถบนำทาง"</string>
<string name="nav_bar_layout" msgid="4716392484772899544">"การจัดวาง"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"การสนทนาสำคัญ"</string>
<string name="recent_conversations" msgid="8531874684782574622">"การสนทนาล่าสุด"</string>
<string name="okay" msgid="6490552955618608554">"ตกลง"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> วันที่ผ่านมา"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 สัปดาห์ที่ผ่านมา"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 สัปดาห์ที่ผ่านมา"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"มากกว่า 1 สัปดาห์ที่ผ่านมา"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"มากกว่า 2 สัปดาห์ที่ผ่านมา"</string>
<string name="birthday_status" msgid="2596961629465396761">"วันเกิด"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"วันนี้เป็นวันเกิดของ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"ใกล้ถึงวันเกิดแล้ว"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 64bf1fc..0ece0cb 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"Naka-disable ang NFC"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"Naka-enable ang NFC"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Pag-record ng Screen"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Pag-record ng screen"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Magsimula"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Ihinto"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"I-unblock ang mikropono ng device?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Mga priyoridad na pag-uusap"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Mga kamakailang pag-uusap"</string>
<string name="okay" msgid="6490552955618608554">"Okay"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> (na) araw ang nakalipas"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 linggo na"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 linggo na"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Mahigit 1 linggo na"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Mahigit 2 linggo na"</string>
<string name="birthday_status" msgid="2596961629465396761">"Kaarawan"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Kaarawan ni <xliff:g id="NAME">%1$s</xliff:g> ngayon"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Kaarawang paparating"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 4ed0f5e..c0702e9 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC devre dışı"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC etkin"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ekran Kaydı"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Ekran kaydı"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Başlat"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Durdur"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Cihaz mikrofonunun engellemesi kaldırılsın mı?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Öncelikli görüşmeler"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Son görüşmeler"</string>
<string name="okay" msgid="6490552955618608554">"Tamam"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> gün önce"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 hafta önce"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 hafta önce"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"1 haftadan uzun süre önce"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"2 haftadan uzun süre önce"</string>
<string name="birthday_status" msgid="2596961629465396761">"Doğum günü"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Bugün <xliff:g id="NAME">%1$s</xliff:g> adlı kişinin doğum günü"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Yaklaşan doğum günü"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 15a592e..2b6183d 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -427,7 +427,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC вимкнено"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC ввімкнено"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Запис екрана"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Запис відео з екрана"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Почати"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Зупинити"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Надати доступ до мікрофона?"</string>
@@ -1124,16 +1124,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Важливі розмови"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Нещодавні розмови"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> дн. тому"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 тиждень тому"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 тижні тому"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Більше ніж 1 тиждень тому"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Більше ніж 2 тижні тому"</string>
<string name="birthday_status" msgid="2596961629465396761">"День народження"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Сьогодні <xliff:g id="NAME">%1$s</xliff:g> святкує День народження"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Скоро іменини"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 05cd034..f27f813 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -408,8 +408,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"<xliff:g id="DATA_USED">%s</xliff:g> استعمال کردہ"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"<xliff:g id="DATA_LIMIT">%s</xliff:g> حد"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"<xliff:g id="DATA_LIMIT">%s</xliff:g> وارننگ"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"دفتری ایپس"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"نائٹ لائٹ"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"غروب آفتاب کے وقت آن ہوگی"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"طلوع آفتاب تک"</string>
@@ -424,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC غیر فعال ہے"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC فعال ہے"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"اسکرین ریکارڈر کریں"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"اسکرین ریکارڈ"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"شروع کریں"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"روکیں"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"آلے کا مائیکروفون غیر مسدود کریں؟"</string>
@@ -1041,8 +1040,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"EDGE پر لے جائیں اور چھپائیں"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"EDGE اور شو سے باہر منتقل کریں"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ٹوگل کریں"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"ہوم کنٹرولز"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"کنٹرولز شامل کرنے کے لیے ایپ منتخب کریں"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> کنٹرولز شامل کر دیے گئے۔</item>
@@ -1056,8 +1054,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"پسندیدگی ختم کریں"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"پوزیشن <xliff:g id="NUMBER">%d</xliff:g> میں منتقل کریں"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"کنٹرولز"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"فوری ترتیبات سے رسائی کے لیے کنٹرولز منتخب کریں"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"کنٹرولز کو دوبارہ ترتیب دینے کے ليے پکڑیں اور گھسیٹیں"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"سبھی کنٹرولز ہٹا دیے گئے"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"تبدیلیاں محفوظ نہیں ہوئیں"</string>
@@ -1096,8 +1093,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"صورتحال لوڈ نہیں ہو سکتی"</string>
<string name="controls_error_failed" msgid="960228639198558525">"خرابی، دوبارہ کوشش کریں"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"پیشرفت میں"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"نئے کنٹرولز دیکھنے کے لیے فوری ترتیبات کھولیں"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"کنٹرولز شامل کریں"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"کنٹرولز میں ترمیم کریں"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"آؤٹ پٹس شامل کریں"</string>
@@ -1116,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"ترجیحی گفتگوئیں"</string>
<string name="recent_conversations" msgid="8531874684782574622">"حالیہ گفتگوئیں"</string>
<string name="okay" msgid="6490552955618608554">"ٹھیک ہے"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> دن پہلے"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 ہفتہ پہلے"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 ہفتے پہلے"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"1 ہفتہ سے بھی پہلے"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"2 ہفتے سے بھی پہلے"</string>
<string name="birthday_status" msgid="2596961629465396761">"سالگرہ"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"<xliff:g id="NAME">%1$s</xliff:g> کی یوم پیدائش ہے"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"سالگرہ قریب ہے"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index fc98d05..6a9d46f 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC o‘chiq"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC yoniq"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ekranni yozib olish"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Ekranni yozib olish"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Boshlash"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Toʻxtatish"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Qurilma mikrofoni blokdan chiqarilsinmi?"</string>
@@ -1004,8 +1004,8 @@
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Ilovalarda ishlatilmoqda: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" va "</string>
- <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"<xliff:g id="APPLICATION_NAME">%1$s</xliff:g> foydalanadi"</string>
- <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Yaqinda <xliff:g id="APPLICATION_NAME">%1$s</xliff:g> ishlatgan"</string>
+ <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"<xliff:g id="APPLICATION_NAME">%1$s</xliff:g> ishlatmoqda"</string>
+ <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Yaqinda <xliff:g id="APPLICATION_NAME">%1$s</xliff:g> ishlatdi"</string>
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ish)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefon chaqiruvi"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> orqali)"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Muhim suhbatlar"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Oxirgi suhbatlar"</string>
<string name="okay" msgid="6490552955618608554">"OK"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> kun oldin"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 hafta oldin"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 hafta oldin"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"1 haftadan oldinroq"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"2 haftadan oldinroq"</string>
<string name="birthday_status" msgid="2596961629465396761">"Tavallud kuni"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Bugun <xliff:g id="NAME">%1$s</xliff:g>ning tugʻilgan kuni!"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Yaqinda tavallud kun"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 25f156e..86ee67a 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -351,8 +351,8 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Phương thức nhập"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Vị trí"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Tắt vị trí"</string>
- <string name="quick_settings_camera_label" msgid="5612076679385269339">"Quyền truy cập vào máy ảnh"</string>
- <string name="quick_settings_mic_label" msgid="8392773746295266375">"Quyền truy cập vào micrô"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Truy cập máy ảnh"</string>
+ <string name="quick_settings_mic_label" msgid="8392773746295266375">"Truy cập micrô"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Được phép"</string>
<string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bị chặn"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"Thiết bị phương tiện"</string>
@@ -408,8 +408,7 @@
<string name="quick_settings_cellular_detail_data_used" msgid="6798849610647988987">"Đã sử dụng <xliff:g id="DATA_USED">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_limit" msgid="1791389609409211628">"Giới hạn <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_cellular_detail_data_warning" msgid="7957253810481086455">"Cảnh báo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
- <!-- no translation found for quick_settings_work_mode_label (6440531507319809121) -->
- <skip />
+ <string name="quick_settings_work_mode_label" msgid="6440531507319809121">"Ứng dụng công việc"</string>
<string name="quick_settings_night_display_label" msgid="8180030659141778180">"Ánh sáng đêm"</string>
<string name="quick_settings_night_secondary_label_on_at_sunset" msgid="3358706312129866626">"Bật khi trời tối"</string>
<string name="quick_settings_night_secondary_label_until_sunrise" msgid="4063448287758262485">"Cho đến khi trời sáng"</string>
@@ -424,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC đã được tắt"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC đã được bật"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Ghi lại nội dung trên màn hình"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Ghi màn hình"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Bắt đầu"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Dừng"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Bỏ chặn micrô của thiết bị?"</string>
@@ -1006,7 +1005,7 @@
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" và "</string>
<string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"<xliff:g id="APPLICATION_NAME">%1$s</xliff:g> đang dùng"</string>
- <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Được <xliff:g id="APPLICATION_NAME">%1$s</xliff:g> dùng gần đây"</string>
+ <string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"<xliff:g id="APPLICATION_NAME">%1$s</xliff:g> đã dùng gần đây"</string>
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(công việc)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Cuộc gọi điện thoại"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(thông qua <xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>)"</string>
@@ -1041,8 +1040,7 @@
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Chuyển đến cạnh và ẩn"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Chuyển ra xa cạnh và hiển thị"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"bật/tắt"</string>
- <!-- no translation found for quick_controls_title (7095074621086860062) -->
- <skip />
+ <string name="quick_controls_title" msgid="7095074621086860062">"Điều khiển nhà"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Chọn ứng dụng để thêm các tùy chọn điều khiển"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
<item quantity="other">Đã thêm <xliff:g id="NUMBER_1">%s</xliff:g> tùy chọn điều khiển.</item>
@@ -1056,8 +1054,7 @@
<string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"bỏ yêu thích"</string>
<string name="accessibility_control_move" msgid="8980344493796647792">"Di chuyển tới vị trí số <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="controls_favorite_default_title" msgid="967742178688938137">"Các tùy chọn điều khiển"</string>
- <!-- no translation found for controls_favorite_subtitle (6481675111056961083) -->
- <skip />
+ <string name="controls_favorite_subtitle" msgid="6481675111056961083">"Chọn các chế độ điều khiển sẽ truy cập từ trình đơn Cài đặt nhanh"</string>
<string name="controls_favorite_rearrange" msgid="5616952398043063519">"Giữ và kéo để sắp xếp lại các tùy chọn điều khiển"</string>
<string name="controls_favorite_removed" msgid="5276978408529217272">"Đã xóa tất cả tùy chọn điều khiển"</string>
<string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Chưa lưu các thay đổi"</string>
@@ -1096,8 +1093,7 @@
<string name="controls_error_generic" msgid="352500456918362905">"Không tải được trạng thái"</string>
<string name="controls_error_failed" msgid="960228639198558525">"Lỗi, hãy thử lại"</string>
<string name="controls_in_progress" msgid="4421080500238215939">"Đang thực hiện"</string>
- <!-- no translation found for controls_added_tooltip (5866098408470111984) -->
- <skip />
+ <string name="controls_added_tooltip" msgid="5866098408470111984">"Mở trình đơn Cài đặt nhanh để xem các chế độ điều khiển mới"</string>
<string name="controls_menu_add" msgid="4447246119229920050">"Thêm các tùy chọn điều khiển"</string>
<string name="controls_menu_edit" msgid="890623986951347062">"Chỉnh sửa tùy chọn điều khiển"</string>
<string name="media_output_dialog_add_output" msgid="5642703238877329518">"Thêm thiết bị đầu ra"</string>
@@ -1116,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Cuộc trò chuyện ưu tiên"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Cuộc trò chuyện gần đây"</string>
<string name="okay" msgid="6490552955618608554">"Ok"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> ngày trước"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 tuần trước"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 tuần trước"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Hơn 1 tuần trước"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Hơn 2 tuần trước"</string>
<string name="birthday_status" msgid="2596961629465396761">"Sinh nhật"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Hôm nay là sinh nhật của <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Sắp đến sinh nhật"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index d6d7b3d..928510b 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 已停用"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 已启用"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"屏幕录制"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"屏幕录制"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"开始"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"停止"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要取消禁用设备麦克风吗?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"优先对话"</string>
<string name="recent_conversations" msgid="8531874684782574622">"近期对话"</string>
<string name="okay" msgid="6490552955618608554">"确定"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> 天前"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 周前"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 周前"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"超过 1 周前"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"超过 2 周前"</string>
<string name="birthday_status" msgid="2596961629465396761">"生日"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"今天是<xliff:g id="NAME">%1$s</xliff:g>的生日"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"生日快到了"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index fe846c5..a80896f 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -354,7 +354,7 @@
<string name="quick_settings_camera_label" msgid="5612076679385269339">"相機存取權"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"麥克風存取權"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"可用"</string>
- <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"已封鎖"</string>
+ <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"已禁用"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"媒體裝置"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"只可撥打緊急電話"</string>
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 已停用"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 已啟用"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"畫面錄影"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"螢幕錄影"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"開始"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"停"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要解除封鎖裝置麥克風嗎?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"優先對話"</string>
<string name="recent_conversations" msgid="8531874684782574622">"最近的對話"</string>
<string name="okay" msgid="6490552955618608554">"確定"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> 天前"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 週前"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 週前"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"超過 1 週前"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"超過 2 週前"</string>
<string name="birthday_status" msgid="2596961629465396761">"生日之星"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"今天是<xliff:g id="NAME">%1$s</xliff:g>的生日"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"即將生日"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index b640fc5..7584d23 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC 已停用"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC 已啟用"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"螢幕畫面錄製"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"螢幕錄影"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"開始"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"停止"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"要將裝置麥克風解除封鎖嗎?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"優先對話"</string>
<string name="recent_conversations" msgid="8531874684782574622">"最近的對話"</string>
<string name="okay" msgid="6490552955618608554">"確定"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"<xliff:g id="DURATION">%1$s</xliff:g> 天前"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"1 週前"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"2 週前"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"超過 1 週"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"超過 2 週"</string>
<string name="birthday_status" msgid="2596961629465396761">"本日壽星"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"今天是<xliff:g id="NAME">%1$s</xliff:g>的生日"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"生日快到了"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index baaf83c..021afbb 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -423,7 +423,7 @@
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"I-NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"I-NFC ikhutshaziwe"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"I-NFC inikwe amandla"</string>
- <string name="quick_settings_screen_record_label" msgid="1594046461509776676">"Irekhodi lesikrini"</string>
+ <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Irekhodi lesikrini"</string>
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Qala"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Misa"</string>
<string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vulela imakrofoni yedivayisi?"</string>
@@ -1112,16 +1112,11 @@
<string name="priority_conversations" msgid="3967482288896653039">"Izingxoxo ezibalulekile"</string>
<string name="recent_conversations" msgid="8531874684782574622">"Izingxoxo zakamuva"</string>
<string name="okay" msgid="6490552955618608554">"Kulungile"</string>
- <!-- no translation found for days_timestamp (5821854736213214331) -->
- <skip />
- <!-- no translation found for one_week_timestamp (4925600765473875590) -->
- <skip />
- <!-- no translation found for two_weeks_timestamp (9111801081871962155) -->
- <skip />
- <!-- no translation found for over_one_week_timestamp (3770560704420807142) -->
- <skip />
- <!-- no translation found for over_two_weeks_timestamp (6300507859007874050) -->
- <skip />
+ <string name="days_timestamp" msgid="5821854736213214331">"izinsuku ezedlule <xliff:g id="DURATION">%1$s</xliff:g>"</string>
+ <string name="one_week_timestamp" msgid="4925600765473875590">"iviki eledlule 1"</string>
+ <string name="two_weeks_timestamp" msgid="9111801081871962155">"amaviki adlule 2"</string>
+ <string name="over_one_week_timestamp" msgid="3770560704420807142">"Ngaphezu kweviki eli-1 eledlule"</string>
+ <string name="over_two_weeks_timestamp" msgid="6300507859007874050">"Ngaphezu kwamaviki ama-2 adlule"</string>
<string name="birthday_status" msgid="2596961629465396761">"Usuku lokuzalwa"</string>
<string name="birthday_status_content_description" msgid="682836371128282925">"Wusuku lokuzalwa luka-<xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="upcoming_birthday_status" msgid="2005452239256870351">"Usuku lokuzalwa maduze"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 5559600..862d59e9 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -196,13 +196,7 @@
<color name="default_invocation_lights_color">#ffffffff</color> <!-- white -->
<!-- Global screenshot actions -->
- <color name="global_screenshot_button_background">#F5F5F5</color>
- <color name="global_screenshot_button_text">#000000</color>
- <color name="global_screenshot_button_border">@color/GM2_grey_300</color>
<color name="global_screenshot_button_ripple">#1f000000</color>
- <color name="global_screenshot_button_icon">@color/GM2_blue_500</color>
- <color name="global_screenshot_dismiss_background">#FFFFFF</color>
- <color name="global_screenshot_dismiss_foreground">@color/GM2_grey_500</color>
<color name="global_screenshot_background_protection_start">#40000000</color> <!-- 25% black -->
<!-- Long screenshot UI -->
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d4dbcf9..be9065b 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -352,7 +352,7 @@
<!-- Nav bar button default ordering/layout -->
<string name="config_navBarLayout" translatable="false">left[.5W],back[1WC];home;recent[1WC],right[.5W]</string>
<string name="config_navBarLayoutQuickstep" translatable="false">back[1.7WC];home;contextual[1.7WC]</string>
- <string name="config_navBarLayoutHandle" translatable="false">back[40AC];home_handle;ime_switcher[40AC]</string>
+ <string name="config_navBarLayoutHandle" translatable="false">back[70AC];home_handle;ime_switcher[70AC]</string>
<bool name="quick_settings_show_full_alarm">false</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ad84fdd..5c1e935 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -330,26 +330,30 @@
<dimen name="global_screenshot_bg_protection_height">400dp</dimen>
<dimen name="global_screenshot_x_scale">80dp</dimen>
<dimen name="screenshot_bg_protection_height">242dp</dimen>
- <dimen name="screenshot_preview_elevation">6dp</dimen>
- <dimen name="screenshot_offset_y">32dp</dimen>
+ <dimen name="screenshot_preview_elevation">4dp</dimen>
+ <dimen name="screenshot_offset_y">24dp</dimen>
<dimen name="screenshot_offset_x">16dp</dimen>
<dimen name="screenshot_dismiss_button_tappable_size">48dp</dimen>
<dimen name="screenshot_dismiss_button_margin">8dp</dimen>
<dimen name="screenshot_action_container_offset_y">16dp</dimen>
- <dimen name="screenshot_action_container_corner_radius">10dp</dimen>
- <dimen name="screenshot_action_container_padding_vertical">6dp</dimen>
+ <dimen name="screenshot_action_container_corner_radius">18dp</dimen>
+ <dimen name="screenshot_action_container_padding_vertical">4dp</dimen>
<dimen name="screenshot_action_container_margin_horizontal">8dp</dimen>
<dimen name="screenshot_action_container_padding_right">8dp</dimen>
<!-- Radius of the chip background on global screenshot actions -->
- <dimen name="screenshot_button_corner_radius">20dp</dimen>
+ <dimen name="screenshot_button_corner_radius">8dp</dimen>
+ <!-- Margin between successive chips -->
<dimen name="screenshot_action_chip_margin_start">8dp</dimen>
- <dimen name="screenshot_action_chip_margin_vertical">10dp</dimen>
- <dimen name="screenshot_action_chip_padding_vertical">7dp</dimen>
+ <!-- Padding to make tappable chip height 48dp (18+11+11+4+4) -->
+ <dimen name="screenshot_action_chip_margin_vertical">4dp</dimen>
+ <dimen name="screenshot_action_chip_padding_vertical">11dp</dimen>
<dimen name="screenshot_action_chip_icon_size">18dp</dimen>
- <dimen name="screenshot_action_chip_padding_start">8dp</dimen>
- <!-- Padding between icon and text -->
- <dimen name="screenshot_action_chip_padding_middle">8dp</dimen>
- <dimen name="screenshot_action_chip_padding_end">16dp</dimen>
+ <!-- Padding on each side of the icon for icon-only chips -->
+ <dimen name="screenshot_action_chip_icon_only_padding_horizontal">14dp</dimen>
+ <!-- Padding at the edges of the chip for icon-and-text chips -->
+ <dimen name="screenshot_action_chip_padding_horizontal">12dp</dimen>
+ <!-- Spacing between chip icon and chip text -->
+ <dimen name="screenshot_action_chip_spacing">8dp</dimen>
<dimen name="screenshot_action_chip_text_size">14sp</dimen>
<dimen name="screenshot_dismissal_height_delta">80dp</dimen>
<dimen name="screenshot_crop_handle_thickness">3dp</dimen>
@@ -468,6 +472,8 @@
<dimen name="volume_dialog_panel_transparent_padding">20dp</dimen>
+ <dimen name="volume_dialog_ringer_rows_padding">7dp</dimen>
+
<dimen name="volume_dialog_stream_padding">12dp</dimen>
<dimen name="volume_dialog_panel_width">56dp</dimen>
@@ -1239,6 +1245,11 @@
<dimen name="ongoing_appops_chip_icon_size">16dp</dimen>
<!-- Radius of Ongoing App Ops chip corners -->
<dimen name="ongoing_appops_chip_bg_corner_radius">28dp</dimen>
+ <!-- One or two privacy items -->
+ <dimen name="ongoing_appops_chip_min_width">56dp</dimen>
+ <!-- Three privacy items. This value must not be exceeded -->
+ <dimen name="ongoing_appops_chip_max_width">76dp</dimen>
+ <dimen name="ongoing_appops_dot_diameter">6dp</dimen>
<dimen name="ongoing_appops_dialog_side_margins">@dimen/notification_shade_content_margin_horizontal</dimen>
@@ -1407,10 +1418,6 @@
<dimen name="media_output_dialog_icon_corner_radius">16dp</dimen>
<dimen name="media_output_dialog_title_anim_y_delta">12.5dp</dimen>
- <!-- Delay after which the media will start transitioning to the full shade on
- the lockscreen -->
- <dimen name="lockscreen_shade_media_transition_start_delay">40dp</dimen>
-
<!-- Distance that the full shade transition takes in order for qs to fully transition to the
shade -->
<dimen name="lockscreen_shade_qs_transition_distance">200dp</dimen>
@@ -1419,13 +1426,16 @@
the shade (in alpha) -->
<dimen name="lockscreen_shade_scrim_transition_distance">80dp</dimen>
- <!-- Extra inset for the notifications when accounting for media during the lockscreen to
- shade transition to compensate for the disappearing media -->
- <dimen name="lockscreen_shade_transition_extra_media_inset">-48dp</dimen>
+ <!-- Distance that the full shade transition takes in order for media to fully transition to
+ the shade -->
+ <dimen name="lockscreen_shade_media_transition_distance">140dp</dimen>
<!-- Maximum overshoot for the topPadding of notifications when transitioning to the full
shade -->
- <dimen name="lockscreen_shade_max_top_overshoot">32dp</dimen>
+ <dimen name="lockscreen_shade_notification_movement">24dp</dimen>
+
+ <!-- Maximum overshoot for the pulse expansion -->
+ <dimen name="pulse_expansion_max_top_overshoot">16dp</dimen>
<dimen name="people_space_widget_radius">28dp</dimen>
<dimen name="people_space_image_radius">20dp</dimen>
diff --git a/packages/SystemUI/res/values/flags.xml b/packages/SystemUI/res/values/flags.xml
index 6393147..f4086ed 100644
--- a/packages/SystemUI/res/values/flags.xml
+++ b/packages/SystemUI/res/values/flags.xml
@@ -38,8 +38,6 @@
<!-- The new animations to/from lockscreen and AOD! -->
<bool name="flag_lockscreen_animations">false</bool>
- <bool name="flag_toast_style">false</bool>
-
<bool name="flag_pm_lite">false</bool>
<bool name="flag_alarm_tile">false</bool>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index bdc7bdb..f4f881f 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -100,6 +100,7 @@
<!-- For notification icons for which targetSdk < L, this caches whether the icon is grayscale -->
<item type="id" name="icon_is_grayscale" />
<item type="id" name="image_icon_tag" />
+ <item type="id" name="align_transform_end_tag" />
<item type="id" name="contains_transformed_view" />
<item type="id" name="is_clicked_heads_up_tag" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 01d0dde..db3fae6 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1062,6 +1062,9 @@
<!-- Shows to explain the double tap interaction with notifications: After tapping a notification on Keyguard, this will explain users to tap again to launch a notification. [CHAR LIMIT=60] -->
<string name="notification_tap_again">Tap again to open</string>
+ <!-- Asks for a second tap as confirmation on an item that normally requires one tap. [CHAR LIMIT=60] -->
+ <string name="tap_again">Tap again</string>
+
<!-- Message shown when lock screen is tapped or face authentication fails. [CHAR LIMIT=60] -->
<string name="keyguard_unlock">Swipe up to open</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index ecc60ec..aadcaba 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -651,6 +651,8 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:backgroundTint">@color/media_player_outline_button_bg</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+ <item name="android:layout_gravity">center</item>
+ <item name="android:singleLine">true</item>
</style>
<style name="MediaPlayer.SolidButton">
@@ -700,6 +702,8 @@
<item name="android:windowActivityTransitions">true</item>
</style>
+ <style name="Screenshot" parent="@android:style/Theme.DeviceDefault.DayNight"/>
+
<!-- Privacy dialog -->
<style name="PrivacyDialog" parent="Theme.SystemUI.QuickSettings.Dialog">
<item name="android:windowIsTranslucent">true</item>
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index f98a959..b2ae2a0 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -40,7 +40,8 @@
name: "SystemUISharedLib",
srcs: [
"src/**/*.java",
- "src/**/I*.aidl",
+ "src/**/*.kt",
+ "src/**/*.aidl",
":wm_shell-aidls",
],
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 2cf3ad2..c468e41 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -36,6 +36,9 @@
* Various shared constants between Launcher and SysUI as part of quickstep
*/
public class QuickStepContract {
+ // Fully qualified name of the Launcher activity.
+ public static final String LAUNCHER_ACTIVITY_CLASS_NAME =
+ "com.google.android.apps.nexuslauncher.NexusLauncherActivity";
public static final String KEY_EXTRA_SYSUI_PROXY = "extra_sysui_proxy";
public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
@@ -52,6 +55,8 @@
// See IStartingWindow.aidl
public static final String KEY_EXTRA_SHELL_STARTING_WINDOW =
"extra_shell_starting_window";
+ // See ISmartspaceTransitionController.aidl
+ public static final String KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER = "smartspace_transition";
public static final String NAV_BAR_MODE_2BUTTON_OVERLAY =
WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceCallback.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceCallback.aidl
new file mode 100644
index 0000000..511df4c
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceCallback.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.system.smartspace;
+
+import com.android.systemui.shared.system.smartspace.SmartspaceState;
+
+// Methods for getting and setting the state of a SmartSpace. This is used to allow a remote process
+// (such as System UI) to sync with and control a SmartSpace view hosted in another process (such as
+// Launcher).
+interface ISmartspaceCallback {
+
+ // Return information about the state of the SmartSpace, including location on-screen and
+ // currently selected page.
+ SmartspaceState getSmartspaceState();
+
+ // Set the currently selected page of this SmartSpace.
+ oneway void setSelectedPage(int selectedPage);
+
+ oneway void setVisibility(int visibility);
+}
\ No newline at end of file
diff --git a/packages/Connectivity/service/proto/connectivityproto.proto b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceTransitionController.aidl
similarity index 64%
copy from packages/Connectivity/service/proto/connectivityproto.proto
copy to packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceTransitionController.aidl
index a992d7c..2b3e961 100644
--- a/packages/Connectivity/service/proto/connectivityproto.proto
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/ISmartspaceTransitionController.aidl
@@ -14,7 +14,11 @@
* limitations under the License.
*/
-syntax = "proto2";
+package com.android.systemui.shared.system.smartspace;
-// Connectivity protos can be created in this directory. Note this file must be included before
-// building system-messages-proto, otherwise it will not build by itself.
+import com.android.systemui.shared.system.smartspace.ISmartspaceCallback;
+
+// Controller that keeps track of SmartSpace instances in remote processes (such as Launcher).
+interface ISmartspaceTransitionController {
+ oneway void setSmartspace(ISmartspaceCallback callback);
+}
\ No newline at end of file
diff --git a/packages/Connectivity/service/proto/connectivityproto.proto b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.aidl
similarity index 75%
rename from packages/Connectivity/service/proto/connectivityproto.proto
rename to packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.aidl
index a992d7c..2d01d6a 100644
--- a/packages/Connectivity/service/proto/connectivityproto.proto
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.aidl
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-syntax = "proto2";
+package com.android.systemui.shared.system.smartspace;
-// Connectivity protos can be created in this directory. Note this file must be included before
-// building system-messages-proto, otherwise it will not build by itself.
+import com.android.systemui.shared.system.smartspace.SmartspaceState;
+
+parcelable SmartspaceState;
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt
new file mode 100644
index 0000000..2d51c4d
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.system.smartspace
+
+import android.graphics.Rect
+import android.os.Parcel
+import android.os.Parcelable
+
+/**
+ * Represents the state of a SmartSpace, including its location on screen and the index of the
+ * currently selected page. This object contains all of the information needed to synchronize two
+ * SmartSpace instances so that we can perform shared-element transitions between them.
+ */
+class SmartspaceState() : Parcelable {
+ var boundsOnScreen: Rect = Rect()
+ var selectedPage = 0
+
+ constructor(parcel: Parcel) : this() {
+ this.boundsOnScreen = parcel.readParcelable(Rect::javaClass.javaClass.classLoader)
+ this.selectedPage = parcel.readInt()
+ }
+
+ override fun writeToParcel(dest: Parcel?, flags: Int) {
+ dest?.writeParcelable(boundsOnScreen, 0)
+ dest?.writeInt(selectedPage)
+ }
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun toString(): String {
+ return "boundsOnScreen: $boundsOnScreen, selectedPage: $selectedPage"
+ }
+
+ companion object CREATOR : Parcelable.Creator<SmartspaceState> {
+ override fun createFromParcel(parcel: Parcel): SmartspaceState {
+ return SmartspaceState(parcel)
+ }
+
+ override fun newArray(size: Int): Array<SmartspaceState?> {
+ return arrayOfNulls(size)
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
index 332de6c..7cb4846 100644
--- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java
@@ -54,8 +54,8 @@
private boolean mIsDozing;
private boolean mIsCharging;
private float mDozeAmount;
+ boolean mKeyguardShowing;
private Locale mLocale;
- private boolean mAttached; // if keyguard isn't showing, mAttached = false
private final NumberFormat mBurmeseNf = NumberFormat.getInstance(Locale.forLanguageTag("my"));
private final String mBurmeseNumerals;
@@ -85,11 +85,15 @@
R.dimen.keyguard_clock_line_spacing_scale);
}
+ private void reset() {
+ mView.animateDoze(mIsDozing, false);
+ }
+
private final BatteryController.BatteryStateChangeCallback mBatteryCallback =
new BatteryController.BatteryStateChangeCallback() {
@Override
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
- if (!mIsCharging && charging) {
+ if (mKeyguardShowing && !mIsCharging && charging) {
mView.animateCharge(mIsDozing);
}
mIsCharging = charging;
@@ -103,21 +107,6 @@
}
};
- private final KeyguardUpdateMonitorCallback mKeyguardPersistentCallback =
- new KeyguardUpdateMonitorCallback() {
- @Override
- public void onKeyguardVisibilityChanged(boolean showing) {
- // call attached/detached methods on visibility changes. benefits include:
- // - no animations when keyguard/clock view aren't visible
- // - resets state when keyguard is visible again (ie: font weight)
- if (showing) {
- onViewAttached();
- } else {
- onViewDetached();
- }
- }
- };
-
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@Override
@@ -128,44 +117,41 @@
mView.animateDisappear();
}
}
+
+ @Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ mKeyguardShowing = showing;
+ if (!mKeyguardShowing) {
+ // reset state (ie: after animateDisappear)
+ reset();
+ }
+ }
};
@Override
protected void onViewAttached() {
- if (mAttached) {
- return;
- }
- mAttached = true;
updateLocale();
mBroadcastDispatcher.registerReceiver(mLocaleBroadcastReceiver,
new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
mStatusBarStateController.addCallback(mStatusBarStateListener);
+
mIsDozing = mStatusBarStateController.isDozing();
mDozeAmount = mStatusBarStateController.getDozeAmount();
mBatteryController.addCallback(mBatteryCallback);
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
-
- mKeyguardUpdateMonitor.removeCallback(mKeyguardPersistentCallback);
- mKeyguardUpdateMonitor.registerCallback(mKeyguardPersistentCallback);
+ mKeyguardShowing = true;
refreshTime();
initColors();
+ mView.animateDoze(mIsDozing, false);
}
@Override
protected void onViewDetached() {
- if (!mAttached) {
- return;
- }
-
- mAttached = false;
mBroadcastDispatcher.unregisterReceiver(mLocaleBroadcastReceiver);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
mBatteryController.removeCallback(mBatteryCallback);
- if (!mView.isAttachedToWindow()) {
- mKeyguardUpdateMonitor.removeCallback(mKeyguardPersistentCallback);
- }
}
/** Animate the clock appearance */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index aa7f9a2..28534d3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -32,8 +32,10 @@
import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -44,7 +46,9 @@
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.ViewController;
+import java.util.HashSet;
import java.util.Locale;
+import java.util.Set;
import java.util.TimeZone;
import javax.inject.Inject;
@@ -92,6 +96,9 @@
// If set, will replace keyguard_status_area
private View mSmartspaceView;
+ private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ private SmartspaceTransitionController mSmartspaceTransitionController;
+
@Inject
public KeyguardClockSwitchController(
KeyguardClockSwitch keyguardClockSwitch,
@@ -104,7 +111,9 @@
BatteryController batteryController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
KeyguardBypassController bypassController,
- LockscreenSmartspaceController smartspaceController) {
+ LockscreenSmartspaceController smartspaceController,
+ KeyguardUnlockAnimationController keyguardUnlockAnimationController,
+ SmartspaceTransitionController smartspaceTransitionController) {
super(keyguardClockSwitch);
mStatusBarStateController = statusBarStateController;
mColorExtractor = colorExtractor;
@@ -116,6 +125,9 @@
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mBypassController = bypassController;
mSmartspaceController = smartspaceController;
+
+ mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
+ mSmartspaceTransitionController = smartspaceTransitionController;
}
/**
@@ -187,6 +199,7 @@
nic.setLayoutParams(lp);
mView.setSmartspaceView(mSmartspaceView);
+ mSmartspaceTransitionController.setLockscreenSmartspace(mSmartspaceView);
}
}
@@ -285,12 +298,44 @@
if (mSmartspaceView != null) {
PropertyAnimator.setProperty(mSmartspaceView, AnimatableProperty.TRANSLATION_X,
x, props, animate);
+
+ // If we're unlocking with the SmartSpace shared element transition, let the controller
+ // know that it should re-position our SmartSpace.
+ if (mKeyguardUnlockAnimationController.isUnlockingWithSmartSpaceTransition()) {
+ mKeyguardUnlockAnimationController.updateLockscreenSmartSpacePosition();
+ } else {
+ // Otherwise, reset Y translation in case it's still offset from a previous shared
+ // element transition.
+ ((View) mSmartspaceView).setTranslationY(0f);
+ }
}
mKeyguardSliceViewController.updatePosition(x, props, animate);
mNotificationIconAreaController.updatePosition(x, props, animate);
}
+ /** Sets an alpha value on every child view except for the smartspace. */
+ public void setChildrenAlphaExcludingSmartspace(float alpha) {
+ final Set<View> excludedViews = new HashSet<>();
+
+ if (mSmartspaceView != null) {
+ excludedViews.add(mSmartspaceView);
+ }
+
+ setChildrenAlphaExcluding(alpha, excludedViews);
+ }
+
+ /** Sets an alpha value on every child view except for the views in the provided set. */
+ public void setChildrenAlphaExcluding(float alpha, Set<View> excludedViews) {
+ for (int i = 0; i < mView.getChildCount(); i++) {
+ final View child = mView.getChildAt(i);
+
+ if (!excludedViews.contains(child)) {
+ child.setAlpha(alpha);
+ }
+ }
+ }
+
void updateTimeZone(TimeZone timeZone) {
mView.onTimeZoneChanged(timeZone);
if (mClockViewController != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 3ab2cca..96eda3d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -28,6 +28,7 @@
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.GridLayout;
import android.widget.TextView;
@@ -39,6 +40,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.Set;
/**
* View consisting of:
@@ -55,6 +57,7 @@
private final LockPatternUtils mLockPatternUtils;
private final IActivityManager mIActivityManager;
+ private ViewGroup mStatusViewContainer;
private TextView mLogoutView;
private KeyguardClockSwitch mClockView;
private TextView mOwnerInfo;
@@ -66,6 +69,7 @@
private float mDarkAmount = 0;
private int mTextColor;
+ private float mChildrenAlphaExcludingSmartSpace = 1f;
/**
* Bottom margin that defines the margin between bottom of smart space and top of notification
@@ -132,6 +136,7 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mStatusViewContainer = findViewById(R.id.status_view_container);
mLogoutView = findViewById(R.id.logout);
if (mLogoutView != null) {
mLogoutView.setOnClickListener(this::onLogoutClicked);
@@ -228,9 +233,7 @@
}
mDarkAmount = darkAmount;
mClockView.setDarkAmount(darkAmount);
- if (mMediaHostContainer.getVisibility() != View.GONE) {
- CrossFadeHelper.fadeOut(mMediaHostContainer, darkAmount);
- }
+ CrossFadeHelper.fadeOut(mMediaHostContainer, darkAmount);
updateDark();
}
@@ -251,6 +254,27 @@
mClockView.setTextColor(blendedTextColor);
}
+ public void setChildrenAlphaExcludingClockView(float alpha) {
+ setChildrenAlphaExcluding(alpha, Set.of(mClockView));
+ }
+
+ /** Sets an alpha value on every view except for the views in the provided set. */
+ public void setChildrenAlphaExcluding(float alpha, Set<View> excludedViews) {
+ mChildrenAlphaExcludingSmartSpace = alpha;
+
+ for (int i = 0; i < mStatusViewContainer.getChildCount(); i++) {
+ final View child = mStatusViewContainer.getChildAt(i);
+
+ if (!excludedViews.contains(child)) {
+ child.setAlpha(alpha);
+ }
+ }
+ }
+
+ public float getChildrenAlphaExcludingSmartSpace() {
+ return mChildrenAlphaExcludingSmartSpace;
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardStatusView:");
pw.println(" mOwnerInfo: " + (mOwnerInfo == null
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 388c085..7b6514a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -20,6 +20,8 @@
import android.os.UserHandle;
import android.util.Slog;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
@@ -49,6 +51,9 @@
private final ConfigurationController mConfigurationController;
private final DozeParameters mDozeParameters;
private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
+ private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ private final KeyguardStateController mKeyguardStateController;
+ private SmartspaceTransitionController mSmartspaceTransitionController;
private final Rect mClipBounds = new Rect();
@Inject
@@ -59,15 +64,33 @@
KeyguardStateController keyguardStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
ConfigurationController configurationController,
- DozeParameters dozeParameters) {
+ DozeParameters dozeParameters,
+ KeyguardUnlockAnimationController keyguardUnlockAnimationController,
+ SmartspaceTransitionController smartspaceTransitionController) {
super(keyguardStatusView);
mKeyguardSliceViewController = keyguardSliceViewController;
mKeyguardClockSwitchController = keyguardClockSwitchController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mConfigurationController = configurationController;
mDozeParameters = dozeParameters;
+ mKeyguardStateController = keyguardStateController;
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController,
dozeParameters);
+ mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
+ mSmartspaceTransitionController = smartspaceTransitionController;
+
+ mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
+ @Override
+ public void onKeyguardShowingChanged() {
+ // If we explicitly re-show the keyguard, make sure that all the child views are
+ // visible. They might have been animating out as part of the SmartSpace shared
+ // element transition.
+ if (keyguardStateController.isShowing()) {
+ mView.setChildrenAlphaExcludingClockView(1f);
+ mKeyguardClockSwitchController.setChildrenAlphaExcludingSmartspace(1f);
+ }
+ }
+ });
}
@Override
@@ -137,7 +160,24 @@
*/
public void setAlpha(float alpha) {
if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) {
- mView.setAlpha(alpha);
+ // If we're capable of performing the SmartSpace shared element transition, and we are
+ // going to (we're swiping to dismiss vs. bringing up the PIN screen), then fade out
+ // everything except for the SmartSpace.
+ if (mKeyguardUnlockAnimationController.isUnlockingWithSmartSpaceTransition()) {
+ mView.setChildrenAlphaExcludingClockView(alpha);
+ mKeyguardClockSwitchController.setChildrenAlphaExcludingSmartspace(alpha);
+ } else if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) {
+ // Otherwise, we can just set the alpha for the entire container.
+ mView.setAlpha(alpha);
+
+ // If we previously unlocked with the shared element transition, some child views
+ // might still have alpha = 0f. Set them back to 1f since we're just using the
+ // parent container's alpha.
+ if (mView.getChildrenAlphaExcludingSmartSpace() < 1f) {
+ mView.setChildrenAlphaExcludingClockView(1f);
+ mKeyguardClockSwitchController.setChildrenAlphaExcludingSmartspace(1f);
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index 096597a..0d31906 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -16,22 +16,36 @@
package com.android.keyguard;
import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
+import android.graphics.drawable.VectorDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
+import androidx.annotation.Nullable;
+
+import com.android.settingslib.Utils;
+import com.android.systemui.R;
+
/**
* Similar to the {@link NumPadKey}, but displays an image.
*/
public class NumPadButton extends AlphaOptimizedImageButton {
+ @Nullable
private NumPadAnimator mAnimator;
public NumPadButton(Context context, AttributeSet attrs) {
super(context, attrs);
- mAnimator = new NumPadAnimator(context, (RippleDrawable) getBackground(),
- attrs.getStyleAttribute());
+ Drawable background = getBackground();
+ if (background instanceof RippleDrawable) {
+ mAnimator = new NumPadAnimator(context, (RippleDrawable) getBackground(),
+ attrs.getStyleAttribute());
+ } else {
+ mAnimator = null;
+ }
}
@Override
@@ -41,7 +55,7 @@
// Set width/height to the same value to ensure a smooth circle for the bg, but shrink
// the height to match the old pin bouncer
int width = getMeasuredWidth();
- int height = width;
+ int height = mAnimator == null ? (int) (width * .75f) : width;
setMeasuredDimension(getMeasuredWidth(), height);
}
@@ -50,12 +64,12 @@
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
- mAnimator.onLayout(b - t);
+ if (mAnimator != null) mAnimator.onLayout(b - t);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN && mAnimator != null) {
mAnimator.start();
}
return super.onTouchEvent(event);
@@ -65,6 +79,13 @@
* Reload colors from resources.
**/
public void reloadColors() {
- mAnimator.reloadColors(getContext());
+ if (mAnimator != null) {
+ mAnimator.reloadColors(getContext());
+ } else {
+ // Needed for old style pin
+ int textColor = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary)
+ .getDefaultColor();
+ ((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(textColor));
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 35ace0d..cffa630 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -30,6 +31,8 @@
import android.view.accessibility.AccessibilityManager;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.internal.widget.LockPatternUtils;
import com.android.settingslib.Utils;
import com.android.systemui.R;
@@ -47,6 +50,7 @@
private int mTextViewResId;
private PasswordTextView mTextView;
+ @Nullable
private NumPadAnimator mAnimator;
private View.OnClickListener mListener = new View.OnClickListener() {
@@ -126,8 +130,13 @@
setContentDescription(mDigitText.getText().toString());
- mAnimator = new NumPadAnimator(context, (RippleDrawable) getBackground(),
- R.style.NumPadKey);
+ Drawable background = getBackground();
+ if (background instanceof RippleDrawable) {
+ mAnimator = new NumPadAnimator(context, (RippleDrawable) background,
+ R.style.NumPadKey);
+ } else {
+ mAnimator = null;
+ }
}
/**
@@ -141,14 +150,14 @@
mDigitText.setTextColor(textColor);
mKlondikeText.setTextColor(klondikeColor);
- mAnimator.reloadColors(getContext());
+ if (mAnimator != null) mAnimator.reloadColors(getContext());
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
doHapticKeyClick();
- mAnimator.start();
+ if (mAnimator != null) mAnimator.start();
}
return super.onTouchEvent(event);
@@ -162,7 +171,7 @@
// Set width/height to the same value to ensure a smooth circle for the bg, but shrink
// the height to match the old pin bouncer
int width = getMeasuredWidth();
- int height = width;
+ int height = mAnimator == null ? (int) (width * .75f) : width;
setMeasuredDimension(getMeasuredWidth(), height);
}
@@ -183,7 +192,7 @@
left = centerX - mKlondikeText.getMeasuredWidth() / 2;
mKlondikeText.layout(left, top, left + mKlondikeText.getMeasuredWidth(), bottom);
- mAnimator.onLayout(b - t);
+ if (mAnimator != null) mAnimator.onLayout(b - t);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index afda2a4..e9c5653 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -236,7 +236,7 @@
Log.i(TAG, "ScreenDecorations is disabled");
return;
}
- mHandler = mThreadFactory.builderHandlerOnNewThread("ScreenDecorations");
+ mHandler = mThreadFactory.buildHandlerOnNewThread("ScreenDecorations");
mExecutor = mThreadFactory.buildDelayableExecutorOnHandler(mHandler);
mExecutor.execute(this::startOnScreenDecorationsThread);
mDotViewController.setUiExecutor(mExecutor);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index cc167b9..e6fe060 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -133,6 +133,7 @@
.setTaskViewFactory(Optional.ofNullable(null))
.setTransitions(Transitions.createEmptyForTesting())
.setStartingSurface(Optional.ofNullable(null));
+
}
mSysUIComponent = builder.build();
if (mInitializeComponents) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
index ee7eb4b..964b135 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
@@ -16,6 +16,7 @@
package com.android.systemui.accessibility;
+import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
import android.annotation.NonNull;
@@ -70,7 +71,7 @@
private final ImageView mImageView;
private final Runnable mWindowInsetChangeRunnable;
private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
- private int mMagnificationMode = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
+ private int mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
private final LayoutParams mParams;
@VisibleForTesting
final Rect mDraggableWindowBounds = new Rect();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
index 71260de..ebfd206 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
@@ -26,9 +26,11 @@
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
/**
@@ -97,6 +99,11 @@
super(context, attrs);
}
+ @VisibleForTesting
+ AuthBiometricFaceToFingerprintView(Context context, AttributeSet attrs, Injector injector) {
+ super(context, attrs, injector);
+ }
+
void setFingerprintSensorProps(@NonNull FingerprintSensorPropertiesInternal sensorProps) {
if (!sensorProps.isAnyUdfpsType()) {
return;
@@ -119,23 +126,44 @@
}
@Override
+ @BiometricState
+ protected int getStateForAfterError() {
+ if (mActiveSensorType == TYPE_FACE) {
+ mHandler.post(() -> mCallback.onAction(
+ Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR));
+ return STATE_AUTHENTICATING;
+ }
+
+ return super.getStateForAfterError();
+ }
+
+ @Override
@NonNull
protected IconController getIconController() {
if (mActiveSensorType == TYPE_FINGERPRINT) {
if (!(mIconController instanceof UdfpsIconController)) {
- mIconController = new UdfpsIconController(getContext(), mIconView, mIndicatorView);
+ mIconController = createUdfpsIconController();
}
return mIconController;
}
return super.getIconController();
}
+ @NonNull
+ protected IconController createUdfpsIconController() {
+ return new UdfpsIconController(getContext(), mIconView, mIndicatorView);
+ }
+
@Override
public void updateState(int newState) {
if (mState == STATE_HELP || mState == STATE_ERROR) {
mActiveSensorType = TYPE_FINGERPRINT;
+
setRequireConfirmation(false);
+ mConfirmButton.setEnabled(false);
+ mConfirmButton.setVisibility(View.GONE);
}
+
super.updateState(newState);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
index 4c5ca69..f7d2d8c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
@@ -29,6 +29,7 @@
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
public class AuthBiometricFaceView extends AuthBiometricView {
@@ -148,6 +149,11 @@
super(context, attrs);
}
+ @VisibleForTesting
+ AuthBiometricFaceView(Context context, AttributeSet attrs, Injector injector) {
+ super(context, attrs, injector);
+ }
+
@Override
protected int getDelayAfterAuthenticatedDurationMs() {
return HIDE_DELAY_MS;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index a40af70..1ac1df1 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -99,6 +99,13 @@
int ACTION_BUTTON_TRY_AGAIN = 4;
int ACTION_ERROR = 5;
int ACTION_USE_DEVICE_CREDENTIAL = 6;
+ /**
+ * Notify the receiver to start the fingerprint sensor.
+ *
+ * This is only applicable to multi-sensor devices that need to delay fingerprint auth
+ * (i.e face -> fingerprint).
+ */
+ int ACTION_START_DELAYED_FINGERPRINT_SENSOR = 7;
/**
* When an action has occurred. The caller will only invoke this when the callback should
@@ -166,7 +173,7 @@
}
private final Injector mInjector;
- private final Handler mHandler;
+ protected final Handler mHandler;
private final AccessibilityManager mAccessibilityManager;
protected final int mTextColorError;
protected final int mTextColorHint;
@@ -199,7 +206,7 @@
// Measurements when biometric view is showing text, buttons, etc.
@Nullable @VisibleForTesting AuthDialog.LayoutParams mLayoutParams;
- private Callback mCallback;
+ protected Callback mCallback;
protected @BiometricState int mState;
private float mIconOriginalY;
@@ -605,7 +612,7 @@
mIndicatorView.setTextColor(mTextColorError);
mIndicatorView.setVisibility(View.VISIBLE);
mIndicatorView.setSelected(true);
- mHandler.postDelayed(resetMessageRunnable, BiometricPrompt.HIDE_DIALOG_DELAY);
+ mHandler.postDelayed(resetMessageRunnable, mInjector.getDelayAfterError());
Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 9e72310..6f1a387 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -16,6 +16,8 @@
package com.android.systemui.biometrics;
+import static android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -121,6 +123,7 @@
boolean mCredentialAllowed;
boolean mSkipIntro;
long mOperationId;
+ @BiometricMultiSensorMode int mMultiSensorConfig;
}
public static class Builder {
@@ -166,6 +169,12 @@
return this;
}
+ /** The multi-sensor mode. */
+ public Builder setMultiSensorConfig(@BiometricMultiSensorMode int multiSensorConfig) {
+ mConfig.mMultiSensorConfig = multiSensorConfig;
+ return this;
+ }
+
public AuthContainerView build(int[] sensorIds, boolean credentialAllowed,
@Nullable List<FingerprintSensorPropertiesInternal> fpProps,
@Nullable List<FaceSensorPropertiesInternal> faceProps) {
@@ -237,6 +246,9 @@
addCredentialView(false /* animatePanel */, true /* animateContents */);
}, mInjector.getAnimateCredentialStartDelayMs());
break;
+ case AuthBiometricView.Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR:
+ mConfig.mCallback.onStartFingerprintNow();
+ break;
default:
Log.e(TAG, "Unhandled action: " + action);
}
@@ -316,21 +328,9 @@
return;
}
} else if (sensorCount == 2) {
- int fingerprintSensorId = -1;
- int faceSensorId = -1;
- for (final int sensorId : config.mSensorIds) {
- if (Utils.containsSensorId(mFpProps, sensorId)) {
- fingerprintSensorId = sensorId;
- continue;
- } else if (Utils.containsSensorId(mFaceProps, sensorId)) {
- faceSensorId = sensorId;
- continue;
- }
-
- if (fingerprintSensorId != -1 && faceSensorId != -1) {
- break;
- }
- }
+ final int[] allSensors = findFaceAndFingerprintSensors();
+ final int faceSensorId = allSensors[0];
+ final int fingerprintSensorId = allSensors[1];
if (fingerprintSensorId == -1 || faceSensorId == -1) {
Log.e(TAG, "Missing fingerprint or face for dual-sensor config");
@@ -747,4 +747,29 @@
lp.token = windowToken;
return lp;
}
+
+ private boolean hasFaceAndFingerprintSensors() {
+ final int[] ids = findFaceAndFingerprintSensors();
+ return ids[0] >= 0 && ids[1] >= 0;
+ }
+
+ // returns [face, fingerprint] sensor ids (id is -1 if not present)
+ private int[] findFaceAndFingerprintSensors() {
+ int faceSensorId = -1;
+ int fingerprintSensorId = -1;
+
+ for (final int sensorId : mConfig.mSensorIds) {
+ if (Utils.containsSensorId(mFpProps, sensorId)) {
+ fingerprintSensorId = sensorId;
+ } else if (Utils.containsSensorId(mFaceProps, sensorId)) {
+ faceSensorId = sensorId;
+ }
+
+ if (fingerprintSensorId != -1 && faceSensorId != -1) {
+ break;
+ }
+ }
+
+ return new int[] {faceSensorId, fingerprintSensorId};
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 6db44ed..146f430 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -19,6 +19,7 @@
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.Authenticators;
+import static android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -53,14 +54,16 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import com.android.systemui.SystemUI;
+import com.android.systemui.assist.ui.DisplayUtils;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.doze.DozeReceiver;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import javax.inject.Inject;
import javax.inject.Provider;
@@ -78,13 +81,14 @@
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final CommandQueue mCommandQueue;
- private final StatusBarStateController mStatusBarStateController;
private final ActivityTaskManager mActivityTaskManager;
@Nullable private final FingerprintManager mFingerprintManager;
@Nullable private final FaceManager mFaceManager;
private final Provider<UdfpsController> mUdfpsControllerFactory;
private final Provider<SidefpsController> mSidefpsControllerFactory;
@Nullable private final PointF mFaceAuthSensorLocation;
+ @Nullable private final PointF mFingerprintLocation;
+ private final Set<Callback> mCallbacks = new HashSet<>();
// TODO: These should just be saved from onSaveState
private SomeArgs mCurrentDialogArgs;
@@ -141,6 +145,10 @@
if (mSidefpsProps != null) {
mSidefpsController = mSidefpsControllerFactory.get();
}
+
+ for (Callback cb : mCallbacks) {
+ cb.onAllAuthenticatorsRegistered();
+ }
}
};
@@ -194,6 +202,20 @@
}
}
+ /**
+ * Adds a callback. See {@link Callback}.
+ */
+ public void addCallback(@NonNull Callback callback) {
+ mCallbacks.add(callback);
+ }
+
+ /**
+ * Removes a callback. See {@link Callback}.
+ */
+ public void removeCallback(@NonNull Callback callback) {
+ mCallbacks.remove(callback);
+ }
+
@Override
public void dozeTimeTick() {
if (mUdfpsController != null) {
@@ -255,6 +277,20 @@
}
@Override
+ public void onStartFingerprintNow() {
+ if (mReceiver == null) {
+ Log.e(TAG, "onStartUdfpsNow: Receiver is null");
+ return;
+ }
+
+ try {
+ mReceiver.onStartFingerprintNow();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException when sending onDialogAnimatedIn", e);
+ }
+ }
+
+ @Override
public void onDismissed(@DismissedReason int reason, @Nullable byte[] credentialAttestation) {
switch (reason) {
case AuthDialogCallback.DISMISSED_USER_CANCELED:
@@ -320,6 +356,17 @@
}
/**
+ * @return where the fingerprint sensor exists in pixels in portrait mode. devices without an
+ * overridden value will use the default value even if they don't have a fingerprint sensor
+ */
+ @Nullable public PointF getFingerprintSensorLocation() {
+ if (getUdfpsSensorLocation() != null) {
+ return getUdfpsSensorLocation();
+ }
+ return mFingerprintLocation;
+ }
+
+ /**
* @return where the face authentication sensor exists relative to the screen in pixels in
* portrait mode.
*/
@@ -372,7 +419,6 @@
@Inject
public AuthController(Context context, CommandQueue commandQueue,
- StatusBarStateController statusBarStateController,
ActivityTaskManager activityTaskManager,
@Nullable FingerprintManager fingerprintManager,
@Nullable FaceManager faceManager,
@@ -380,7 +426,6 @@
Provider<SidefpsController> sidefpsControllerFactory) {
super(context);
mCommandQueue = commandQueue;
- mStatusBarStateController = statusBarStateController;
mActivityTaskManager = activityTaskManager;
mFingerprintManager = fingerprintManager;
mFaceManager = faceManager;
@@ -399,6 +444,10 @@
(float) faceAuthLocation[1]);
}
+ mFingerprintLocation = new PointF(DisplayUtils.getWidth(mContext) / 2,
+ mContext.getResources().getDimensionPixelSize(
+ com.android.systemui.R.dimen.physical_fingerprint_sensor_center_screen_location_y));
+
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
@@ -423,7 +472,8 @@
@Override
public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
- int userId, String opPackageName, long operationId) {
+ int userId, String opPackageName, long operationId,
+ @BiometricMultiSensorMode int multiSensorConfig) {
@Authenticators.Types final int authenticators = promptInfo.getAuthenticators();
if (DEBUG) {
@@ -435,7 +485,8 @@
+ ", sensorIds: " + ids.toString()
+ ", credentialAllowed: " + credentialAllowed
+ ", requireConfirmation: " + requireConfirmation
- + ", operationId: " + operationId);
+ + ", operationId: " + operationId
+ + ", multiSensorConfig: " + multiSensorConfig);
}
SomeArgs args = SomeArgs.obtain();
args.arg1 = promptInfo;
@@ -446,6 +497,7 @@
args.argi1 = userId;
args.arg6 = opPackageName;
args.arg7 = operationId;
+ args.argi2 = multiSensorConfig;
boolean skipAnimation = false;
if (mCurrentDialog != null) {
@@ -463,14 +515,24 @@
*/
@Override
public void onBiometricAuthenticated() {
- mCurrentDialog.onAuthenticationSucceeded();
+ if (DEBUG) Log.d(TAG, "onBiometricAuthenticated: ");
+
+ if (mCurrentDialog != null) {
+ mCurrentDialog.onAuthenticationSucceeded();
+ } else {
+ Log.w(TAG, "onBiometricAuthenticated callback but dialog gone");
+ }
}
@Override
public void onBiometricHelp(String message) {
if (DEBUG) Log.d(TAG, "onBiometricHelp: " + message);
- mCurrentDialog.onHelp(message);
+ if (mCurrentDialog != null) {
+ mCurrentDialog.onHelp(message);
+ } else {
+ Log.w(TAG, "onBiometricHelp callback but dialog gone");
+ }
}
@Nullable
@@ -509,19 +571,23 @@
final boolean isSoftError = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED
|| error == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT);
- if (mCurrentDialog.isAllowDeviceCredentials() && isLockout) {
- if (DEBUG) Log.d(TAG, "onBiometricError, lockout");
- mCurrentDialog.animateToCredentialUI();
- } else if (isSoftError) {
- final String errorMessage = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED)
- ? mContext.getString(R.string.biometric_not_recognized)
- : getErrorString(modality, error, vendorCode);
- if (DEBUG) Log.d(TAG, "onBiometricError, soft error: " + errorMessage);
- mCurrentDialog.onAuthenticationFailed(errorMessage);
+ if (mCurrentDialog != null) {
+ if (mCurrentDialog.isAllowDeviceCredentials() && isLockout) {
+ if (DEBUG) Log.d(TAG, "onBiometricError, lockout");
+ mCurrentDialog.animateToCredentialUI();
+ } else if (isSoftError) {
+ final String errorMessage = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED)
+ ? mContext.getString(R.string.biometric_not_recognized)
+ : getErrorString(modality, error, vendorCode);
+ if (DEBUG) Log.d(TAG, "onBiometricError, soft error: " + errorMessage);
+ mCurrentDialog.onAuthenticationFailed(errorMessage);
+ } else {
+ final String errorMessage = getErrorString(modality, error, vendorCode);
+ if (DEBUG) Log.d(TAG, "onBiometricError, hard error: " + errorMessage);
+ mCurrentDialog.onError(errorMessage);
+ }
} else {
- final String errorMessage = getErrorString(modality, error, vendorCode);
- if (DEBUG) Log.d(TAG, "onBiometricError, hard error: " + errorMessage);
- mCurrentDialog.onError(errorMessage);
+ Log.w(TAG, "onBiometricError callback but dialog is gone");
}
onCancelUdfps();
@@ -576,6 +642,7 @@
final int userId = args.argi1;
final String opPackageName = (String) args.arg6;
final long operationId = (long) args.arg7;
+ final @BiometricMultiSensorMode int multiSensorConfig = args.argi2;
// Create a new dialog but do not replace the current one yet.
final AuthDialog newDialog = buildDialog(
@@ -586,7 +653,8 @@
credentialAllowed,
opPackageName,
skipAnimation,
- operationId);
+ operationId,
+ multiSensorConfig);
if (newDialog == null) {
Log.e(TAG, "Unsupported type configuration");
@@ -664,7 +732,8 @@
protected AuthDialog buildDialog(PromptInfo promptInfo, boolean requireConfirmation,
int userId, int[] sensorIds, boolean credentialAllowed, String opPackageName,
- boolean skipIntro, long operationId) {
+ boolean skipIntro, long operationId,
+ @BiometricMultiSensorMode int multiSensorConfig) {
return new AuthContainerView.Builder(mContext)
.setCallback(this)
.setPromptInfo(promptInfo)
@@ -673,6 +742,15 @@
.setOpPackageName(opPackageName)
.setSkipIntro(skipIntro)
.setOperationId(operationId)
+ .setMultiSensorConfig(multiSensorConfig)
.build(sensorIds, credentialAllowed, mFpProps, mFaceProps);
}
+
+ interface Callback {
+ /**
+ * Called when authenticators are registered. If authenticators are already
+ * registered before this call, this callback will never be triggered.
+ */
+ void onAllAuthenticatorsRegistered();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
index d8d07e7..9f40ca7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java
@@ -67,7 +67,12 @@
void onSystemEvent(int event);
/**
- * Notifies when the dialog has finished animating in.
+ * Notifies when the dialog has finished animating.
*/
void onDialogAnimatedIn();
+
+ /**
+ * Notifies that the fingerprint sensor should be started now.
+ */
+ void onStartFingerprintNow();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 257bd25..cf577a3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -28,6 +28,7 @@
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.StatusBar
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.ViewController
@@ -40,6 +41,7 @@
*/
@StatusBarScope
class AuthRippleController @Inject constructor(
+ private val statusBar: StatusBar,
private val sysuiContext: Context,
private val authController: AuthController,
private val configurationController: ConfigurationController,
@@ -49,13 +51,14 @@
private val bypassController: KeyguardBypassController,
rippleView: AuthRippleView?
) : ViewController<AuthRippleView>(rippleView) {
- private var fingerprintSensorLocation: PointF? = null
+ var fingerprintSensorLocation: PointF? = null
private var faceSensorLocation: PointF? = null
@VisibleForTesting
public override fun onViewAttached() {
updateRippleColor()
updateSensorLocation()
+ authController.addCallback(authControllerCallback)
configurationController.addCallback(configurationChangedListener)
keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
commandRegistry.registerCommand("auth-ripple") { AuthRippleCommand() }
@@ -63,6 +66,7 @@
@VisibleForTesting
public override fun onViewDetached() {
+ authController.removeCallback(authControllerCallback)
keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback)
configurationController.removeCallback(configurationChangedListener)
commandRegistry.unregisterCommand("auth-ripple")
@@ -97,9 +101,10 @@
})
}
- private fun updateSensorLocation() {
- fingerprintSensorLocation = authController.udfpsSensorLocation
+ fun updateSensorLocation() {
+ fingerprintSensorLocation = authController.fingerprintSensorLocation
faceSensorLocation = authController.faceAuthSensorLocation
+ statusBar.updateCircleReveal()
}
private fun updateRippleColor() {
@@ -134,6 +139,8 @@
}
}
+ private val authControllerCallback = AuthController.Callback { updateSensorLocation() }
+
inner class AuthRippleCommand : Command {
override fun execute(pw: PrintWriter, args: List<String>) {
if (args.isEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index 374ddae..01fbe39 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -23,7 +23,11 @@
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.PointF
+import android.media.AudioAttributes
+import android.os.VibrationEffect
+import android.os.Vibrator
import android.util.AttributeSet
+import android.util.MathUtils
import android.view.View
import android.view.animation.PathInterpolator
import com.android.internal.graphics.ColorUtils
@@ -31,15 +35,26 @@
private const val RIPPLE_ANIMATION_DURATION: Long = 1533
private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.4f
+private const val RIPPLE_VIBRATION_PRIMITIVE: Int = VibrationEffect.Composition.PRIMITIVE_LOW_TICK
+private const val RIPPLE_VIBRATION_SIZE: Int = 60
+private const val RIPPLE_VIBRATION_SCALE_START: Float = 0.6f
+private const val RIPPLE_VIBRATION_SCALE_DECAY: Float = -0.1f
/**
* Expanding ripple effect on the transition from biometric authentication success to showing
* launcher.
*/
class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
+ private val vibrator: Vibrator? = context?.getSystemService(Vibrator::class.java)
private var rippleInProgress: Boolean = false
private val rippleShader = RippleShader()
private val ripplePaint = Paint()
+ private val rippleVibrationEffect = createVibrationEffect(vibrator)
+ private val rippleVibrationAttrs =
+ AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ .build()
init {
rippleShader.color = 0xffffffff.toInt() // default color
@@ -95,6 +110,7 @@
visibility = GONE
}
})
+ vibrate()
animatorSet.start()
visibility = VISIBLE
rippleInProgress = true
@@ -108,4 +124,23 @@
// draw over the entire screen
canvas?.drawRect(0f, 0f, width.toFloat(), height.toFloat(), ripplePaint)
}
+
+ private fun vibrate() {
+ if (rippleVibrationEffect != null) {
+ vibrator?.vibrate(rippleVibrationEffect, rippleVibrationAttrs)
+ }
+ }
+
+ private fun createVibrationEffect(vibrator: Vibrator?): VibrationEffect? {
+ if (vibrator?.areAllPrimitivesSupported(RIPPLE_VIBRATION_PRIMITIVE) == false) {
+ return null
+ }
+ val composition = VibrationEffect.startComposition()
+ for (i in 0 until RIPPLE_VIBRATION_SIZE) {
+ val scale =
+ RIPPLE_VIBRATION_SCALE_START * MathUtils.exp(RIPPLE_VIBRATION_SCALE_DECAY * i)
+ composition.addPrimitive(RIPPLE_VIBRATION_PRIMITIVE, scale, 0 /* delay */)
+ }
+ return composition.compose()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 3075617..5c360a6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -496,7 +496,6 @@
mSensorProps = findFirstUdfps();
// At least one UDFPS sensor exists
checkArgument(mSensorProps != null);
- mStatusBar.setSensorRect(getSensorLocation());
mCoreLayoutParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
index ee69e27..dba530e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
@@ -40,6 +40,7 @@
private boolean mIsFalseRobustTap;
private final List<FalsingBeliefListener> mFalsingBeliefListeners = new ArrayList<>();
+ private final List<FalsingTapListener> mTapListeners = new ArrayList<>();
@Override
public void onSuccessfulUnlock() {
@@ -148,11 +149,15 @@
@Override
public void addTapListener(FalsingTapListener falsingTapListener) {
-
+ mTapListeners.add(falsingTapListener);
}
@Override
public void removeTapListener(FalsingTapListener falsingTapListener) {
+ mTapListeners.remove(falsingTapListener);
+ }
+ public List<FalsingTapListener> getTapListeners() {
+ return mTapListeners;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 26db33d..053d75d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -46,6 +46,7 @@
import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.media.AudioManager;
+import android.media.IAudioService;
import android.media.MediaRouter2Manager;
import android.media.session.MediaSessionManager;
import android.net.ConnectivityManager;
@@ -77,6 +78,8 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.shared.system.PackageManagerWrapper;
+import java.util.Optional;
+
import javax.inject.Singleton;
import dagger.Module;
@@ -167,6 +170,13 @@
@Provides
@Singleton
+ static IAudioService provideIAudioService() {
+ return IAudioService.Stub.asInterface(ServiceManager.getService(Context.AUDIO_SERVICE));
+ }
+
+
+ @Provides
+ @Singleton
static IBatteryStats provideIBatteryStats() {
return IBatteryStats.Stub.asInterface(
ServiceManager.getService(BatteryStats.SERVICE_NAME));
@@ -362,6 +372,12 @@
@Provides
@Singleton
+ static Optional<Vibrator> provideOptionalVibrator(Context context) {
+ return Optional.ofNullable(context.getSystemService(Vibrator.class));
+ }
+
+ @Provides
+ @Singleton
static ViewConfiguration provideViewConfiguration(Context context) {
return ViewConfiguration.get(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 1396099..f422e9e 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -45,6 +45,7 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.settings.dagger.SettingsModule;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -173,6 +174,12 @@
return SystemUIFactory.getInstance();
}
+ @SysUISingleton
+ @Provides
+ static SmartspaceTransitionController provideSmartspaceTransitionController() {
+ return new SmartspaceTransitionController();
+ }
+
// TODO: This should provided by the WM component
/** Provides Optional of BubbleManager */
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index 411e0f0..178a74c 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -95,9 +95,10 @@
d.setOnShowListener(dialog -> {
if (mBlurUtils.supportsBlursOnWindows()) {
- background.setAlpha((int) (ScrimController.BUSY_SCRIM_ALPHA * 255));
+ int backgroundAlpha = (int) (ScrimController.BUSY_SCRIM_ALPHA * 255);
+ background.setAlpha(backgroundAlpha);
mBlurUtils.applyBlur(d.getWindow().getDecorView().getViewRootImpl(),
- mBlurUtils.blurRadiusOfRatio(1));
+ mBlurUtils.blurRadiusOfRatio(1), backgroundAlpha == 255);
} else {
float backgroundAlpha = mContext.getResources().getFloat(
com.android.systemui.R.dimen.shutdown_scrim_behind_alpha);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 411c328..665376a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -23,11 +23,14 @@
import android.graphics.Matrix
import android.view.RemoteAnimationTarget
import android.view.SyncRtSurfaceTransactionApplier
+import android.view.View
import androidx.core.math.MathUtils
import com.android.internal.R
+import com.android.keyguard.KeyguardClockSwitchController
import com.android.keyguard.KeyguardViewController
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController
import com.android.systemui.statusbar.policy.KeyguardStateController
import dagger.Lazy
import javax.inject.Inject
@@ -85,7 +88,8 @@
context: Context,
private val keyguardStateController: KeyguardStateController,
private val keyguardViewMediator: Lazy<KeyguardViewMediator>,
- private val keyguardViewController: KeyguardViewController
+ private val keyguardViewController: KeyguardViewController,
+ private val smartspaceTransitionController: SmartspaceTransitionController
) : KeyguardStateController.Callback {
/**
@@ -131,6 +135,21 @@
/** Rounded corner radius to apply to the surface behind the keyguard. */
private var roundedCornerRadius = 0f
+ /** The SmartSpace view on the lockscreen, provided by [KeyguardClockSwitchController]. */
+ public var lockscreenSmartSpace: View? = null
+
+ /**
+ * Whether we are currently in the process of unlocking the keyguard, and we are performing the
+ * shared element SmartSpace transition.
+ */
+ private var unlockingWithSmartSpaceTransition: Boolean = false
+
+ /**
+ * Whether we tried to start the SmartSpace shared element transition for this unlock swipe.
+ * It's possible we're unable to do so (if the Launcher SmartSpace is not available).
+ */
+ private var attemptedSmartSpaceTransitionForThisSwipe = false
+
init {
surfaceBehindAlphaAnimator.duration = 150
surfaceBehindAlphaAnimator.interpolator = Interpolators.ALPHA_IN
@@ -214,6 +233,24 @@
}
/**
+ * Whether we are currently in the process of unlocking the keyguard, and we are performing the
+ * shared element SmartSpace transition.
+ */
+ fun isUnlockingWithSmartSpaceTransition(): Boolean {
+ return unlockingWithSmartSpaceTransition
+ }
+
+ /**
+ * Update the lockscreen SmartSpace to be positioned according to the current dismiss amount. As
+ * the dismiss amount increases, we will increase our SmartSpace's progress to the destination
+ * bounds (the location of the Launcher SmartSpace).
+ */
+ fun updateLockscreenSmartSpacePosition() {
+ smartspaceTransitionController.setProgressToDestinationBounds(
+ keyguardStateController.dismissAmount / DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD)
+ }
+
+ /**
* Scales in and translates up the surface behind the keyguard. This is used during unlock
* animations and swipe gestures to animate the surface's entry (and exit, if the swipe is
* cancelled).
@@ -284,36 +321,85 @@
return
}
+ if (keyguardViewController.isShowing) {
+ updateKeyguardViewMediatorIfThresholdsReached()
+
+ // If the surface is visible or it's about to be, start updating its appearance to
+ // reflect the new dismiss amount.
+ if (keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() ||
+ keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) {
+ updateSurfaceBehindAppearAmount()
+ }
+ }
+
+ // The end of the SmartSpace transition can occur after the keyguard is hidden (when we tell
+ // Launcher's SmartSpace to become visible again), so update it even if the keyguard view is
+ // no longer showing.
+ updateSmartSpaceTransition()
+ }
+
+ /**
+ * Lets the KeyguardViewMediator know if the dismiss amount has crossed a threshold of interest,
+ * such as reaching the point in the dismiss swipe where we need to make the surface behind the
+ * keyguard visible.
+ */
+ private fun updateKeyguardViewMediatorIfThresholdsReached() {
val dismissAmount = keyguardStateController.dismissAmount
// Hide the keyguard if we're fully dismissed, or if we're swiping to dismiss and have
// crossed the threshold to finish the dismissal.
val reachedHideKeyguardThreshold = (dismissAmount >= 1f ||
(keyguardStateController.isDismissingFromSwipe &&
- // Don't hide if we're flinging during a swipe, since we need to finish
- // animating it out. This will be called again after the fling ends.
- !keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture &&
- dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD))
+ // Don't hide if we're flinging during a swipe, since we need to finish
+ // animating it out. This will be called again after the fling ends.
+ !keyguardStateController.isFlingingToDismissKeyguardDuringSwipeGesture &&
+ dismissAmount >= DISMISS_AMOUNT_EXIT_KEYGUARD_THRESHOLD))
if (dismissAmount >= DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
!keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
- // We passed the threshold, and we're not yet showing the surface behind the keyguard.
- // Animate it in.
+ // We passed the threshold, and we're not yet showing the surface behind the
+ // keyguard. Animate it in.
keyguardViewMediator.get().showSurfaceBehindKeyguard()
fadeInSurfaceBehind()
} else if (dismissAmount < DISMISS_AMOUNT_SHOW_SURFACE_THRESHOLD &&
keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard()) {
- // We're no longer past the threshold but we are showing the surface. Animate it out.
+ // We're no longer past the threshold but we are showing the surface. Animate it
+ // out.
keyguardViewMediator.get().hideSurfaceBehindKeyguard()
fadeOutSurfaceBehind()
- } else if (keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe &&
+ } else if (keyguardViewMediator.get()
+ .isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe &&
reachedHideKeyguardThreshold) {
keyguardViewMediator.get().onKeyguardExitRemoteAnimationFinished()
}
+ }
- if (keyguardViewMediator.get().requestedShowSurfaceBehindKeyguard() ||
- keyguardViewMediator.get().isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe) {
- updateSurfaceBehindAppearAmount()
+ /**
+ * Updates flags related to the SmartSpace transition in response to a change in keyguard
+ * dismiss amount, and also updates the SmartSpaceTransitionController, which will let Launcher
+ * know if it needs to do something as a result.
+ */
+ private fun updateSmartSpaceTransition() {
+ val dismissAmount = keyguardStateController.dismissAmount
+
+ // If we've begun a swipe, and are capable of doing the SmartSpace transition, start it!
+ if (!attemptedSmartSpaceTransitionForThisSwipe &&
+ dismissAmount > 0f &&
+ dismissAmount < 1f &&
+ keyguardViewController.isShowing) {
+ attemptedSmartSpaceTransitionForThisSwipe = true
+
+ smartspaceTransitionController.prepareForUnlockTransition()
+ if (keyguardStateController.canPerformSmartSpaceTransition()) {
+ unlockingWithSmartSpaceTransition = true
+ smartspaceTransitionController.launcherSmartspace?.setVisibility(
+ View.INVISIBLE)
+ }
+ } else if (attemptedSmartSpaceTransitionForThisSwipe &&
+ (dismissAmount == 0f || dismissAmount == 1f)) {
+ attemptedSmartSpaceTransitionForThisSwipe = false
+ unlockingWithSmartSpaceTransition = false
+ smartspaceTransitionController.launcherSmartspace?.setVisibility(View.VISIBLE)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index a873abf..27a4e93 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -35,6 +35,7 @@
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.os.Bundle;
+import android.text.Layout;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
@@ -220,7 +221,7 @@
mPlayerViewHolder.getPlayer().setOnLongClickListener(v -> {
if (!mMediaViewController.isGutsVisible()) {
- mMediaViewController.openGuts();
+ openGuts();
return true;
} else {
closeGuts();
@@ -244,7 +245,7 @@
mRecommendationViewHolder.getRecommendations().setOnLongClickListener(v -> {
if (!mMediaViewController.isGutsVisible()) {
- mMediaViewController.openGuts();
+ openGuts();
return true;
} else {
return false;
@@ -433,7 +434,7 @@
// Guts label
boolean isDismissible = data.isClearable();
- mPlayerViewHolder.getSettingsText().setText(isDismissible
+ mPlayerViewHolder.getLongPressText().setText(isDismissible
? R.string.controls_media_close_session
: R.string.controls_media_active_session);
@@ -446,11 +447,8 @@
if (mKey != null) {
closeGuts();
- mKeyguardDismissUtil.executeWhenUnlocked(() -> {
- mMediaDataManagerLazy.get().dismissMediaData(mKey,
- MediaViewController.GUTS_ANIMATION_DURATION + 100);
- return true;
- }, /* requiresShadeOpen */ true, false);
+ mMediaDataManagerLazy.get().dismissMediaData(mKey,
+ MediaViewController.GUTS_ANIMATION_DURATION + 100);
} else {
Log.w(TAG, "Dismiss media with null notification. Token uid="
+ data.getToken().getUid());
@@ -575,11 +573,8 @@
logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
/* isRecommendationCard */ true);
closeGuts();
- mKeyguardDismissUtil.executeWhenUnlocked(() -> {
- mMediaDataManagerLazy.get().dismissSmartspaceRecommendation(
- MediaViewController.GUTS_ANIMATION_DURATION + 100L);
- return true;
- }, true /* requiresShadeOpen */, false);
+ mMediaDataManagerLazy.get().dismissSmartspaceRecommendation(
+ MediaViewController.GUTS_ANIMATION_DURATION + 100L);
});
mController = null;
@@ -592,6 +587,11 @@
* @param immediate {@code true} if it should be closed without animation
*/
public void closeGuts(boolean immediate) {
+ if (mPlayerViewHolder != null) {
+ mPlayerViewHolder.marquee(false, mMediaViewController.GUTS_ANIMATION_DURATION);
+ } else if (mRecommendationViewHolder != null) {
+ mRecommendationViewHolder.marquee(false, mMediaViewController.GUTS_ANIMATION_DURATION);
+ }
mMediaViewController.closeGuts(immediate);
}
@@ -599,6 +599,32 @@
closeGuts(false);
}
+ private void openGuts() {
+ ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
+ ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
+
+ boolean wasTruncated = false;
+ Layout l = null;
+ if (mPlayerViewHolder != null) {
+ mPlayerViewHolder.marquee(true, mMediaViewController.GUTS_ANIMATION_DURATION);
+ l = mPlayerViewHolder.getSettingsText().getLayout();
+ } else if (mRecommendationViewHolder != null) {
+ mRecommendationViewHolder.marquee(true, mMediaViewController.GUTS_ANIMATION_DURATION);
+ l = mRecommendationViewHolder.getSettingsText().getLayout();
+ }
+ if (l != null) {
+ wasTruncated = l.getEllipsisCount(0) > 0;
+ }
+ mMediaViewController.setShouldHideGutsSettings(wasTruncated);
+ if (wasTruncated) {
+ // not enough room for the settings button to show fully, let's hide it
+ expandedSet.constrainMaxWidth(R.id.settings, 0);
+ collapsedSet.constrainMaxWidth(R.id.settings, 0);
+ }
+
+ mMediaViewController.openGuts();
+ }
+
@UiThread
private Drawable scaleDrawable(Icon icon) {
if (icon == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 73dfe5e..075bc70 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -26,21 +26,23 @@
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroupOverlay
+import androidx.annotation.VisibleForTesting
import com.android.systemui.R
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.CrossFadeHelper
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.animation.UniqueObjectHostView
import javax.inject.Inject
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
/**
* Similarly to isShown but also excludes views that have 0 alpha
@@ -80,6 +82,7 @@
wakefulnessLifecycle: WakefulnessLifecycle,
private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager
) {
+
/**
* The root overlay of the hierarchy. This is where the media notification is attached to
* whenever the view is transitioning from one host to another. It also make sure that the
@@ -90,6 +93,30 @@
private var rootView: View? = null
private var currentBounds = Rect()
private var animationStartBounds: Rect = Rect()
+
+ /**
+ * The cross fade progress at the start of the animation. 0.5f means it's just switching between
+ * the start and the end location and the content is fully faded, while 0.75f means that we're
+ * halfway faded in again in the target state.
+ */
+ private var animationStartCrossFadeProgress = 0.0f
+
+ /**
+ * The starting alpha of the animation
+ */
+ private var animationStartAlpha = 0.0f
+
+ /**
+ * The starting location of the cross fade if an animation is running right now.
+ */
+ @MediaLocation
+ private var crossFadeAnimationStartLocation = -1
+
+ /**
+ * The end location of the cross fade if an animation is running right now.
+ */
+ @MediaLocation
+ private var crossFadeAnimationEndLocation = -1
private var targetBounds: Rect = Rect()
private val mediaFrame
get() = mediaCarouselController.mediaFrame
@@ -98,9 +125,22 @@
interpolator = Interpolators.FAST_OUT_SLOW_IN
addUpdateListener {
updateTargetState()
- interpolateBounds(animationStartBounds, targetBounds, animatedFraction,
+ val currentAlpha: Float
+ var boundsProgress = animatedFraction
+ if (isCrossFadeAnimatorRunning) {
+ animationCrossFadeProgress = MathUtils.lerp(animationStartCrossFadeProgress, 1.0f,
+ animatedFraction)
+ // When crossfading, let's keep the bounds at the right location during fading
+ boundsProgress = if (animationCrossFadeProgress < 0.5f) 0.0f else 1.0f
+ currentAlpha = calculateAlphaFromCrossFade(animationCrossFadeProgress,
+ instantlyShowAtEnd = false)
+ } else {
+ // If we're not crossfading, let's interpolate from the start alpha to 1.0f
+ currentAlpha = MathUtils.lerp(animationStartAlpha, 1.0f, animatedFraction)
+ }
+ interpolateBounds(animationStartBounds, targetBounds, boundsProgress,
result = currentBounds)
- applyState(currentBounds)
+ applyState(currentBounds, currentAlpha)
}
addListener(object : AnimatorListenerAdapter() {
private var cancelled: Boolean = false
@@ -112,6 +152,7 @@
}
override fun onAnimationEnd(animation: Animator?) {
+ isCrossFadeAnimatorRunning = false
if (!cancelled) {
applyTargetStateIfNotAnimating()
}
@@ -192,11 +233,6 @@
private var distanceForFullShadeTransition = 0
/**
- * Delay after which the media will start transitioning to the full shade on the lockscreen.
- */
- private var fullShadeTransitionDelay = 0
-
- /**
* The amount of progress we are currently in if we're transitioning to the full shade.
* 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
* shade.
@@ -207,18 +243,33 @@
return
}
field = value
- if (bypassController.bypassEnabled) {
+ if (bypassController.bypassEnabled || statusbarState != StatusBarState.KEYGUARD) {
+ // No need to do all the calculations / updates below if we're not on the lockscreen
+ // or if we're bypassing.
return
}
- updateDesiredLocation()
+ updateDesiredLocation(forceNoAnimation = isCurrentlyFading())
if (value >= 0) {
updateTargetState()
+ // Setting the alpha directly, as the below call will use it to update the alpha
+ carouselAlpha = calculateAlphaFromCrossFade(field, instantlyShowAtEnd = true)
applyTargetStateIfNotAnimating()
}
}
+ /**
+ * Is there currently a cross-fade animation running driven by an animator?
+ */
+ private var isCrossFadeAnimatorRunning = false
+
+ /**
+ * Are we currently transitionioning from the lockscreen to the full shade
+ * [StatusBarState.SHADE_LOCKED] or [StatusBarState.SHADE]. Once the user has dragged down and
+ * the transition starts, this will no longer return true.
+ */
private val isTransitioningToFullShade: Boolean
- get() = fullShadeTransitionProgress != 0f && !bypassController.bypassEnabled
+ get() = fullShadeTransitionProgress != 0f && !bypassController.bypassEnabled &&
+ statusbarState == StatusBarState.KEYGUARD
/**
* Set the amount of pixels we have currently dragged down if we're transitioning to the full
@@ -227,14 +278,8 @@
fun setTransitionToFullShadeAmount(value: Float) {
// If we're transitioning starting on the shade_locked, we don't want any delay and rather
// have it aligned with the rest of the animation
- val delay = if (statusbarState == StatusBarState.KEYGUARD) {
- fullShadeTransitionDelay
- } else {
- 0
- }
- val progress = MathUtils.saturate((value - delay) /
- (distanceForFullShadeTransition - delay))
- fullShadeTransitionProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(progress)
+ val progress = MathUtils.saturate(value / distanceForFullShadeTransition)
+ fullShadeTransitionProgress = progress
}
/**
@@ -296,6 +341,49 @@
}
}
+ /**
+ * The current cross fade progress. 0.5f means it's just switching
+ * between the start and the end location and the content is fully faded, while 0.75f means
+ * that we're halfway faded in again in the target state.
+ * This is only valid while [isCrossFadeAnimatorRunning] is true.
+ */
+ private var animationCrossFadeProgress = 1.0f
+
+ /**
+ * The current carousel Alpha.
+ */
+ private var carouselAlpha: Float = 1.0f
+ set(value) {
+ if (field == value) {
+ return
+ }
+ field = value
+ CrossFadeHelper.fadeIn(mediaFrame, value)
+ }
+
+ /**
+ * Calculate the alpha of the view when given a cross-fade progress.
+ *
+ * @param crossFadeProgress The current cross fade progress. 0.5f means it's just switching
+ * between the start and the end location and the content is fully faded, while 0.75f means
+ * that we're halfway faded in again in the target state.
+ *
+ * @param instantlyShowAtEnd should the view be instantly shown at the end. This is needed
+ * to avoid fadinging in when the target was hidden anyway.
+ */
+ private fun calculateAlphaFromCrossFade(
+ crossFadeProgress: Float,
+ instantlyShowAtEnd: Boolean
+ ): Float {
+ if (crossFadeProgress <= 0.5f) {
+ return 1.0f - crossFadeProgress / 0.5f
+ } else if (instantlyShowAtEnd) {
+ return 1.0f
+ } else {
+ return (crossFadeProgress - 0.5f) / 0.5f
+ }
+ }
+
init {
updateConfiguration()
configurationController.addCallback(object : ConfigurationController.ConfigurationListener {
@@ -375,9 +463,7 @@
private fun updateConfiguration() {
distanceForFullShadeTransition = context.resources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_qs_transition_distance)
- fullShadeTransitionDelay = context.resources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_media_transition_start_delay)
+ R.dimen.lockscreen_shade_media_transition_distance)
}
/**
@@ -449,8 +535,13 @@
shouldAnimateTransition(desiredLocation, previousLocation)
val (animDuration, delay) = getAnimationParams(previousLocation, desiredLocation)
val host = getHost(desiredLocation)
- mediaCarouselController.onDesiredLocationChanged(desiredLocation, host, animate,
- animDuration, delay)
+ val willFade = calculateTransformationType() == TRANSFORMATION_TYPE_FADE
+ if (!willFade || isCurrentlyInGuidedTransformation() || !animate) {
+ // if we're fading, we want the desired location / measurement only to change
+ // once fully faded. This is happening in the host attachment
+ mediaCarouselController.onDesiredLocationChanged(desiredLocation, host,
+ animate, animDuration, delay)
+ }
performTransitionToNewLocation(isNewView, animate)
}
}
@@ -470,6 +561,8 @@
if (isCurrentlyInGuidedTransformation()) {
applyTargetStateIfNotAnimating()
} else if (animate) {
+ val wasCrossFading = isCrossFadeAnimatorRunning
+ val previewsCrossFadeProgress = animationCrossFadeProgress
animator.cancel()
if (currentAttachmentLocation != previousLocation ||
!previousHost.hostView.isAttachedToWindow) {
@@ -482,6 +575,42 @@
// be outdated
animationStartBounds.set(previousHost.currentBounds)
}
+ val transformationType = calculateTransformationType()
+ var needsCrossFade = transformationType == TRANSFORMATION_TYPE_FADE
+ var crossFadeStartProgress = 0.0f
+ // The alpha is only relevant when not cross fading
+ var newCrossFadeStartLocation = previousLocation
+ if (wasCrossFading) {
+ if (currentAttachmentLocation == crossFadeAnimationEndLocation) {
+ if (needsCrossFade) {
+ // We were previously crossFading and we've already reached
+ // the end view, Let's start crossfading from the same position there
+ crossFadeStartProgress = 1.0f - previewsCrossFadeProgress
+ }
+ // Otherwise let's fade in from the current alpha, but not cross fade
+ } else {
+ // We haven't reached the previous location yet, let's still cross fade from
+ // where we were.
+ newCrossFadeStartLocation = crossFadeAnimationStartLocation
+ if (newCrossFadeStartLocation == desiredLocation) {
+ // we're crossFading back to where we were, let's start at the end position
+ crossFadeStartProgress = 1.0f - previewsCrossFadeProgress
+ } else {
+ // Let's start from where we are right now
+ crossFadeStartProgress = previewsCrossFadeProgress
+ // We need to force cross fading as we haven't reached the end location yet
+ needsCrossFade = true
+ }
+ }
+ } else if (needsCrossFade) {
+ // let's not flicker and start with the same alpha
+ crossFadeStartProgress = (1.0f - carouselAlpha) / 2.0f
+ }
+ isCrossFadeAnimatorRunning = needsCrossFade
+ crossFadeAnimationStartLocation = newCrossFadeStartLocation
+ crossFadeAnimationEndLocation = desiredLocation
+ animationStartAlpha = carouselAlpha
+ animationStartCrossFadeProgress = crossFadeStartProgress
adjustAnimatorForTransition(desiredLocation, previousLocation)
if (!animationPending) {
rootView?.let {
@@ -518,6 +647,17 @@
// non-trivial reattaching logic happening that will make the view not-shown earlier
return true
}
+
+ if (statusbarState == StatusBarState.KEYGUARD) {
+ if (currentLocation == LOCATION_LOCKSCREEN &&
+ previousLocation == LOCATION_QS ||
+ (currentLocation == LOCATION_QS &&
+ previousLocation == LOCATION_LOCKSCREEN)) {
+ // We're always fading from lockscreen to keyguard in situations where the player
+ // is already fully hidden
+ return false
+ }
+ }
return mediaFrame.isShownNotFaded || animator.isRunning || animationPending
}
@@ -538,7 +678,7 @@
keyguardStateController.isKeyguardFadingAway) {
delay = keyguardStateController.keyguardFadingAwayDelay
}
- animDuration = StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE.toLong()
+ animDuration = (StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE / 2f).toLong()
} else if (previousLocation == LOCATION_QQS && desiredLocation == LOCATION_LOCKSCREEN) {
animDuration = StackStateAnimator.ANIMATION_DURATION_APPEAR_DISAPPEAR.toLong()
}
@@ -550,7 +690,7 @@
// Let's immediately apply the target state (which is interpolated) if there is
// no animation running. Otherwise the animation update will already update
// the location
- applyState(targetBounds)
+ applyState(targetBounds, carouselAlpha)
}
}
@@ -558,7 +698,7 @@
* Updates the bounds that the view wants to be in at the end of the animation.
*/
private fun updateTargetState() {
- if (isCurrentlyInGuidedTransformation()) {
+ if (isCurrentlyInGuidedTransformation() && !isCurrentlyFading()) {
val progress = getTransformationProgress()
var endHost = getHost(desiredLocation)!!
var starthost = getHost(previousLocation)!!
@@ -606,12 +746,33 @@
}
/**
+ * Calculate the transformation type for the current animation
+ */
+ @VisibleForTesting
+ @TransformationType
+ fun calculateTransformationType(): Int {
+ if (isTransitioningToFullShade) {
+ return TRANSFORMATION_TYPE_FADE
+ }
+ if (previousLocation == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QS ||
+ previousLocation == LOCATION_QS && desiredLocation == LOCATION_LOCKSCREEN) {
+ // animating between ls and qs should fade, as QS is clipped.
+ return TRANSFORMATION_TYPE_FADE
+ }
+ if (previousLocation == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QQS) {
+ // animating between ls and qqs should fade when dragging down via e.g. expand button
+ return TRANSFORMATION_TYPE_FADE
+ }
+ return TRANSFORMATION_TYPE_TRANSITION
+ }
+
+ /**
* @return the current transformation progress if we're in a guided transformation and -1
* otherwise
*/
private fun getTransformationProgress(): Float {
val progress = getQSTransformationProgress()
- if (progress >= 0) {
+ if (statusbarState != StatusBarState.KEYGUARD && progress >= 0) {
return progress
}
if (isTransitioningToFullShade) {
@@ -643,19 +804,20 @@
private fun cancelAnimationAndApplyDesiredState() {
animator.cancel()
getHost(desiredLocation)?.let {
- applyState(it.currentBounds, immediately = true)
+ applyState(it.currentBounds, alpha = 1.0f, immediately = true)
}
}
/**
* Apply the current state to the view, updating it's bounds and desired state
*/
- private fun applyState(bounds: Rect, immediately: Boolean = false) {
+ private fun applyState(bounds: Rect, alpha: Float, immediately: Boolean = false) {
currentBounds.set(bounds)
- val currentlyInGuidedTransformation = isCurrentlyInGuidedTransformation()
- val startLocation = if (currentlyInGuidedTransformation) previousLocation else -1
- val progress = if (currentlyInGuidedTransformation) getTransformationProgress() else 1.0f
- val endLocation = desiredLocation
+ carouselAlpha = if (isCurrentlyFading()) alpha else 1.0f
+ val onlyUseEndState = !isCurrentlyInGuidedTransformation() || isCurrentlyFading()
+ val startLocation = if (onlyUseEndState) -1 else previousLocation
+ val progress = if (onlyUseEndState) 1.0f else getTransformationProgress()
+ val endLocation = resolveLocationForFading()
mediaCarouselController.setCurrentState(startLocation, endLocation, progress, immediately)
updateHostAttachment()
if (currentAttachmentLocation == IN_OVERLAY) {
@@ -668,8 +830,19 @@
}
private fun updateHostAttachment() {
- val inOverlay = isTransitionRunning() && rootOverlay != null
- val newLocation = if (inOverlay) IN_OVERLAY else desiredLocation
+ var newLocation = resolveLocationForFading()
+ var canUseOverlay = !isCurrentlyFading()
+ if (isCrossFadeAnimatorRunning) {
+ if (getHost(newLocation)?.visible == true &&
+ getHost(newLocation)?.hostView?.isShown == false &&
+ newLocation != desiredLocation) {
+ // We're crossfading but the view is already hidden. Let's move to the overlay
+ // instead. This happens when animating to the full shade using a button click.
+ canUseOverlay = true
+ }
+ }
+ val inOverlay = isTransitionRunning() && rootOverlay != null && canUseOverlay
+ newLocation = if (inOverlay) IN_OVERLAY else newLocation
if (currentAttachmentLocation != newLocation) {
currentAttachmentLocation = newLocation
@@ -677,10 +850,10 @@
(mediaFrame.parent as ViewGroup?)?.removeView(mediaFrame)
// Add it to the new one
- val targetHost = getHost(desiredLocation)!!.hostView
if (inOverlay) {
rootOverlay!!.add(mediaFrame)
} else {
+ val targetHost = getHost(newLocation)!!.hostView
// When adding back to the host, let's make sure to reset the bounds.
// Usually adding the view will trigger a layout that does this automatically,
// but we sometimes suppress this.
@@ -693,9 +866,39 @@
left + currentBounds.width(),
top + currentBounds.height())
}
+ if (isCrossFadeAnimatorRunning) {
+ // When cross-fading with an animation, we only notify the media carousel of the
+ // location change, once the view is reattached to the new place and not immediately
+ // when the desired location changes. This callback will update the measurement
+ // of the carousel, only once we've faded out at the old location and then reattach
+ // to fade it in at the new location.
+ mediaCarouselController.onDesiredLocationChanged(
+ newLocation,
+ getHost(newLocation),
+ animate = false
+ )
+ }
}
}
+ /**
+ * Calculate the location when cross fading between locations. While fading out,
+ * the content should remain in the previous location, while after the switch it should
+ * be at the desired location.
+ */
+ private fun resolveLocationForFading(): Int {
+ if (isCrossFadeAnimatorRunning) {
+ // When animating between two hosts with a fade, let's keep ourselves in the old
+ // location for the first half, and then switch over to the end location
+ if (animationCrossFadeProgress > 0.5 || previousLocation == -1) {
+ return crossFadeAnimationEndLocation
+ } else {
+ return crossFadeAnimationStartLocation
+ }
+ }
+ return desiredLocation
+ }
+
private fun isTransitionRunning(): Boolean {
return isCurrentlyInGuidedTransformation() && getTransformationProgress() != 1.0f ||
animator.isRunning || animationPending
@@ -708,29 +911,29 @@
return desiredLocation
}
val onLockscreen = (!bypassController.bypassEnabled &&
- (statusbarState == StatusBarState.KEYGUARD ||
- statusbarState == StatusBarState.FULLSCREEN_USER_SWITCHER))
+ (statusbarState == StatusBarState.KEYGUARD ||
+ statusbarState == StatusBarState.FULLSCREEN_USER_SWITCHER))
val allowedOnLockscreen = notifLockscreenUserManager.shouldShowLockscreenNotifications()
val location = when {
qsExpansion > 0.0f && !onLockscreen -> LOCATION_QS
qsExpansion > 0.4f && onLockscreen -> LOCATION_QS
- onLockscreen && isTransitioningToFullShade -> LOCATION_QQS
+ onLockscreen && isTransformingToFullShadeAndInQQS() -> LOCATION_QQS
onLockscreen && allowedOnLockscreen -> LOCATION_LOCKSCREEN
else -> LOCATION_QQS
}
// When we're on lock screen and the player is not active, we should keep it in QS.
// Otherwise it will try to animate a transition that doesn't make sense.
if (location == LOCATION_LOCKSCREEN && getHost(location)?.visible != true &&
- !statusBarStateController.isDozing) {
+ !statusBarStateController.isDozing) {
return LOCATION_QS
}
if (location == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QS &&
- collapsingShadeFromQS) {
+ collapsingShadeFromQS) {
// When collapsing on the lockscreen, we want to remain in QS
return LOCATION_QS
}
if (location != LOCATION_LOCKSCREEN && desiredLocation == LOCATION_LOCKSCREEN &&
- !fullyAwake) {
+ !fullyAwake) {
// When unlocking from dozing / while waking up, the media shouldn't be transitioning
// in an animated way. Let's keep it in the lockscreen until we're fully awake and
// reattach it without an animation
@@ -740,6 +943,26 @@
}
/**
+ * Are we currently transforming to the full shade and already in QQS
+ */
+ private fun isTransformingToFullShadeAndInQQS(): Boolean {
+ if (!isTransitioningToFullShade) {
+ return false
+ }
+ return fullShadeTransitionProgress > 0.5f
+ }
+
+ /**
+ * Is the current transformationType fading
+ */
+ private fun isCurrentlyFading(): Boolean {
+ if (isTransitioningToFullShade) {
+ return true
+ }
+ return isCrossFadeAnimatorRunning
+ }
+
+ /**
* Returns true when the media card could be visible to the user if existed.
*/
private fun isVisibleToUser(): Boolean {
@@ -789,9 +1012,27 @@
* Attached at the root of the hierarchy in an overlay
*/
const val IN_OVERLAY = -1000
+
+ /**
+ * The default transformation type where the hosts transform into each other using a direct
+ * transition
+ */
+ const val TRANSFORMATION_TYPE_TRANSITION = 0
+
+ /**
+ * A transformation type where content fades from one place to another instead of
+ * transitioning
+ */
+ const val TRANSFORMATION_TYPE_FADE = 1
}
}
+@IntDef(prefix = ["TRANSFORMATION_TYPE_"], value = [
+ MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION,
+ MediaHierarchyManager.TRANSFORMATION_TYPE_FADE])
+@Retention(AnnotationRetention.SOURCE)
+private annotation class TransformationType
+
@IntDef(prefix = ["LOCATION_"], value = [MediaHierarchyManager.LOCATION_QS,
MediaHierarchyManager.LOCATION_QQS, MediaHierarchyManager.LOCATION_LOCKSCREEN])
@Retention(AnnotationRetention.SOURCE)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
index 7ba42b3..7fe408f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
@@ -23,7 +23,6 @@
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.media.MediaDescription
-import android.media.session.MediaController
import android.os.UserHandle
import android.provider.Settings
import android.service.media.MediaBrowserService
@@ -160,6 +159,7 @@
if (useMediaResumption) {
// If this had been started from a resume state, disconnect now that it's live
mediaBrowser?.disconnect()
+ mediaBrowser = null
// If we don't have a resume action, check if we haven't already
if (data.resumeAction == null && !data.hasCheckedForResume && data.isLocalSession) {
// TODO also check for a media button receiver intended for restarting (b/154127084)
@@ -189,7 +189,6 @@
*/
private fun tryUpdateResumptionList(key: String, componentName: ComponentName) {
Log.d(TAG, "Testing if we can connect to $componentName")
- mediaBrowser?.disconnect()
mediaBrowser = mediaBrowserFactory.create(
object : ResumeMediaBrowser.Callback() {
override fun onConnected() {
@@ -199,7 +198,6 @@
override fun onError() {
Log.e(TAG, "Cannot resume with $componentName")
mediaDataManager.setResumeAction(key, null)
- mediaBrowser?.disconnect()
mediaBrowser = null
}
@@ -212,7 +210,6 @@
Log.d(TAG, "Can get resumable media from $componentName")
mediaDataManager.setResumeAction(key, getResumeAction(componentName))
updateResumptionList(componentName)
- mediaBrowser?.disconnect()
mediaBrowser = null
}
},
@@ -250,30 +247,7 @@
*/
private fun getResumeAction(componentName: ComponentName): Runnable {
return Runnable {
- mediaBrowser?.disconnect()
- mediaBrowser = mediaBrowserFactory.create(
- object : ResumeMediaBrowser.Callback() {
- override fun onConnected() {
- if (mediaBrowser?.token == null) {
- Log.e(TAG, "Error after connect")
- mediaBrowser?.disconnect()
- mediaBrowser = null
- return
- }
- Log.d(TAG, "Connected for restart $componentName")
- val controller = MediaController(context, mediaBrowser!!.token)
- val controls = controller.transportControls
- controls.prepare()
- controls.play()
- }
-
- override fun onError() {
- Log.e(TAG, "Resume failed for $componentName")
- mediaBrowser?.disconnect()
- mediaBrowser = null
- }
- },
- componentName)
+ mediaBrowser = mediaBrowserFactory.create(null, componentName)
mediaBrowser?.restart()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index 50d6e12..3681a2a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -185,6 +185,11 @@
var isGutsVisible = false
private set
+ /**
+ * Whether the settings button in the guts should be visible
+ */
+ var shouldHideGutsSettings = false
+
init {
mediaHostStatesManager.addController(this)
layoutController.sizeChangedListener = { width: Int, height: Int ->
@@ -277,6 +282,9 @@
viewState.widgetStates.get(id)?.gone = !isGutsVisible
}
}
+ if (shouldHideGutsSettings) {
+ viewState.widgetStates.get(R.id.settings)?.gone = true
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
index 08d8726..791f59d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
@@ -59,11 +59,12 @@
val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
// Settings screen
- val settingsText = itemView.requireViewById<TextView>(R.id.remove_text)
+ val longPressText = itemView.requireViewById<TextView>(R.id.remove_text)
val cancel = itemView.requireViewById<View>(R.id.cancel)
val dismiss = itemView.requireViewById<ViewGroup>(R.id.dismiss)
val dismissLabel = dismiss.getChildAt(0)
val settings = itemView.requireViewById<View>(R.id.settings)
+ val settingsText = itemView.requireViewById<TextView>(R.id.settings_text)
init {
(player.background as IlluminationDrawable).let {
@@ -92,6 +93,10 @@
}
}
+ fun marquee(start: Boolean, delay: Long) {
+ longPressText.getHandler().postDelayed({ longPressText.setSelected(start) }, delay)
+ }
+
companion object {
/**
* Creates a PlayerViewHolder.
diff --git a/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt
index a3f9910..78619d6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt
@@ -49,10 +49,12 @@
R.id.media_cover6)
// Settings/Guts screen
+ val longPressText = itemView.requireViewById<TextView>(R.id.remove_text)
val cancel = itemView.requireViewById<View>(R.id.cancel)
val dismiss = itemView.requireViewById<ViewGroup>(R.id.dismiss)
val dismissLabel = dismiss.getChildAt(0)
val settings = itemView.requireViewById<View>(R.id.settings)
+ val settingsText = itemView.requireViewById<TextView>(R.id.settings_text)
init {
(recommendations.background as IlluminationDrawable).let { background ->
@@ -64,6 +66,10 @@
}
}
+ fun marquee(start: Boolean, delay: Long) {
+ longPressText.getHandler().postDelayed({ longPressText.setSelected(start) }, delay)
+ }
+
companion object {
/**
* Creates a RecommendationViewHolder.
diff --git a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
index e453653..fecc903 100644
--- a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
+++ b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
@@ -16,6 +16,7 @@
package com.android.systemui.media;
+import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -47,7 +48,7 @@
private static final String TAG = "ResumeMediaBrowser";
private final Context mContext;
- private final Callback mCallback;
+ @Nullable private final Callback mCallback;
private MediaBrowserFactory mBrowserFactory;
private MediaBrowser mMediaBrowser;
private ComponentName mComponentName;
@@ -58,8 +59,8 @@
* @param callback used to report media items found
* @param componentName Component name of the MediaBrowserService this browser will connect to
*/
- public ResumeMediaBrowser(Context context, Callback callback, ComponentName componentName,
- MediaBrowserFactory browserFactory) {
+ public ResumeMediaBrowser(Context context, @Nullable Callback callback,
+ ComponentName componentName, MediaBrowserFactory browserFactory) {
mContext = context;
mCallback = callback;
mComponentName = componentName;
@@ -93,18 +94,24 @@
List<MediaBrowser.MediaItem> children) {
if (children.size() == 0) {
Log.d(TAG, "No children found for " + mComponentName);
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
} else {
// We ask apps to return a playable item as the first child when sending
// a request with EXTRA_RECENT; if they don't, no resume controls
MediaBrowser.MediaItem child = children.get(0);
MediaDescription desc = child.getDescription();
if (child.isPlayable() && mMediaBrowser != null) {
- mCallback.addTrack(desc, mMediaBrowser.getServiceComponent(),
- ResumeMediaBrowser.this);
+ if (mCallback != null) {
+ mCallback.addTrack(desc, mMediaBrowser.getServiceComponent(),
+ ResumeMediaBrowser.this);
+ }
} else {
Log.d(TAG, "Child found but not playable for " + mComponentName);
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
}
}
disconnect();
@@ -113,7 +120,9 @@
@Override
public void onError(String parentId) {
Log.d(TAG, "Subscribe error for " + mComponentName + ": " + parentId);
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
disconnect();
}
@@ -121,7 +130,9 @@
public void onError(String parentId, Bundle options) {
Log.d(TAG, "Subscribe error for " + mComponentName + ": " + parentId
+ ", options: " + options);
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
disconnect();
}
};
@@ -138,13 +149,20 @@
Log.d(TAG, "Service connected for " + mComponentName);
if (mMediaBrowser != null && mMediaBrowser.isConnected()) {
String root = mMediaBrowser.getRoot();
- if (!TextUtils.isEmpty(root) && mMediaBrowser != null) {
- mCallback.onConnected();
- mMediaBrowser.subscribe(root, mSubscriptionCallback);
+ if (!TextUtils.isEmpty(root)) {
+ if (mCallback != null) {
+ mCallback.onConnected();
+ }
+ if (mMediaBrowser != null) {
+ mMediaBrowser.subscribe(root, mSubscriptionCallback);
+ }
return;
}
}
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
+ disconnect();
}
/**
@@ -153,7 +171,9 @@
@Override
public void onConnectionSuspended() {
Log.d(TAG, "Connection suspended for " + mComponentName);
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
disconnect();
}
@@ -163,16 +183,18 @@
@Override
public void onConnectionFailed() {
Log.d(TAG, "Connection failed for " + mComponentName);
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
disconnect();
}
};
/**
- * Disconnect the media browser. This should be called after restart or testConnection have
- * completed to close the connection.
+ * Disconnect the media browser. This should be done after callbacks have completed to
+ * disconnect from the media browser service.
*/
- public void disconnect() {
+ protected void disconnect() {
if (mMediaBrowser != null) {
mMediaBrowser.disconnect();
}
@@ -183,7 +205,8 @@
* Connects to the MediaBrowserService and starts playback.
* ResumeMediaBrowser.Callback#onError or ResumeMediaBrowser.Callback#onConnected will be called
* depending on whether it was successful.
- * ResumeMediaBrowser#disconnect should be called after this to ensure the connection is closed.
+ * If the connection is successful, the listener should call ResumeMediaBrowser#disconnect after
+ * getting a media update from the app
*/
public void restart() {
disconnect();
@@ -195,7 +218,10 @@
public void onConnected() {
Log.d(TAG, "Connected for restart " + mMediaBrowser.isConnected());
if (mMediaBrowser == null || !mMediaBrowser.isConnected()) {
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
+ disconnect();
return;
}
MediaSession.Token token = mMediaBrowser.getSessionToken();
@@ -203,17 +229,26 @@
controller.getTransportControls();
controller.getTransportControls().prepare();
controller.getTransportControls().play();
- mCallback.onConnected();
+ if (mCallback != null) {
+ mCallback.onConnected();
+ }
+ // listener should disconnect after media player update
}
@Override
public void onConnectionFailed() {
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
+ disconnect();
}
@Override
public void onConnectionSuspended() {
- mCallback.onError();
+ if (mCallback != null) {
+ mCallback.onError();
+ }
+ disconnect();
}
}, rootHints);
mMediaBrowser.connect();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 9e77b60..d8b342a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -31,6 +31,7 @@
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
@@ -200,7 +201,7 @@
private final UiEventLogger mUiEventLogger;
private Bundle mSavedState;
- private NavigationBarView mNavigationBarView = null;
+ private NavigationBarView mNavigationBarView;
private @WindowVisibleState int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
@@ -392,7 +393,8 @@
};
private final Runnable mAutoDim = () -> getBarTransitions().setAutoDim(true);
-
+ private final Runnable mEnableLayoutTransitions = () ->
+ mNavigationBarView.setLayoutTransitionsEnabled(true);
private final Runnable mOnVariableDurationHomeLongClick = () -> {
if (onHomeLongClick(mNavigationBarView.getHomeButton().getCurrentView())) {
mNavigationBarView.getHomeButton().getCurrentView().performHapticFeedback(
@@ -488,7 +490,7 @@
mA11yBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
}
- public View getView() {
+ public NavigationBarView getView() {
return mNavigationBarView;
}
@@ -504,16 +506,19 @@
| WindowManager.LayoutParams.FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
lp.token = new Binder();
- lp.setTitle("NavigationBar" + mContext.getDisplayId());
lp.accessibilityTitle = mContext.getString(R.string.nav_bar);
- lp.windowAnimations = 0;
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
+ lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ lp.windowAnimations = 0;
+ lp.setTitle("NavigationBar" + mContext.getDisplayId());
+ lp.setFitInsetsTypes(0 /* types */);
NavigationBarFrame frame = (NavigationBarFrame) LayoutInflater.from(mContext).inflate(
R.layout.navigation_bar_window, null);
View barView = LayoutInflater.from(frame.getContext()).inflate(
R.layout.navigation_bar, frame);
barView.addOnAttachStateChangeListener(this);
+ mNavigationBarView = barView.findViewById(R.id.navigation_bar_view);
if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + barView);
mContext.getSystemService(WindowManager.class).addView(frame, lp);
@@ -533,6 +538,19 @@
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED),
false, mAssistContentObserver, UserHandle.USER_ALL);
+ mAllowForceNavBarHandleOpaque = mContext.getResources().getBoolean(
+ R.bool.allow_force_nav_bar_handle_opaque);
+ mForceNavBarHandleOpaque = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ NAV_BAR_HANDLE_FORCE_OPAQUE,
+ /* defaultValue = */ true);
+ mHomeButtonLongPressDurationMs = Optional.of(DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_SYSTEMUI,
+ HOME_BUTTON_LONG_PRESS_DURATION_MS,
+ /* defaultValue = */ 0
+ )).filter(duration -> duration != 0);
+ DeviceConfig.addOnPropertiesChangedListener(
+ DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, mOnPropertiesChangedListener);
updateAssistantEntrypoints();
if (savedState != null) {
@@ -543,25 +561,10 @@
mTransientShown = savedState.getBoolean(EXTRA_TRANSIENT_STATE, false);
}
mSavedState = savedState;
- mAccessibilityManagerWrapper.addCallback(mAccessibilityListener);
// Respect the latest disabled-flags.
mCommandQueue.recomputeDisableFlags(mDisplayId, false);
- mAllowForceNavBarHandleOpaque = mContext.getResources().getBoolean(
- R.bool.allow_force_nav_bar_handle_opaque);
- mForceNavBarHandleOpaque = DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- NAV_BAR_HANDLE_FORCE_OPAQUE,
- /* defaultValue = */ true);
- mHomeButtonLongPressDurationMs = Optional.of(DeviceConfig.getLong(
- DeviceConfig.NAMESPACE_SYSTEMUI,
- HOME_BUTTON_LONG_PRESS_DURATION_MS,
- /* defaultValue = */ 0
- )).filter(duration -> duration != 0);
- DeviceConfig.addOnPropertiesChangedListener(
- DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, mOnPropertiesChangedListener);
-
mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
mDeviceProvisionedController.addCallback(mUserSetupListener);
@@ -587,7 +590,6 @@
@Override
public void onViewAttachedToWindow(View v) {
final Display display = v.getDisplay();
- mNavigationBarView = v.findViewById(R.id.navigation_bar_view);
mNavigationBarView.setComponents(mStatusBarLazy.get().getPanelController());
mNavigationBarView.setDisabledFlags(mDisabledFlags1);
mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
@@ -598,6 +600,9 @@
mNavigationBarView.setNavigationIconHints(mNavigationIconHints);
mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
mNavigationBarView.setBehavior(mBehavior);
+
+ mAccessibilityManagerWrapper.addCallback(mAccessibilityListener);
+
mSplitScreenOptional.ifPresent(mNavigationBarView::registerDockedListener);
mPipOptional.ifPresent(mNavigationBarView::registerPipExclusionBoundsChangeListener);
@@ -657,10 +662,8 @@
@Override
public void onViewDetachedFromWindow(View v) {
- if (mNavigationBarView != null) {
- mNavigationBarView.getBarTransitions().destroy();
- mNavigationBarView.getLightTransitionsController().destroy(mContext);
- }
+ mNavigationBarView.getBarTransitions().destroy();
+ mNavigationBarView.getLightTransitionsController().destroy(mContext);
mOverviewProxyService.removeCallback(mOverviewProxyListener);
mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
if (mOrientationHandle != null) {
@@ -671,6 +674,8 @@
mOrientationHandleGlobalLayoutListener);
}
mHandler.removeCallbacks(mAutoDim);
+ mHandler.removeCallbacks(mOnVariableDurationHomeLongClick);
+ mHandler.removeCallbacks(mEnableLayoutTransitions);
mNavigationBarView = null;
mOrientationHandle = null;
}
@@ -682,9 +687,7 @@
outState.putInt(EXTRA_APPEARANCE, mAppearance);
outState.putInt(EXTRA_BEHAVIOR, mBehavior);
outState.putBoolean(EXTRA_TRANSIENT_STATE, mTransientShown);
- if (mNavigationBarView != null) {
- mNavigationBarView.getLightTransitionsController().saveState(outState);
- }
+ mNavigationBarView.getLightTransitionsController().saveState(outState);
}
/**
@@ -809,15 +812,12 @@
// mOrientedHandle is initialized lazily
mOrientationHandle.setVisibility(View.GONE);
}
- if (mNavigationBarView != null) {
- mNavigationBarView.setVisibility(View.VISIBLE);
- mNavigationBarView.setOrientedHandleSamplingRegion(null);
- }
+ mNavigationBarView.setVisibility(View.VISIBLE);
+ mNavigationBarView.setOrientedHandleSamplingRegion(null);
}
private void reconfigureHomeLongClick() {
- if (mNavigationBarView == null
- || mNavigationBarView.getHomeButton().getCurrentView() == null) {
+ if (mNavigationBarView.getHomeButton().getCurrentView() == null) {
return;
}
if (mHomeButtonLongPressDurationMs.isPresent() || !mLongPressHomeEnabled) {
@@ -844,17 +844,12 @@
pw.println(" mHomeButtonLongPressDurationMs=" + mHomeButtonLongPressDurationMs);
pw.println(" mLongPressHomeEnabled=" + mLongPressHomeEnabled);
pw.println(" mAssistantTouchGestureEnabled=" + mAssistantTouchGestureEnabled);
-
- if (mNavigationBarView != null) {
- pw.println(" mNavigationBarWindowState="
- + windowStateToString(mNavigationBarWindowState));
- pw.println(" mNavigationBarMode="
- + BarTransitions.modeToString(mNavigationBarMode));
- dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
- mNavigationBarView.dump(pw);
- } else {
- pw.print(" mNavigationBarView=null");
- }
+ pw.println(" mNavigationBarWindowState="
+ + windowStateToString(mNavigationBarWindowState));
+ pw.println(" mNavigationBarMode="
+ + BarTransitions.modeToString(mNavigationBarMode));
+ dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
+ mNavigationBarView.dump(pw);
}
// ----- CommandQueue Callbacks -----
@@ -889,10 +884,7 @@
if (hints == mNavigationIconHints) return;
mNavigationIconHints = hints;
-
- if (mNavigationBarView != null) {
- mNavigationBarView.setNavigationIconHints(hints);
- }
+ mNavigationBarView.setNavigationIconHints(hints);
checkBarModes();
updateSystemUiStateFlags(-1);
}
@@ -911,23 +903,12 @@
orientSecondaryHomeHandle();
}
if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
-
- if (mNavigationBarView != null) {
- mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
- }
+ mNavigationBarView.setWindowVisible(isNavBarWindowVisible());
}
}
@Override
public void onRotationProposal(final int rotation, boolean isValid) {
- if (mNavigationBarView == null) {
- if (RotationContextButton.DEBUG_ROTATION) {
- Log.v(TAG, "onRotationProposal proposedRotation=" +
- Surface.rotationToString(rotation) + ", mNavigationBarView is null");
- }
- return;
- }
-
final int winRotation = mNavigationBarView.getDisplay().getRotation();
final boolean rotateSuggestionsDisabled = RotationButtonController
.hasDisable2RotateSuggestionFlag(mDisabledFlags2);
@@ -941,8 +922,7 @@
+ ", isValid=" + isValid + ", mNavBarWindowState="
+ StatusBarManager.windowStateToString(mNavigationBarWindowState)
+ ", rotateSuggestionsDisabled=" + rotateSuggestionsDisabled
- + ", isRotateButtonVisible=" + (mNavigationBarView == null ? "null"
- : rotationButton.isVisible()));
+ + ", isRotateButtonVisible=" + rotationButton.isVisible());
}
// Respect the disabled flag, no need for action as flag change callback will handle hiding
@@ -983,9 +963,6 @@
boolean nbModeChanged = false;
if (mAppearance != appearance) {
mAppearance = appearance;
- if (getView() == null) {
- return;
- }
nbModeChanged = updateBarMode(barMode(mTransientShown, appearance));
}
if (mLightBarController != null) {
@@ -994,9 +971,7 @@
}
if (mBehavior != behavior) {
mBehavior = behavior;
- if (mNavigationBarView != null) {
- mNavigationBarView.setBehavior(behavior);
- }
+ mNavigationBarView.setBehavior(behavior);
updateSystemUiStateFlags(-1);
}
}
@@ -1034,12 +1009,7 @@
}
private void handleTransientChanged() {
- if (getView() == null) {
- return;
- }
- if (mNavigationBarView != null) {
- mNavigationBarView.onTransientStateChanged(mTransientShown);
- }
+ mNavigationBarView.onTransientStateChanged(mTransientShown);
final int barMode = barMode(mTransientShown, mAppearance);
if (updateBarMode(barMode) && mLightBarController != null) {
mLightBarController.onNavigationBarModeChanged(barMode);
@@ -1092,9 +1062,7 @@
| StatusBarManager.DISABLE_SEARCH);
if (masked != mDisabledFlags1) {
mDisabledFlags1 = masked;
- if (mNavigationBarView != null) {
- mNavigationBarView.setDisabledFlags(state1);
- }
+ mNavigationBarView.setDisabledFlags(state1);
updateScreenPinningGestures();
}
@@ -1110,17 +1078,13 @@
private void setDisabled2Flags(int state2) {
// Method only called on change of disable2 flags
- if (mNavigationBarView != null) {
- mNavigationBarView.getRotationButtonController().onDisable2FlagChanged(state2);
- }
+ mNavigationBarView.getRotationButtonController().onDisable2FlagChanged(state2);
}
// ----- Internal stuff -----
private void refreshLayout(int layoutDirection) {
- if (mNavigationBarView != null) {
- mNavigationBarView.setLayoutDirection(layoutDirection);
- }
+ mNavigationBarView.setLayoutDirection(layoutDirection);
}
private boolean shouldDisableNavbarGestures() {
@@ -1129,7 +1093,7 @@
}
private void repositionNavigationBar() {
- if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
+ if (!mNavigationBarView.isAttachedToWindow()) return;
prepareNavigationBarView();
@@ -1138,10 +1102,6 @@
}
private void updateScreenPinningGestures() {
- if (mNavigationBarView == null) {
- return;
- }
-
// Change the cancel pin gesture to home and back if recents button is invisible
boolean pinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
ButtonDispatcher backButton = mNavigationBarView.getBackButton();
@@ -1252,10 +1212,7 @@
AssistManager.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
mAssistManagerLazy.get().startAssist(args);
mStatusBarLazy.get().awakenDreams();
-
- if (mNavigationBarView != null) {
- mNavigationBarView.abortCurrentGesture();
- }
+ mNavigationBarView.abortCurrentGesture();
return true;
}
@@ -1405,9 +1362,6 @@
}
void updateAccessibilityServicesState(AccessibilityManager accessibilityManager) {
- if (mNavigationBarView == null) {
- return;
- }
boolean[] feedbackEnabled = new boolean[1];
int a11yFlags = getA11yButtonState(feedbackEnabled);
@@ -1593,7 +1547,7 @@
public void disableAnimationsDuringHide(long delay) {
mNavigationBarView.setLayoutTransitionsEnabled(false);
- mNavigationBarView.postDelayed(() -> mNavigationBarView.setLayoutTransitionsEnabled(true),
+ mHandler.postDelayed(mEnableLayoutTransitions,
delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
}
@@ -1608,10 +1562,7 @@
}
public NavigationBarTransitions getBarTransitions() {
- if (mNavigationBarView != null) {
- return mNavigationBarView.getBarTransitions();
- }
- return null;
+ return mNavigationBarView.getBarTransitions();
}
public void finishBarAnimations() {
@@ -1626,8 +1577,7 @@
}
private final Consumer<Integer> mRotationWatcher = rotation -> {
- if (mNavigationBarView != null
- && mNavigationBarView.needsReorient(rotation)) {
+ if (mNavigationBarView.needsReorient(rotation)) {
repositionNavigationBar();
}
};
@@ -1635,9 +1585,6 @@
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (mNavigationBarView == null) {
- return;
- }
String action = intent.getAction();
if (Intent.ACTION_SCREEN_OFF.equals(action)
|| Intent.ACTION_SCREEN_ON.equals(action)) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index ae9b598..8b5a537 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -123,8 +123,7 @@
// Tracks config changes that will actually recreate the nav bar
private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
- ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE
- | ActivityInfo.CONFIG_SCREEN_LAYOUT
+ ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_SCREEN_LAYOUT
| ActivityInfo.CONFIG_UI_MODE);
@Inject
@@ -225,10 +224,7 @@
if (navBar == null) {
continue;
}
- NavigationBarView view = (NavigationBarView) navBar.getView();
- if (view != null) {
- view.updateStates();
- }
+ navBar.getView().updateStates();
}
});
}
@@ -366,13 +362,12 @@
mHandler,
mNavBarOverlayController,
mUiEventLogger);
+ mNavigationBars.put(displayId, navBar);
View navigationBarView = navBar.createView(savedState);
navigationBarView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
- mNavigationBars.put(displayId, navBar);
-
if (result != null) {
navBar.setImeWindowStatus(display.getDisplayId(), result.mImeToken,
result.mImeWindowVis, result.mImeBackDisposition,
@@ -448,7 +443,7 @@
*/
public @Nullable NavigationBarView getNavigationBarView(int displayId) {
NavigationBar navBar = mNavigationBars.get(displayId);
- return (navBar == null) ? null : (NavigationBarView) navBar.getView();
+ return (navBar == null) ? null : navBar.getView();
}
/** @return {@link NavigationBar} on the default display. */
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
index 4d25079..0218016 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
@@ -40,7 +40,6 @@
private final ArrayList<View> mViews = new ArrayList<>();
private final int mId;
- private final AssistManager mAssistManager;
private View.OnClickListener mClickListener;
private View.OnTouchListener mTouchListener;
@@ -73,7 +72,6 @@
public ButtonDispatcher(int id) {
mId = id;
- mAssistManager = Dependency.get(AssistManager.class);
}
public void clear() {
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index 98d8866..6a025a7 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -184,10 +184,4 @@
// Refresh tile views to sync new conversations.
buildActivity();
}
-
- @Override
- protected void onPause() {
- super.onPause();
- finish();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index 7b5ab0d..e53cc0b 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -52,6 +52,7 @@
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.widget.MessagingMessage;
import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.R;
import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
@@ -265,10 +266,16 @@
boolean hasMessageText = message != null && !TextUtils.isEmpty(message.getText());
CharSequence content = (isMissedCall && !hasMessageText)
? context.getString(R.string.missed_call) : message.getText();
- Uri dataUri = message != null ? message.getDataUri() : null;
+
+ // We only use the URI if it's an image, otherwise we fallback to text (for example, with an
+ // audio URI)
+ Uri imageUri = message != null && MessagingMessage.hasImage(message)
+ ? message.getDataUri() : null;
+
if (DEBUG) {
Log.d(TAG, "Tile key: " + key.toString() + ". Notification message has text: "
- + hasMessageText + " Has last interaction: " + sbn.getPostTime());
+ + hasMessageText + ". Image URI: " + imageUri + ". Has last interaction: "
+ + sbn.getPostTime());
}
CharSequence sender = getSenderIfGroupConversation(notification, message);
@@ -278,7 +285,7 @@
.setNotificationCategory(notification.category)
.setNotificationContent(content)
.setNotificationSender(sender)
- .setNotificationDataUri(dataUri)
+ .setNotificationDataUri(imageUri)
.setMessagesCount(messagesCount)
.build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java b/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java
index f3cb359..96aeb60 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java
@@ -29,6 +29,8 @@
import android.util.IconDrawableFactory;
import android.util.Log;
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+
import com.android.settingslib.Utils;
import com.android.systemui.R;
@@ -58,7 +60,7 @@
mIconDrawableFactory = iconDrawableFactory;
mImportantConversationColor = context.getColor(R.color.important_conversation);
mAccentColor = Utils.getColorAttr(context,
- com.android.internal.R.attr.colorAccentPrimary).getDefaultColor();
+ com.android.internal.R.attr.colorAccentPrimaryVariant).getDefaultColor();
mContext = context;
}
@@ -83,7 +85,8 @@
* Returns a {@link Drawable} for the entire conversation. The shortcut icon will be badged
* with the launcher icon of the app specified by packageName.
*/
- public Drawable getPeopleTileDrawable(Drawable headDrawable, String packageName, int userId,
+ public Drawable getPeopleTileDrawable(RoundedBitmapDrawable headDrawable, String packageName,
+ int userId,
boolean important, boolean newStory) {
return new PeopleStoryIconDrawable(headDrawable, getAppBadge(packageName, userId),
mIconBitmapSize, mImportantConversationColor, important, mIconSize, mDensity,
@@ -96,7 +99,7 @@
*/
public static class PeopleStoryIconDrawable extends Drawable {
private float mFullIconSize;
- private Drawable mAvatar;
+ private RoundedBitmapDrawable mAvatar;
private Drawable mBadgeIcon;
private int mIconSize;
private Paint mPriorityRingPaint;
@@ -105,12 +108,13 @@
private Paint mStoryPaint;
private float mDensity;
- PeopleStoryIconDrawable(Drawable avatar,
+ PeopleStoryIconDrawable(RoundedBitmapDrawable avatar,
Drawable badgeIcon,
int iconSize,
@ColorInt int ringColor,
boolean showImportantRing, float fullIconSize, float density,
@ColorInt int accentColor, boolean showStoryRing) {
+ avatar.setCircular(true);
mAvatar = avatar;
mBadgeIcon = badgeIcon;
mIconSize = iconSize;
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
index 59c7fd1..72d382a 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
@@ -45,9 +45,6 @@
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
-import android.icu.text.MeasureFormat;
-import android.icu.util.Measure;
-import android.icu.util.MeasureUnit;
import android.net.Uri;
import android.os.Bundle;
import android.os.UserHandle;
@@ -61,6 +58,9 @@
import android.widget.RemoteViews;
import android.widget.TextView;
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.systemui.R;
@@ -72,6 +72,7 @@
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
@@ -94,6 +95,8 @@
public static final int LAYOUT_LARGE = 2;
private static final int MIN_CONTENT_MAX_LINES = 2;
+ private static final int NAME_MAX_LINES_WITHOUT_LAST_INTERACTION = 3;
+ private static final int NAME_MAX_LINES_WITH_LAST_INTERACTION = 1;
private static final int FIXED_HEIGHT_DIMENS_FOR_LARGE_NOTIF_CONTENT = 16 + 22 + 8 + 16;
private static final int FIXED_HEIGHT_DIMENS_FOR_LARGE_STATUS_CONTENT = 16 + 16 + 24 + 4 + 16;
@@ -225,7 +228,9 @@
Log.d(TAG,
"Create status view for: " + statusesForEntireView.get(0).getActivity());
}
- return createStatusRemoteViews(statusesForEntireView.get(0));
+ ConversationStatus mostRecentlyStartedStatus = statusesForEntireView.stream().max(
+ Comparator.comparing(s -> s.getStartTimeMillis())).get();
+ return createStatusRemoteViews(mostRecentlyStartedStatus);
}
return createLastInteractionRemoteViews();
@@ -579,11 +584,33 @@
setMaxLines(views, false);
}
setAvailabilityDotPadding(views, R.dimen.availability_dot_status_padding);
- // TODO: Set status pre-defined icons
- views.setImageViewResource(R.id.predefined_icon, R.drawable.ic_person);
+ views.setImageViewResource(R.id.predefined_icon, getDrawableForStatus(status));
return views;
}
+ private int getDrawableForStatus(ConversationStatus status) {
+ switch (status.getActivity()) {
+ case ACTIVITY_NEW_STORY:
+ return R.drawable.ic_pages;
+ case ACTIVITY_ANNIVERSARY:
+ return R.drawable.ic_celebration;
+ case ACTIVITY_UPCOMING_BIRTHDAY:
+ return R.drawable.ic_gift;
+ case ACTIVITY_BIRTHDAY:
+ return R.drawable.ic_cake;
+ case ACTIVITY_LOCATION:
+ return R.drawable.ic_location;
+ case ACTIVITY_GAME:
+ return R.drawable.ic_play_games;
+ case ACTIVITY_VIDEO:
+ return R.drawable.ic_video;
+ case ACTIVITY_AUDIO:
+ return R.drawable.ic_music_note;
+ default:
+ return R.drawable.ic_person;
+ }
+ }
+
/**
* Update the padding of the availability dot. The padding on the availability dot decreases
* on the status layouts compared to all other layouts.
@@ -658,7 +685,6 @@
}
private RemoteViews decorateBackground(RemoteViews views, CharSequence content) {
- int visibility = View.GONE;
CharSequence emoji = getDoubleEmoji(content);
if (!TextUtils.isEmpty(emoji)) {
setEmojiBackground(views, emoji);
@@ -768,6 +794,7 @@
}
private RemoteViews setViewForContentLayout(RemoteViews views) {
+ views = decorateBackground(views, "");
if (mLayoutSize == LAYOUT_SMALL) {
views.setViewVisibility(R.id.predefined_icon, View.VISIBLE);
views.setViewVisibility(R.id.name, View.GONE);
@@ -819,6 +846,7 @@
private RemoteViews createLastInteractionRemoteViews() {
RemoteViews views = new RemoteViews(mContext.getPackageName(), getEmptyLayout());
+ views.setInt(R.id.name, "setMaxLines", NAME_MAX_LINES_WITH_LAST_INTERACTION);
if (mLayoutSize == LAYOUT_SMALL) {
views.setViewVisibility(R.id.name, View.VISIBLE);
views.setViewVisibility(R.id.predefined_icon, View.GONE);
@@ -836,6 +864,9 @@
} else {
if (DEBUG) Log.d(TAG, "Hide last interaction");
views.setViewVisibility(R.id.last_interaction, View.GONE);
+ if (mLayoutSize == LAYOUT_MEDIUM) {
+ views.setInt(R.id.name, "setMaxLines", NAME_MAX_LINES_WITHOUT_LAST_INTERACTION);
+ }
}
return views;
}
@@ -891,8 +922,9 @@
context.getPackageManager(),
IconDrawableFactory.newInstance(context, false),
maxAvatarSize);
- Drawable drawable = icon.loadDrawable(context);
- Drawable personDrawable = storyIcon.getPeopleTileDrawable(drawable,
+ RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory.create(
+ context.getResources(), icon.getBitmap());
+ Drawable personDrawable = storyIcon.getPeopleTileDrawable(roundedDrawable,
tile.getPackageName(), getUserId(tile), tile.isImportantConversation(),
hasNewStory);
return convertDrawableToBitmap(personDrawable);
@@ -907,14 +939,11 @@
}
long now = System.currentTimeMillis();
Duration durationSinceLastInteraction = Duration.ofMillis(now - lastInteraction);
- MeasureFormat formatter = MeasureFormat.getInstance(Locale.getDefault(),
- MeasureFormat.FormatWidth.WIDE);
if (durationSinceLastInteraction.toDays() <= ONE_DAY) {
return null;
} else if (durationSinceLastInteraction.toDays() < DAYS_IN_A_WEEK) {
- return context.getString(R.string.days_timestamp, formatter.formatMeasures(
- new Measure(durationSinceLastInteraction.toDays(),
- MeasureUnit.DAY)));
+ return context.getString(R.string.days_timestamp,
+ durationSinceLastInteraction.toDays());
} else if (durationSinceLastInteraction.toDays() == DAYS_IN_A_WEEK) {
return context.getString(R.string.one_week_timestamp);
} else if (durationSinceLastInteraction.toDays() < DAYS_IN_A_WEEK * 2) {
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
index 9e0dd72..2602d7a 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -667,12 +667,16 @@
if (icon != null) {
updatedTile.setUserIcon(icon);
}
+ if (DEBUG) Log.d(TAG, "Statuses: " + conversation.getStatuses().toString());
+ NotificationChannel channel = conversation.getParentNotificationChannel();
+ if (channel != null) {
+ if (DEBUG) Log.d(TAG, "Important:" + channel.isImportantConversation());
+ updatedTile.setIsImportantConversation(channel.isImportantConversation());
+ }
updatedTile
.setContactUri(uri)
.setStatuses(conversation.getStatuses())
- .setLastInteractionTimestamp(conversation.getLastEventTimestamp())
- .setIsImportantConversation(conversation.getParentNotificationChannel() != null
- && conversation.getParentNotificationChannel().isImportantConversation());
+ .setLastInteractionTimestamp(conversation.getLastEventTimestamp());
updateAppWidgetOptionsAndView(appWidgetId, updatedTile.build());
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 34c654c..1c5fa43 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -95,7 +95,7 @@
private boolean mLastKeyguardAndExpanded;
/**
* The last received state from the controller. This should not be used directly to check if
- * we're on keyguard but use {@link #isKeyguardShowing()} instead since that is more accurate
+ * we're on keyguard but use {@link #isKeyguardState()} instead since that is more accurate
* during state transitions which often call into us.
*/
private int mState;
@@ -326,7 +326,7 @@
|| mHeaderAnimating;
mQSPanelController.setExpanded(mQsExpanded);
mQSDetail.setExpanded(mQsExpanded);
- boolean keyguardShowing = isKeyguardShowing();
+ boolean keyguardShowing = isKeyguardState();
mHeader.setVisibility((mQsExpanded || !keyguardShowing || mHeaderAnimating
|| mShowCollapsedOnKeyguard)
? View.VISIBLE
@@ -344,7 +344,7 @@
!mQsDisabled && expandVisually ? View.VISIBLE : View.INVISIBLE);
}
- private boolean isKeyguardShowing() {
+ private boolean isKeyguardState() {
// We want the freshest state here since otherwise we'll have some weirdness if earlier
// listeners trigger updates
return mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
@@ -366,7 +366,7 @@
if (mQSAnimator != null) {
mQSAnimator.setShowCollapsedOnKeyguard(showCollapsed);
}
- if (!showCollapsed && isKeyguardShowing()) {
+ if (!showCollapsed && isKeyguardState()) {
setQsExpansion(mLastQSExpansion, 0);
}
}
@@ -457,7 +457,7 @@
mContainer.setExpansion(expansion);
final float translationScaleY = (mTranslateWhileExpanding
? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1);
- boolean onKeyguardAndExpanded = isKeyguardShowing() && !mShowCollapsedOnKeyguard;
+ boolean onKeyguardAndExpanded = isKeyguardState() && !mShowCollapsedOnKeyguard;
if (!mHeaderAnimating && !headerWillBeAnimating()) {
getView().setTranslationY(
onKeyguardAndExpanded
@@ -531,7 +531,6 @@
// The Media can be scrolled off screen by default, let's offset it
float expandedMediaPosition = absoluteBottomPosition - mQSPanelScrollView.getScrollY()
+ mQSPanelScrollView.getScrollRange();
- // The expanded media host should never move below the laid out position
pinToBottom(expandedMediaPosition, mQsMediaHost, true /* expanded */);
// The expanded media host should never move above the laid out position
pinToBottom(absoluteBottomPosition, mQqsMediaHost, false /* expanded */);
@@ -540,7 +539,8 @@
private void pinToBottom(float absoluteBottomPosition, MediaHost mediaHost, boolean expanded) {
View hostView = mediaHost.getHostView();
- if (mLastQSExpansion > 0) {
+ // on keyguard we cross-fade to expanded, so no need to pin it.
+ if (mLastQSExpansion > 0 && !isKeyguardState()) {
float targetPosition = absoluteBottomPosition - getTotalBottomMargin(hostView)
- hostView.getHeight();
float currentPosition = mediaHost.getCurrentBounds().top
@@ -573,7 +573,7 @@
private boolean headerWillBeAnimating() {
return mState == StatusBarState.KEYGUARD && mShowCollapsedOnKeyguard
- && !isKeyguardShowing();
+ && !isKeyguardState();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index b7f2cd0..74d3425 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -416,10 +416,10 @@
if (cb.mAirplaneModeEnabled) {
if (!state.value) {
state.state = Tile.STATE_INACTIVE;
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_airplane);
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
state.secondaryLabel = r.getString(R.string.status_bar_airplane);
} else if (!wifiConnected) {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_airplane);
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
if (cb.mNoNetworksAvailable) {
state.secondaryLabel =
r.getString(R.string.quick_settings_networks_unavailable);
@@ -430,12 +430,14 @@
} else {
state.icon = ResourceIcon.get(cb.mWifiSignalIconId);
}
- } else if (cb.mNoDefaultNetwork && cb.mNoNetworksAvailable) {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
- state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable);
- } else if (cb.mNoValidatedNetwork && !cb.mNoNetworksAvailable) {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_available);
- state.secondaryLabel = r.getString(R.string.quick_settings_networks_available);
+ } else if (cb.mNoDefaultNetwork) {
+ if (cb.mNoNetworksAvailable) {
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
+ state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable);
+ } else {
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_available);
+ state.secondaryLabel = r.getString(R.string.quick_settings_networks_available);
+ }
} else if (cb.mIsTransient) {
state.icon = ResourceIcon.get(
com.android.internal.R.drawable.ic_signal_wifi_transient_animation);
@@ -486,14 +488,16 @@
if (cb.mAirplaneModeEnabled && cb.mQsTypeIcon != TelephonyIcons.ICON_CWF) {
state.state = Tile.STATE_INACTIVE;
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_airplane);
- state.secondaryLabel = r.getString(R.string.status_bar_airplane);
- } else if (cb.mNoDefaultNetwork && cb.mNoNetworksAvailable) {
state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
- state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable);
- } else if (cb.mNoValidatedNetwork && !cb.mNoNetworksAvailable) {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_available);
- state.secondaryLabel = r.getString(R.string.quick_settings_networks_available);
+ state.secondaryLabel = r.getString(R.string.status_bar_airplane);
+ } else if (cb.mNoDefaultNetwork) {
+ if (cb.mNoNetworksAvailable) {
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
+ state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable);
+ } else {
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_available);
+ state.secondaryLabel = r.getString(R.string.quick_settings_networks_available);
+ }
} else {
state.icon = new SignalIcon(cb.mMobileSignalIconId);
state.secondaryLabel = appendMobileDataType(cb.mDataSubscriptionName,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
index e467925..64aec5e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
@@ -18,13 +18,14 @@
import static android.provider.Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT;
+import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE;
+
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.service.quickaccesswallet.GetWalletCardsError;
-import android.service.quickaccesswallet.GetWalletCardsRequest;
import android.service.quickaccesswallet.GetWalletCardsResponse;
import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.service.quickaccesswallet.WalletCard;
@@ -51,6 +52,7 @@
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.systemui.wallet.ui.WalletActivity;
import java.util.List;
@@ -66,16 +68,15 @@
private final CharSequence mLabel = mContext.getString(R.string.wallet_title);
private final WalletCardRetriever mCardRetriever = new WalletCardRetriever();
- // TODO(b/180959290): Re-create the QAW Client when the default NFC payment app changes.
- private final QuickAccessWalletClient mQuickAccessWalletClient;
private final KeyguardStateController mKeyguardStateController;
private final PackageManager mPackageManager;
private final SecureSettings mSecureSettings;
private final Executor mExecutor;
+ private final QuickAccessWalletController mController;
private final FeatureFlags mFeatureFlags;
- @VisibleForTesting Drawable mCardViewDrawable;
private WalletCard mSelectedCard;
+ @VisibleForTesting Drawable mCardViewDrawable;
@Inject
public QuickAccessWalletTile(
@@ -87,15 +88,15 @@
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
- QuickAccessWalletClient quickAccessWalletClient,
KeyguardStateController keyguardStateController,
PackageManager packageManager,
SecureSettings secureSettings,
- @Background Executor executor,
+ @Main Executor executor,
+ QuickAccessWalletController quickAccessWalletController,
FeatureFlags featureFlags) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
- mQuickAccessWalletClient = quickAccessWalletClient;
+ mController = quickAccessWalletController;
mKeyguardStateController = keyguardStateController;
mPackageManager = packageManager;
mSecureSettings = secureSettings;
@@ -115,7 +116,11 @@
protected void handleSetListening(boolean listening) {
super.handleSetListening(listening);
if (listening) {
- queryWalletCards();
+ mController.setupWalletChangeObservers(mCardRetriever, DEFAULT_PAYMENT_APP_CHANGE);
+ if (!mController.getWalletClient().isWalletServiceAvailable()) {
+ mController.reCreateWalletClient();
+ }
+ mController.queryWalletCards(mCardRetriever);
}
}
@@ -139,12 +144,13 @@
mContext.startActivity(intent);
}
} else {
- if (mQuickAccessWalletClient.createWalletIntent() == null) {
+ if (mController.getWalletClient().createWalletIntent() == null) {
Log.w(TAG, "Could not get intent of the wallet app.");
return;
}
mActivityStarter.postStartActivityDismissingKeyguard(
- mQuickAccessWalletClient.createWalletIntent(), /* delay= */ 0,
+ mController.getWalletClient().createWalletIntent(),
+ /* delay= */ 0,
animationController);
}
});
@@ -152,30 +158,34 @@
@Override
protected void handleUpdateState(State state, Object arg) {
- CharSequence label = mQuickAccessWalletClient.getServiceLabel();
+ CharSequence label = mController.getWalletClient().getServiceLabel();
state.label = label == null ? mLabel : label;
state.contentDescription = state.label;
state.icon = ResourceIcon.get(R.drawable.ic_wallet_lockscreen);
boolean isDeviceLocked = !mKeyguardStateController.isUnlocked();
- if (mQuickAccessWalletClient.isWalletServiceAvailable()) {
+ if (mController.getWalletClient().isWalletServiceAvailable()) {
if (mSelectedCard != null) {
if (isDeviceLocked) {
state.state = Tile.STATE_INACTIVE;
state.secondaryLabel =
mContext.getString(R.string.wallet_secondary_label_device_locked);
+ state.sideViewCustomDrawable = null;
} else {
state.state = Tile.STATE_ACTIVE;
state.secondaryLabel = mSelectedCard.getContentDescription();
+ state.sideViewCustomDrawable = mCardViewDrawable;
}
} else {
state.state = Tile.STATE_INACTIVE;
state.secondaryLabel = mContext.getString(R.string.wallet_secondary_label_no_card);
+ state.sideViewCustomDrawable = null;
}
state.stateDescription = state.secondaryLabel;
} else {
state.state = Tile.STATE_UNAVAILABLE;
+ state.secondaryLabel = null;
+ state.sideViewCustomDrawable = null;
}
- state.sideViewCustomDrawable = isDeviceLocked ? null : mCardViewDrawable;
}
@Override
@@ -198,19 +208,14 @@
@Override
public CharSequence getTileLabel() {
- CharSequence label = mQuickAccessWalletClient.getServiceLabel();
+ CharSequence label = mController.getWalletClient().getServiceLabel();
return label == null ? mLabel : label;
}
- private void queryWalletCards() {
- int cardWidth =
- mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_width);
- int cardHeight =
- mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_height);
- int iconSizePx = mContext.getResources().getDimensionPixelSize(R.dimen.wallet_icon_size);
- GetWalletCardsRequest request =
- new GetWalletCardsRequest(cardWidth, cardHeight, iconSizePx, /* maxCards= */ 1);
- mQuickAccessWalletClient.getWalletCards(mExecutor, request, mCardRetriever);
+ @Override
+ protected void handleDestroy() {
+ super.handleDestroy();
+ mController.unregisterWalletChangeObservers(DEFAULT_PAYMENT_APP_CHANGE);
}
private class WalletCardRetriever implements
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 89cb5af..f4c15fb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -29,6 +29,7 @@
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
@@ -88,6 +89,7 @@
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -148,6 +150,7 @@
private final CommandQueue mCommandQueue;
private final ShellTransitions mShellTransitions;
private final Optional<StartingSurface> mStartingSurface;
+ private final SmartspaceTransitionController mSmartspaceTransitionController;
private Region mActiveNavBarRegion;
@@ -552,6 +555,9 @@
mStartingSurface.ifPresent((startingwindow) -> params.putBinder(
KEY_EXTRA_SHELL_STARTING_WINDOW,
startingwindow.createExternalInterface().asBinder()));
+ params.putBinder(
+ KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER,
+ mSmartspaceTransitionController.createExternalInterface().asBinder());
try {
Log.d(TAG_OPS + " b/182478748", "OverviewProxyService.onInitialize: curUser="
@@ -613,7 +619,8 @@
Optional<OneHanded> oneHandedOptional,
BroadcastDispatcher broadcastDispatcher,
ShellTransitions shellTransitions,
- Optional<StartingSurface> startingSurface) {
+ Optional<StartingSurface> startingSurface,
+ SmartspaceTransitionController smartspaceTransitionController) {
super(broadcastDispatcher);
mContext = context;
mPipOptional = pipOptional;
@@ -675,6 +682,7 @@
updateEnabledState();
startConnectionToCurrentUser();
mStartingSurface = startingSurface;
+ mSmartspaceTransitionController = smartspaceTransitionController;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java
index 3370946..4a1aa16 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionChip.java
@@ -21,8 +21,10 @@
import android.graphics.drawable.Icon;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.systemui.R;
@@ -59,6 +61,7 @@
protected void onFinishInflate() {
mIconView = findViewById(R.id.screenshot_action_chip_icon);
mTextView = findViewById(R.id.screenshot_action_chip_text);
+ updatePadding(mTextView.getText().length() > 0);
}
@Override
@@ -76,6 +79,7 @@
void setText(CharSequence text) {
mTextView.setText(text);
+ updatePadding(text.length() > 0);
}
void setPendingIntent(PendingIntent intent, Runnable finisher) {
@@ -93,4 +97,28 @@
mIsPending = isPending;
setPressed(mIsPending);
}
+
+ private void updatePadding(boolean hasText) {
+ LinearLayout.LayoutParams iconParams =
+ (LinearLayout.LayoutParams) mIconView.getLayoutParams();
+ LinearLayout.LayoutParams textParams =
+ (LinearLayout.LayoutParams) mTextView.getLayoutParams();
+ if (hasText) {
+ int paddingHorizontal = mContext.getResources().getDimensionPixelSize(
+ R.dimen.screenshot_action_chip_padding_horizontal);
+ int spacing = mContext.getResources().getDimensionPixelSize(
+ R.dimen.screenshot_action_chip_spacing);
+ iconParams.setMarginStart(paddingHorizontal);
+ iconParams.setMarginEnd(spacing);
+ textParams.setMarginEnd(paddingHorizontal);
+ } else {
+ int paddingHorizontal = mContext.getResources().getDimensionPixelSize(
+ R.dimen.screenshot_action_chip_icon_only_padding_horizontal);
+ iconParams.setMarginStart(paddingHorizontal);
+ iconParams.setMarginEnd(paddingHorizontal);
+ }
+ mTextView.setVisibility(hasText ? View.VISIBLE : View.GONE);
+ mIconView.setLayoutParams(iconParams);
+ mTextView.setLayoutParams(textParams);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 71a152d..facebee 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -40,7 +40,6 @@
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Insets;
-import android.graphics.Outline;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
@@ -61,7 +60,6 @@
import android.view.TouchDelegate;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.accessibility.AccessibilityManager;
@@ -108,7 +106,7 @@
private static final long SCREENSHOT_DISMISS_ALPHA_DURATION_MS = 183;
private static final long SCREENSHOT_DISMISS_ALPHA_OFFSET_MS = 50; // delay before starting fade
private static final float SCREENSHOT_ACTIONS_START_SCALE_X = .7f;
- private static final float ROUNDED_CORNER_RADIUS = .05f;
+ private static final float ROUNDED_CORNER_RADIUS = .25f;
private static final int SWIPE_PADDING_DP = 12; // extra padding around views to allow swipe
private final Interpolator mAccelerateInterpolator = new AccelerateInterpolator();
@@ -129,6 +127,7 @@
private ScreenshotSelectorView mScreenshotSelectorView;
private View mScreenshotStatic;
private ImageView mScreenshotPreview;
+ private View mScreenshotPreviewBorder;
private ImageView mScreenshotFlash;
private ImageView mActionsContainerBackground;
private HorizontalScrollView mActionsContainer;
@@ -265,6 +264,9 @@
protected void onFinishInflate() {
mScreenshotStatic = requireNonNull(findViewById(R.id.global_screenshot_static));
mScreenshotPreview = requireNonNull(findViewById(R.id.global_screenshot_preview));
+ mScreenshotPreviewBorder = requireNonNull(
+ findViewById(R.id.global_screenshot_preview_border));
+ mScreenshotPreview.setClipToOutline(true);
mActionsContainerBackground = requireNonNull(findViewById(
R.id.global_screenshot_actions_container_background));
@@ -279,15 +281,6 @@
mEditChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_edit_chip));
mScrollChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_scroll_chip));
- mScreenshotPreview.setClipToOutline(true);
- mScreenshotPreview.setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(new Rect(0, 0, view.getWidth(), view.getHeight()),
- ROUNDED_CORNER_RADIUS * view.getWidth());
- }
- });
-
int swipePaddingPx = (int) dpToPx(SWIPE_PADDING_DP);
TouchDelegate previewDelegate = new TouchDelegate(
new Rect(swipePaddingPx, swipePaddingPx, swipePaddingPx, swipePaddingPx),
@@ -467,12 +460,18 @@
mScreenshotFlash.setAlpha(0f);
mScreenshotFlash.setVisibility(View.VISIBLE);
+ ValueAnimator borderFadeIn = ValueAnimator.ofFloat(0, 1);
+ borderFadeIn.setDuration(100);
+ borderFadeIn.addUpdateListener((animation) ->
+ mScreenshotPreviewBorder.setAlpha(animation.getAnimatedFraction()));
+
if (showFlash) {
dropInAnimation.play(flashOutAnimator).after(flashInAnimator);
dropInAnimation.play(flashOutAnimator).with(toCorner);
} else {
dropInAnimation.play(toCorner);
}
+ dropInAnimation.play(borderFadeIn).after(toCorner);
dropInAnimation.addListener(new AnimatorListenerAdapter() {
@Override
@@ -497,8 +496,8 @@
finalPos.y - dismissOffset - bounds.height() * cornerScale / 2f);
mScreenshotPreview.setScaleX(1);
mScreenshotPreview.setScaleY(1);
- mScreenshotPreview.setX(finalPos.x - bounds.width() * cornerScale / 2f);
- mScreenshotPreview.setY(finalPos.y - bounds.height() * cornerScale / 2f);
+ mScreenshotPreview.setX(finalPos.x - mScreenshotPreview.getWidth() / 2f);
+ mScreenshotPreview.setY(finalPos.y - mScreenshotPreview.getHeight() / 2f);
requestLayout();
createScreenshotActionsShadeAnimation().start();
@@ -520,7 +519,7 @@
ArrayList<ScreenshotActionChip> chips = new ArrayList<>();
- mShareChip.setText(mContext.getString(com.android.internal.R.string.share));
+ mShareChip.setContentDescription(mContext.getString(com.android.internal.R.string.share));
mShareChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_share), true);
mShareChip.setOnClickListener(v -> {
mShareChip.setIsPending(true);
@@ -532,7 +531,7 @@
});
chips.add(mShareChip);
- mEditChip.setText(mContext.getString(R.string.screenshot_edit_label));
+ mEditChip.setContentDescription(mContext.getString(R.string.screenshot_edit_label));
mEditChip.setIcon(Icon.createWithResource(mContext, R.drawable.ic_screenshot_edit), true);
mEditChip.setOnClickListener(v -> {
mEditChip.setIsPending(true);
@@ -739,6 +738,7 @@
// Clear any references to the bitmap
mScreenshotPreview.setImageDrawable(null);
mScreenshotPreview.setVisibility(View.INVISIBLE);
+ mScreenshotPreviewBorder.setAlpha(0);
mPendingSharedTransition = false;
mActionsContainerBackground.setVisibility(View.GONE);
mActionsContainer.setVisibility(View.GONE);
@@ -798,6 +798,7 @@
yAnim.addUpdateListener(animation -> {
float yDelta = MathUtils.lerp(0, mDismissDeltaY, animation.getAnimatedFraction());
mScreenshotPreview.setTranslationY(screenshotStartY + yDelta);
+ mScreenshotPreviewBorder.setTranslationY(screenshotStartY + yDelta);
mDismissButton.setTranslationY(dismissStartY + yDelta);
mActionsContainer.setTranslationY(yDelta);
mActionsContainerBackground.setTranslationY(yDelta);
@@ -860,11 +861,15 @@
class SwipeDismissHandler implements OnTouchListener {
// distance needed to register a dismissal
- private static final float DISMISS_DISTANCE_THRESHOLD_DP = 30;
+ private static final float DISMISS_DISTANCE_THRESHOLD_DP = 20;
private final GestureDetector mGestureDetector;
private float mStartX;
+ // Keeps track of the most recent direction (between the last two move events).
+ // -1 for left; +1 for right.
+ private int mDirectionX;
+ private float mPreviousX;
SwipeDismissHandler() {
GestureDetector.OnGestureListener gestureListener = new SwipeDismissGestureListener();
@@ -877,6 +882,7 @@
mCallbacks.onUserInteraction();
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
mStartX = event.getRawX();
+ mPreviousX = mStartX;
return true;
} else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
if (isPastDismissThreshold()
@@ -905,16 +911,42 @@
public boolean onScroll(
MotionEvent ev1, MotionEvent ev2, float distanceX, float distanceY) {
mScreenshotStatic.setTranslationX(ev2.getRawX() - mStartX);
+ mDirectionX = (ev2.getRawX() < mPreviousX) ? -1 : 1;
+ mPreviousX = ev2.getRawX();
return true;
}
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
+ float velocityY) {
+ if (mScreenshotStatic.getTranslationX() * velocityX > 0
+ && (mDismissAnimation == null || !mDismissAnimation.isRunning())) {
+ animateDismissal(createSwipeDismissAnimation(velocityX / (float) 1000));
+ return true;
+ }
+ return false;
+ }
}
private boolean isPastDismissThreshold() {
- float distance = Math.abs(mScreenshotStatic.getTranslationX());
- return distance >= dpToPx(DISMISS_DISTANCE_THRESHOLD_DP);
+ float translationX = mScreenshotStatic.getTranslationX();
+ // Determines whether the absolute translation from the start is in the same direction
+ // as the current movement. For example, if the user moves most of the way to the right,
+ // but then starts dragging back left, we do not dismiss even though the absolute
+ // distance is greater than the threshold.
+ if (translationX * mDirectionX > 0) {
+ return Math.abs(translationX) >= dpToPx(DISMISS_DISTANCE_THRESHOLD_DP);
+ }
+ return false;
}
private ValueAnimator createSwipeDismissAnimation() {
+ return createSwipeDismissAnimation(1);
+ }
+
+ private ValueAnimator createSwipeDismissAnimation(float velocity) {
+ // velocity is measured in pixels per millisecond
+ velocity = Math.min(3, Math.max(1, velocity));
ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
float startX = mScreenshotStatic.getTranslationX();
// make sure the UI gets all the way off the screen in the direction of movement
@@ -923,13 +955,14 @@
float finalX = startX < 0
? -1 * mActionsContainerBackground.getRight()
: mDisplayMetrics.widthPixels;
+ float distance = Math.abs(finalX - startX);
anim.addUpdateListener(animation -> {
float translation = MathUtils.lerp(startX, finalX, animation.getAnimatedFraction());
mScreenshotStatic.setTranslationX(translation);
setAlpha(1 - animation.getAnimatedFraction());
});
- anim.setDuration(400);
+ anim.setDuration((long) (distance / Math.abs(velocity)));
return anim;
}
diff --git a/packages/SystemUI/src/com/android/systemui/shared/system/smartspace/SmartspaceTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shared/system/smartspace/SmartspaceTransitionController.kt
new file mode 100644
index 0000000..89b3df0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shared/system/smartspace/SmartspaceTransitionController.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.system.smartspace
+
+import android.graphics.Rect
+import android.view.View
+import com.android.systemui.shared.system.ActivityManagerWrapper
+import com.android.systemui.shared.system.QuickStepContract
+import kotlin.math.min
+
+/**
+ * Controller that keeps track of SmartSpace instances in remote processes (such as Launcher),
+ * allowing System UI to query or update their state during shared-element transitions.
+ */
+class SmartspaceTransitionController {
+
+ /**
+ * Implementation of [ISmartspaceTransitionController] that we provide to Launcher, allowing it
+ * to provide us with a callback to query and update the state of its Smartspace.
+ */
+ private val ISmartspaceTransitionController = object : ISmartspaceTransitionController.Stub() {
+ override fun setSmartspace(callback: ISmartspaceCallback?) {
+ this@SmartspaceTransitionController.launcherSmartspace = callback
+ updateLauncherSmartSpaceState()
+ }
+ }
+
+ /**
+ * Callback provided by Launcher to allow us to query and update the state of its SmartSpace.
+ */
+ public var launcherSmartspace: ISmartspaceCallback? = null
+
+ public var lockscreenSmartspace: View? = null
+
+ /**
+ * Cached state of the Launcher SmartSpace. Retrieving the state is an IPC, so we should avoid
+ * unnecessary
+ */
+ public var mLauncherSmartspaceState: SmartspaceState? = null
+
+ /**
+ * The bounds of our SmartSpace when the shared element transition began. We'll interpolate
+ * between this and [smartspaceDestinationBounds] as the dismiss amount changes.
+ */
+ private val smartspaceOriginBounds = Rect()
+
+ /** The bounds of the Launcher's SmartSpace, which is where we are animating our SmartSpace. */
+
+ private val smartspaceDestinationBounds = Rect()
+
+ fun createExternalInterface(): ISmartspaceTransitionController {
+ return ISmartspaceTransitionController
+ }
+
+ /**
+ * Updates [mLauncherSmartspaceState] and returns it. This will trigger a binder call, so use the
+ * cached [mLauncherSmartspaceState] if possible.
+ */
+ fun updateLauncherSmartSpaceState(): SmartspaceState? {
+ return launcherSmartspace?.smartspaceState.also {
+ mLauncherSmartspaceState = it
+ }
+ }
+
+ fun prepareForUnlockTransition() {
+ updateLauncherSmartSpaceState().also { state ->
+ if (state?.boundsOnScreen != null && lockscreenSmartspace != null) {
+ lockscreenSmartspace!!.getBoundsOnScreen(smartspaceOriginBounds)
+ with(smartspaceDestinationBounds) {
+ set(state.boundsOnScreen)
+ offset(-lockscreenSmartspace!!.paddingLeft,
+ -lockscreenSmartspace!!.paddingTop)
+ }
+ }
+ }
+ }
+
+ fun setProgressToDestinationBounds(progress: Float) {
+ if (!isSmartspaceTransitionPossible()) {
+ return
+ }
+
+ val progressClamped = min(1f, progress)
+
+ // Calculate the distance (relative to the origin) that we need to be for the current
+ // progress value.
+ val progressX =
+ (smartspaceDestinationBounds.left - smartspaceOriginBounds.left) * progressClamped
+ val progressY =
+ (smartspaceDestinationBounds.top - smartspaceOriginBounds.top) * progressClamped
+
+ val lockscreenSmartspaceCurrentBounds = Rect().also {
+ lockscreenSmartspace!!.getBoundsOnScreen(it)
+ }
+
+ // Figure out how far that is from our present location on the screen. This approach
+ // compensates for the fact that our parent container is also translating to animate out.
+ val dx = smartspaceOriginBounds.left + progressX -
+ lockscreenSmartspaceCurrentBounds.left
+ var dy = smartspaceOriginBounds.top + progressY -
+ lockscreenSmartspaceCurrentBounds.top
+
+ with(lockscreenSmartspace!!) {
+ translationX = translationX + dx
+ translationY = translationY + dy
+ }
+ }
+
+ /**
+ * Whether we're capable of performing the Smartspace shared element transition when we unlock.
+ * This is true if:
+ *
+ * - The Launcher registered a Smartspace with us, it's reporting non-empty bounds on screen.
+ * - Launcher is behind the keyguard, and the Smartspace is visible on the currently selected
+ * page.
+ */
+ public fun isSmartspaceTransitionPossible(): Boolean {
+ val smartSpaceNullOrBoundsEmpty = mLauncherSmartspaceState?.boundsOnScreen?.isEmpty ?: true
+ return isLauncherUnderneath() && !smartSpaceNullOrBoundsEmpty
+ }
+
+ companion object {
+ fun isLauncherUnderneath(): Boolean {
+ return ActivityManagerWrapper.getInstance()
+ .runningTask?.topActivity?.className?.equals(
+ QuickStepContract.LAUNCHER_ACTIVITY_CLASS_NAME) ?: false
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
index 9d52fe5..969877d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
@@ -76,13 +76,14 @@
* @param viewRootImpl The window root.
* @param radius blur radius in pixels.
*/
- fun applyBlur(viewRootImpl: ViewRootImpl?, radius: Int) {
+ fun applyBlur(viewRootImpl: ViewRootImpl?, radius: Int, opaqueBackground: Boolean) {
if (viewRootImpl == null || !viewRootImpl.surfaceControl.isValid ||
!supportsBlursOnWindows()) {
return
}
createTransaction().use {
it.setBackgroundBlurRadius(viewRootImpl.surfaceControl, radius)
+ it.setOpaque(viewRootImpl.surfaceControl, opaqueBackground)
it.apply()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 6baacb9..56941b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -18,6 +18,7 @@
import static android.app.StatusBarManager.DISABLE2_NONE;
import static android.app.StatusBarManager.DISABLE_NONE;
+import static android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -289,7 +290,7 @@
IBiometricSysuiReceiver receiver,
int[] sensorIds, boolean credentialAllowed,
boolean requireConfirmation, int userId, String opPackageName,
- long operationId) {
+ long operationId, @BiometricMultiSensorMode int multiSensorConfig) {
}
default void onBiometricAuthenticated() {
@@ -838,17 +839,19 @@
@Override
public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
- int userId, String opPackageName, long operationId) {
+ int userId, String opPackageName, long operationId,
+ @BiometricMultiSensorMode int multiSensorConfig) {
synchronized (mLock) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = promptInfo;
args.arg2 = receiver;
- args.arg3 = sensorIds; //
- args.arg4 = credentialAllowed; //
+ args.arg3 = sensorIds;
+ args.arg4 = credentialAllowed;
args.arg5 = requireConfirmation;
args.argi1 = userId;
args.arg6 = opPackageName;
args.arg7 = operationId;
+ args.argi2 = multiSensorConfig;
mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args)
.sendToTarget();
}
@@ -1303,7 +1306,8 @@
(boolean) someArgs.arg5 /* requireConfirmation */,
someArgs.argi1 /* userId */,
(String) someArgs.arg6 /* opPackageName */,
- (long) someArgs.arg7 /* operationId */);
+ (long) someArgs.arg7 /* operationId */,
+ someArgs.argi2 /* multiSensorConfig */);
}
someArgs.recycle();
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
index ac6d9e8..c7b6e67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java
@@ -61,10 +61,6 @@
return mFlagReader.isEnabled(R.bool.flag_conversations);
}
- public boolean isToastStyleEnabled() {
- return mFlagReader.isEnabled(R.bool.flag_toast_style);
- }
-
public boolean isMonetEnabled() {
return mFlagReader.isEnabled(R.bool.flag_monet);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
index b33424c..acfd998 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -35,7 +35,6 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry.OnSensitivityChangedListener;
-import java.util.List;
/**
* The view in the statusBar that contains part of the heads-up information
@@ -55,10 +54,8 @@
private int[] mTmpPosition = new int[2];
private boolean mFirstLayout = true;
private int mMaxWidth;
- private View mRootView;
private int mSysWinInset;
private int mCutOutInset;
- private List<Rect> mCutOutBounds;
private Rect mIconDrawingRect = new Rect();
private Point mDisplaySize;
private Runnable mOnDrawingRectChangedListener;
@@ -197,19 +194,7 @@
int targetPadding = mAbsoluteStartPadding + mSysWinInset + mCutOutInset;
boolean isRtl = isLayoutRtl();
int start = isRtl ? (mDisplaySize.x - right) : left;
-
if (start != targetPadding) {
- if (mCutOutBounds != null) {
- for (Rect cutOutRect : mCutOutBounds) {
- int cutOutStart = (isRtl)
- ? (mDisplaySize.x - cutOutRect.right) : cutOutRect.left;
- if (start > cutOutStart) {
- start -= cutOutRect.width();
- break;
- }
- }
- }
-
int newPadding = targetPadding - start + getPaddingStart();
setPaddingRelative(newPadding, 0, mEndMargin, 0);
}
@@ -252,12 +237,6 @@
getDisplaySize();
- mCutOutBounds = null;
- if (displayCutout != null && displayCutout.getSafeInsetRight() == 0
- && displayCutout.getSafeInsetLeft() == 0) {
- mCutOutBounds = displayCutout.getBoundingRects();
- }
-
// For Double Cut Out mode, the System window navigation bar is at the right
// side of the left cut out. In this condition, mSysWinInset include the left cut
// out width so we set mCutOutInset to be 0. For RTL, the condition is the same.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index e8ce5f9..b7e8bfb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -184,7 +184,7 @@
blur = 0
}
- blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur)
+ blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur, scrimsVisible)
val zoomOut = blurUtils.ratioOfBlurRadius(blur)
try {
if (root.isAttachedToWindow && root.windowToken != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
index b6357b8..045a197 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowController.java
@@ -36,6 +36,12 @@
*/
default void registerCallback(StatusBarWindowCallback callback) {}
+ /**
+ * Unregisters a {@link StatusBarWindowCallback previous registered with
+ * {@link #registerCallback(StatusBarWindowCallback)}}
+ */
+ default void unregisterCallback(StatusBarWindowCallback callback) {}
+
/** Notifies the registered {@link StatusBarWindowCallback} instances. */
default void notifyStateChangedCallbacks() {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index b93da4b..9dc4ac9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -31,8 +31,8 @@
import android.view.accessibility.AccessibilityNodeInfo;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -53,37 +53,26 @@
public class NotificationShelf extends ActivatableNotificationView implements
View.OnLayoutChangeListener, StateListener {
- private static final boolean ICON_ANMATIONS_WHILE_SCROLLING
- = SystemProperties.getBoolean("debug.icon_scroll_animations", true);
private static final int TAG_CONTINUOUS_CLIPPING = R.id.continuous_clipping_tag;
private static final String TAG = "NotificationShelf";
private NotificationIconContainer mShelfIcons;
private int[] mTmp = new int[2];
private boolean mHideBackground;
- private int mIconAppearTopPadding;
- private float mHiddenShelfIconSize;
private int mStatusBarHeight;
private AmbientState mAmbientState;
private NotificationStackScrollLayoutController mHostLayoutController;
- private int mMaxLayoutHeight;
private int mPaddingBetweenElements;
private int mNotGoneIndex;
private boolean mHasItemsInStableShelf;
private NotificationIconContainer mCollapsedIcons;
private int mScrollFastThreshold;
- private int mIconSize;
private int mStatusBarState;
- private int mRelativeOffset;
private boolean mInteractive;
- private float mOpenedAmount;
- private boolean mNoAnimationsInThisFrame;
private boolean mAnimationsEnabled = true;
private boolean mShowNotificationShelf;
private float mFirstElementRoundness;
private Rect mClipRect = new Rect();
- private int mCutoutHeight;
- private int mGapHeight;
private int mIndexOfFirstViewInShelf = -1;
private float mCornerAnimationDistance;
private NotificationShelfController mController;
@@ -121,7 +110,6 @@
private void initDimens() {
Resources res = getResources();
- mIconAppearTopPadding = res.getDimensionPixelSize(R.dimen.notification_icon_appear_padding);
mStatusBarHeight = res.getDimensionPixelOffset(R.dimen.status_bar_height);
mPaddingBetweenElements = res.getDimensionPixelSize(R.dimen.notification_divider_height);
@@ -133,9 +121,6 @@
mShelfIcons.setPadding(padding, 0, padding, 0);
mScrollFastThreshold = res.getDimensionPixelOffset(R.dimen.scroll_fast_threshold);
mShowNotificationShelf = res.getBoolean(R.bool.config_showNotificationShelf);
- mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
- mHiddenShelfIconSize = res.getDimensionPixelOffset(R.dimen.hidden_shelf_icon_size);
- mGapHeight = res.getDimensionPixelSize(R.dimen.qs_notification_padding);
mCornerAnimationDistance = res.getDimensionPixelSize(
R.dimen.notification_corner_animation_distance);
@@ -180,7 +165,7 @@
if (ambientState.isExpansionChanging() && !ambientState.isOnKeyguard()) {
viewState.alpha = Interpolators.getNotificationScrimAlpha(
- ambientState.getExpansionFraction());
+ ambientState.getExpansionFraction(), true /* notification */);
} else {
viewState.alpha = 1f - ambientState.getHideAmount();
}
@@ -255,7 +240,6 @@
int backgroundTop = 0;
int clipTopAmount = 0;
float firstElementRoundness = 0.0f;
- ActivatableNotificationView previousAnv = null;
for (int i = 0; i < mHostLayoutController.getChildCount(); i++) {
ExpandableView child = mHostLayoutController.getChildAt(i);
@@ -327,52 +311,10 @@
notGoneIndex++;
}
- final float viewEnd = viewStart + child.getActualHeight();
- final float cornerAnimationDistance = mCornerAnimationDistance
- * mAmbientState.getExpansionFraction();
- final float cornerAnimationTop = shelfStart - cornerAnimationDistance;
-
if (child instanceof ActivatableNotificationView) {
ActivatableNotificationView anv =
(ActivatableNotificationView) child;
-
- final boolean isUnlockedHeadsUp = !mAmbientState.isOnKeyguard()
- && !mAmbientState.isShadeExpanded()
- && child instanceof ExpandableView
- && ((ExpandableNotificationRow) child).isHeadsUp();
- if (viewStart < shelfStart
- && !mHostLayoutController.isViewAffectedBySwipe(anv)
- && !isUnlockedHeadsUp
- && !mAmbientState.isPulsing()
- && !mAmbientState.isDozing()) {
-
- if (viewEnd >= cornerAnimationTop) {
- // Round bottom corners within animation bounds
- final float changeFraction = MathUtils.saturate(
- (viewEnd - cornerAnimationTop) / cornerAnimationDistance);
- final float roundness = anv.isLastInSection() ? 1f : changeFraction * 1f;
- anv.setBottomRoundness(roundness, false);
-
- } else if (viewEnd < cornerAnimationTop) {
- // Fast scroll skips frames and leaves corners with unfinished rounding.
- // Reset top and bottom corners outside of animation bounds.
- anv.setBottomRoundness(anv.isLastInSection() ? 1f : 0f, false);
- }
-
- if (viewStart >= cornerAnimationTop) {
- // Round top corners within animation bounds
- final float changeFraction = MathUtils.saturate(
- (viewStart - cornerAnimationTop) / cornerAnimationDistance);
- final float roundness = anv.isFirstInSection() ? 1f : changeFraction * 1f;
- anv.setTopRoundness(roundness, false);
-
- } else if (viewStart < cornerAnimationTop) {
- // Fast scroll skips frames and leaves corners with unfinished rounding.
- // Reset top and bottom corners outside of animation bounds.
- anv.setTopRoundness(anv.isFirstInSection() ? 1f : 0f, false);
- }
- }
- previousAnv = anv;
+ updateCornerRoundnessOnScroll(anv, viewStart, shelfStart);
}
}
@@ -408,6 +350,62 @@
}
}
+ private void updateCornerRoundnessOnScroll(ActivatableNotificationView anv, float viewStart,
+ float shelfStart) {
+
+ final boolean isUnlockedHeadsUp = !mAmbientState.isOnKeyguard()
+ && !mAmbientState.isShadeExpanded()
+ && anv instanceof ExpandableNotificationRow
+ && ((ExpandableNotificationRow) anv).isHeadsUp();
+
+ final boolean isHunGoingToShade = mAmbientState.isShadeExpanded()
+ && anv == mAmbientState.getTrackedHeadsUpRow();
+
+ final boolean shouldUpdateCornerRoundness = viewStart < shelfStart
+ && !mHostLayoutController.isViewAffectedBySwipe(anv)
+ && !isUnlockedHeadsUp
+ && !isHunGoingToShade
+ && !mAmbientState.isPulsing()
+ && !mAmbientState.isDozing();
+
+ if (!shouldUpdateCornerRoundness) {
+ return;
+ }
+
+ final float viewEnd = viewStart + anv.getActualHeight();
+ final float cornerAnimationDistance = mCornerAnimationDistance
+ * mAmbientState.getExpansionFraction();
+ final float cornerAnimationTop = shelfStart - cornerAnimationDistance;
+
+ if (viewEnd >= cornerAnimationTop) {
+ // Round bottom corners within animation bounds
+ final float changeFraction = MathUtils.saturate(
+ (viewEnd - cornerAnimationTop) / cornerAnimationDistance);
+ anv.setBottomRoundness(anv.isLastInSection() ? 1f : changeFraction,
+ false /* animate */);
+
+ } else if (viewEnd < cornerAnimationTop) {
+ // Fast scroll skips frames and leaves corners with unfinished rounding.
+ // Reset top and bottom corners outside of animation bounds.
+ anv.setBottomRoundness(anv.isLastInSection() ? 1f : 0f,
+ false /* animate */);
+ }
+
+ if (viewStart >= cornerAnimationTop) {
+ // Round top corners within animation bounds
+ final float changeFraction = MathUtils.saturate(
+ (viewStart - cornerAnimationTop) / cornerAnimationDistance);
+ anv.setTopRoundness(anv.isFirstInSection() ? 1f : changeFraction,
+ false /* animate */);
+
+ } else if (viewStart < cornerAnimationTop) {
+ // Fast scroll skips frames and leaves corners with unfinished rounding.
+ // Reset top and bottom corners outside of animation bounds.
+ anv.setTopRoundness(anv.isFirstInSection() ? 1f : 0f,
+ false /* animate */);
+ }
+ }
+
/**
* Clips transient views to the top of the shelf - Transient views are only used for
* disappearing views/animations and need to be clipped correctly by the shelf to ensure they
@@ -632,8 +630,7 @@
transitionAmount = mAmbientState.isFullyHidden() ? 1 : 0;
} else {
transitionAmount = iconTransitionAmount;
- iconState.needsCannedAnimation = iconState.clampedAppearAmount != clampedAmount
- && !mNoAnimationsInThisFrame;
+ iconState.needsCannedAnimation = iconState.clampedAppearAmount != clampedAmount;
}
iconState.clampedAppearAmount = clampedAmount;
setIconTransformationAmount(view, transitionAmount);
@@ -734,29 +731,7 @@
private void updateRelativeOffset() {
mCollapsedIcons.getLocationOnScreen(mTmp);
- mRelativeOffset = mTmp[0];
getLocationOnScreen(mTmp);
- mRelativeOffset -= mTmp[0];
- }
-
- @Override
- public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- WindowInsets ret = super.onApplyWindowInsets(insets);
-
- // NotificationShelf drag from the status bar and the status bar dock on the top
- // of the display for current design so just focus on the top of ScreenDecorations.
- // In landscape or multiple window split mode, the NotificationShelf still drag from
- // the top and the physical notch/cutout goes to the right, left, or both side of the
- // display so it doesn't matter for the NotificationSelf in landscape.
- DisplayCutout displayCutout = insets.getDisplayCutout();
- mCutoutHeight = displayCutout == null || displayCutout.getSafeInsetTop() < 0
- ? 0 : displayCutout.getSafeInsetTop();
-
- return ret;
- }
-
- public void setMaxLayoutHeight(int maxLayoutHeight) {
- mMaxLayoutHeight = maxLayoutHeight;
}
/**
@@ -853,7 +828,6 @@
private class ShelfState extends ExpandableViewState {
private boolean hasItemsInStableShelf;
private ExpandableView firstViewInShelf;
- private ExpandableView firstViewInOverflowSection;
@Override
public void applyToView(View view) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
index 91415f27..05afc57f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
@@ -83,6 +83,7 @@
var rippleView: ChargingRippleView = ChargingRippleView(context, attrs = null)
init {
+ pluggedIn = batteryController.isPluggedIn
val batteryStateChangeCallback = object : BatteryController.BatteryStateChangeCallback {
override fun onBatteryLevelChanged(
level: Int,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
index 655ed41..33aa7c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
@@ -26,14 +26,18 @@
import android.provider.DeviceConfig
import android.util.Log
import android.view.View
+import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.phone.StatusBarWindowController
import com.android.systemui.statusbar.policy.CallbackController
import com.android.systemui.util.Assert
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.time.SystemClock
+import java.io.FileDescriptor
+import java.io.PrintWriter
import javax.inject.Inject
@@ -59,9 +63,10 @@
private val coordinator: SystemEventCoordinator,
private val chipAnimationController: SystemEventChipAnimationController,
private val statusBarWindowController: StatusBarWindowController,
+ private val dumpManager: DumpManager,
private val systemClock: SystemClock,
@Main private val executor: DelayableExecutor
-) : CallbackController<SystemStatusAnimationCallback> {
+) : CallbackController<SystemStatusAnimationCallback>, Dumpable {
companion object {
private const val PROPERTY_ENABLE_IMMERSIVE_INDICATOR = "enable_immersive_indicator"
@@ -71,10 +76,6 @@
PROPERTY_ENABLE_IMMERSIVE_INDICATOR, true)
}
- /** True from the time a scheduled event starts until it's animation finishes */
- var isActive = false
- private set
-
@SystemAnimationState var animationState: Int = IDLE
private set
@@ -88,6 +89,7 @@
init {
coordinator.attachScheduler(this)
+ dumpManager.registerDumpable(TAG, this)
}
fun onStatusEvent(event: StatusEvent) {
@@ -293,6 +295,20 @@
anim -> chipAnimationController.onChipAnimationUpdate(anim, animationState)
}
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+ pw.println("Scheduled event: $scheduledEvent")
+ pw.println("Has persistent privacy dot: $hasPersistentDot")
+ pw.println("Animation state: $animationState")
+ pw.println("Listeners:")
+ if (listeners.isEmpty()) {
+ pw.println("(none)")
+ } else {
+ listeners.forEach {
+ pw.println(" $it")
+ }
+ }
+ }
+
inner class ChipAnimatorAdapter(
@SystemAnimationState val endState: Int,
val viewCreator: (context: Context) -> View
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index c0fbf68..7afb015 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -393,6 +393,11 @@
override fun onDozingChanged(isDozing: Boolean) {
if (isDozing) {
setNotificationsVisible(visible = false, animate = false, increaseSpeed = false)
+ } else {
+ // We only unset the flag once we fully went asleep. If the user interrupts the
+ // animation in the middle, we have to abort the animation as well to make sure
+ // the notifications are visible again.
+ animatingScreenOff = false
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
index c1ffc22..8b1efb5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
@@ -98,20 +98,20 @@
int lineCount = mText.getLineCount();
return lineCount == 1 && lineCount == otherTvs.mText.getLineCount()
&& getEllipsisCount() == otherTvs.getEllipsisCount()
- && getViewHeight() != otherTvs.getViewHeight();
+ && getContentHeight() != otherTvs.getContentHeight();
}
@Override
- protected int getViewWidth() {
+ protected int getContentWidth() {
Layout l = mText.getLayout();
if (l != null) {
return (int) l.getLineWidth(0);
}
- return super.getViewWidth();
+ return super.getContentWidth();
}
@Override
- protected int getViewHeight() {
+ protected int getContentHeight() {
return mText.getLineHeight();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 74e62b6..9f9fba4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -41,6 +41,7 @@
public static final int TRANSFORM_X = 0x1;
public static final int TRANSFORM_Y = 0x10;
public static final int TRANSFORM_ALL = TRANSFORM_X | TRANSFORM_Y;
+ public static final int ALIGN_END_TAG = R.id.align_transform_end_tag;
private static final float UNDEFINED = -1f;
private static final int TRANSFORMATION_START_X = R.id.transformation_start_x_tag;
@@ -78,11 +79,13 @@
private boolean mSameAsAny;
private float mTransformationEndY = UNDEFINED;
private float mTransformationEndX = UNDEFINED;
+ private boolean mAlignEnd;
protected Interpolator mDefaultInterpolator = Interpolators.FAST_OUT_SLOW_IN;
public void initFrom(View view, TransformInfo transformInfo) {
mTransformedView = view;
mTransformInfo = transformInfo;
+ mAlignEnd = Boolean.TRUE.equals(view.getTag(ALIGN_END_TAG));
}
/**
@@ -135,13 +138,16 @@
final View transformedView = mTransformedView;
boolean transformX = (transformationFlags & TRANSFORM_X) != 0;
boolean transformY = (transformationFlags & TRANSFORM_Y) != 0;
- int viewHeight = getViewHeight();
- int otherHeight = otherState.getViewHeight();
- boolean differentHeight = otherHeight != viewHeight && otherHeight != 0 && viewHeight != 0;
- int viewWidth = getViewWidth();
- int otherWidth = otherState.getViewWidth();
- boolean differentWidth = otherWidth != viewWidth && otherWidth != 0 && viewWidth != 0;
- boolean transformScale = transformScale(otherState) && (differentHeight || differentWidth);
+ int ownContentHeight = getContentHeight();
+ int otherContentHeight = otherState.getContentHeight();
+ boolean differentHeight = otherContentHeight != ownContentHeight
+ && otherContentHeight != 0 && ownContentHeight != 0;
+ int ownContentWidth = getContentWidth();
+ int otherContentWidth = otherState.getContentWidth();
+ boolean differentWidth = otherContentWidth != ownContentWidth
+ && otherContentWidth != 0 && ownContentWidth != 0;
+ boolean transformScale = (differentHeight || differentWidth) && transformScale(otherState);
+ boolean transformRightEdge = transformRightEdge(otherState);
// lets animate the positions correctly
if (transformationAmount == 0.0f
|| transformX && getTransformationStartX() == UNDEFINED
@@ -159,7 +165,14 @@
if (customTransformation == null
|| !customTransformation.initTransformation(this, otherState)) {
if (transformX) {
- setTransformationStartX(otherPosition[0] - ownStablePosition[0]);
+ if (transformRightEdge) {
+ int otherViewWidth = otherState.getTransformedView().getWidth();
+ int ownViewWidth = transformedView.getWidth();
+ setTransformationStartX((otherPosition[0] + otherViewWidth)
+ - (ownStablePosition[0] + ownViewWidth));
+ } else {
+ setTransformationStartX(otherPosition[0] - ownStablePosition[0]);
+ }
}
if (transformY) {
setTransformationStartY(otherPosition[1] - ownStablePosition[1]);
@@ -167,15 +180,15 @@
// we also want to animate the scale if we're the same
View otherView = otherState.getTransformedView();
if (transformScale && differentWidth) {
- setTransformationStartScaleX(otherWidth * otherView.getScaleX()
- / (float) viewWidth);
- transformedView.setPivotX(0);
+ setTransformationStartScaleX(otherContentWidth * otherView.getScaleX()
+ / (float) ownContentWidth);
+ transformedView.setPivotX(transformRightEdge ? transformedView.getWidth() : 0);
} else {
setTransformationStartScaleX(UNDEFINED);
}
if (transformScale && differentHeight) {
- setTransformationStartScaleY(otherHeight * otherView.getScaleY()
- / (float) viewHeight);
+ setTransformationStartScaleY(otherContentHeight * otherView.getScaleY()
+ / (float) ownContentHeight);
transformedView.setPivotY(0);
} else {
setTransformationStartScaleY(UNDEFINED);
@@ -239,11 +252,19 @@
}
}
- protected int getViewWidth() {
+ /**
+ * The width of the content of this view. For some views, like TextViews, this will be the
+ * width of content inside the view which is transforming, rather than the view's full width.
+ */
+ protected int getContentWidth() {
return mTransformedView.getWidth();
}
- protected int getViewHeight() {
+ /**
+ * The height of the content of this view. For some views, like TextViews, this will be the
+ * height of content inside the view which is transforming, rather than the view's full height.
+ */
+ protected int getContentHeight() {
return mTransformedView.getHeight();
}
@@ -251,6 +272,12 @@
return sameAs(otherState);
}
+ protected boolean transformRightEdge(TransformState otherState) {
+ boolean alignEnd = mAlignEnd && otherState.mAlignEnd;
+ boolean isRtl = mTransformedView.isLayoutRtl() && otherState.mTransformedView.isLayoutRtl();
+ return alignEnd ^ isRtl;
+ }
+
/**
* Transforms the {@link #mTransformedView} to the given transformviewstate
* @param otherState the state to transform from
@@ -302,6 +329,9 @@
boolean transformX = (transformationFlags & TRANSFORM_X) != 0;
boolean transformY = (transformationFlags & TRANSFORM_Y) != 0;
boolean transformScale = transformScale(otherState);
+ boolean transformRightEdge = transformRightEdge(otherState);
+ int ownContentWidth = getContentWidth();
+ int otherContentWidth = otherState.getContentWidth();
// lets animate the positions correctly
if (transformationAmount == 0.0f) {
if (transformX) {
@@ -316,14 +346,13 @@
: transformedView.getTranslationY();
setTransformationStartY(start);
}
- View otherView = otherState.getTransformedView();
- if (transformScale && otherState.getViewWidth() != getViewWidth()) {
+ if (transformScale && otherContentWidth != ownContentWidth) {
setTransformationStartScaleX(transformedView.getScaleX());
- transformedView.setPivotX(0);
+ transformedView.setPivotX(transformRightEdge ? transformedView.getWidth() : 0);
} else {
setTransformationStartScaleX(UNDEFINED);
}
- if (transformScale && otherState.getViewHeight() != getViewHeight()) {
+ if (transformScale && otherState.getContentHeight() != getContentHeight()) {
setTransformationStartScaleY(transformedView.getScaleY());
transformedView.setPivotY(0);
} else {
@@ -336,7 +365,11 @@
int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
int[] ownPosition = getLaidOutLocationOnScreen();
if (transformX) {
- float endX = otherStablePosition[0] - ownPosition[0];
+ int ownViewWidth = transformedView.getWidth();
+ int otherViewWidth = otherState.getTransformedView().getWidth();
+ float endX = transformRightEdge
+ ? (otherStablePosition[0] + otherViewWidth) - (ownPosition[0] + ownViewWidth)
+ : otherStablePosition[0] - ownPosition[0];
float interpolation = interpolatedValue;
if (customTransformation != null) {
if (customTransformation.customTransformTarget(this, otherState)) {
@@ -370,19 +403,18 @@
interpolation));
}
if (transformScale) {
- View otherView = otherState.getTransformedView();
float transformationStartScaleX = getTransformationStartScaleX();
if (transformationStartScaleX != UNDEFINED) {
transformedView.setScaleX(
NotificationUtils.interpolate(transformationStartScaleX,
- (otherState.getViewWidth() / (float) getViewWidth()),
+ (otherContentWidth / (float) ownContentWidth),
interpolatedValue));
}
float transformationStartScaleY = getTransformationStartScaleY();
if (transformationStartScaleY != UNDEFINED) {
transformedView.setScaleY(
NotificationUtils.interpolate(transformationStartScaleY,
- (otherState.getViewHeight() / (float) getViewHeight()),
+ (otherState.getContentHeight() / (float) getContentHeight()),
interpolatedValue));
}
}
@@ -529,6 +561,7 @@
mSameAsAny = false;
mTransformationEndX = UNDEFINED;
mTransformationEndY = UNDEFINED;
+ mAlignEnd = false;
mDefaultInterpolator = Interpolators.FAST_OUT_SLOW_IN;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
index 2a15726..199692b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
@@ -151,6 +151,7 @@
mRightIcon = mView.findViewById(com.android.internal.R.id.right_icon);
if (mRightIcon != null) {
mRightIcon.setTag(ImageTransformState.ICON_TAG, getRightIcon(sbn.getNotification()));
+ mRightIcon.setTag(TransformState.ALIGN_END_TAG, true);
}
mLeftIcon = mView.findViewById(com.android.internal.R.id.left_icon);
if (mLeftIcon != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 66d2347..a189177 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -75,6 +75,7 @@
private int mExpandAnimationTopChange;
private ExpandableNotificationRow mExpandingNotification;
private float mHideAmount;
+ private float mNotificationScrimTop;
private boolean mAppearing;
private float mPulseHeight = MAX_PULSE_HEIGHT;
private float mDozeAmount = 0.0f;
@@ -255,6 +256,20 @@
return mHideAmount;
}
+ /**
+ * Set y position of top of notifications background scrim, relative to top of screen.
+ */
+ public void setNotificationScrimTop(float notificationScrimTop) {
+ mNotificationScrimTop = notificationScrimTop;
+ }
+
+ /**
+ * @return Y position of top of notifications background scrim, relative to top of screen.
+ */
+ public float getNotificationScrimTop() {
+ return mNotificationScrimTop;
+ }
+
public void setHideSensitive(boolean hideSensitive) {
mHideSensitive = hideSensitive;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index a804ae6..94edbd0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -963,7 +963,6 @@
@ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM)
private void setMaxLayoutHeight(int maxLayoutHeight) {
mMaxLayoutHeight = maxLayoutHeight;
- mShelf.setMaxLayoutHeight(maxLayoutHeight);
updateAlgorithmHeightAndPadding();
}
@@ -1009,9 +1008,7 @@
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
private void updateClippingToTopRoundedCorner() {
- Float clipStart = (float) mTopPadding
- + mStackTranslation
- + mAmbientState.getExpandAnimationTopChange();
+ Float clipStart = mAmbientState.getNotificationScrimTop();
Float clipEnd = clipStart + mCornerRadius;
boolean first = true;
for (int i = 0; i < getChildCount(); i++) {
@@ -1024,7 +1021,8 @@
boolean clip = clipStart > start && clipStart < end
|| clipEnd >= start && clipEnd <= end;
clip &= !(first && mScrollAdapter.isScrolledToTop());
- child.setDistanceToTopRoundness(ExpandableView.NO_ROUNDNESS);
+ child.setDistanceToTopRoundness(clip ? Math.max(start - clipStart, 0)
+ : ExpandableView.NO_ROUNDNESS);
first = false;
}
}
@@ -5147,8 +5145,8 @@
}
/**
- * Sets the extra top inset for the full shade transition. This is needed to compensate for
- * media transitioning to quick settings
+ * Sets the extra top inset for the full shade transition. This moves notifications down
+ * during the drag down.
*/
public void setExtraTopInsetForFullShadeTransition(float inset) {
mExtraTopInsetForFullShadeTransition = inset;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index d23a309..4432f54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -185,8 +185,17 @@
private ColorExtractor.OnColorsChangedListener mOnColorsChangedListener;
+ /**
+ * The total distance in pixels that the full shade transition takes to transition entirely to
+ * the full shade.
+ */
private int mTotalDistanceForFullShadeTransition;
- private int mTotalExtraMediaInsetFullShadeTransition;
+
+ /**
+ * The amount of movement the notifications do when transitioning to the full shade before
+ * reaching the overstrech
+ */
+ private int mNotificationDragDownMovement;
@VisibleForTesting
final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
@@ -255,8 +264,8 @@
};
private void updateResources() {
- mTotalExtraMediaInsetFullShadeTransition = mResources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_transition_extra_media_inset);
+ mNotificationDragDownMovement = mResources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_notification_movement);
mTotalDistanceForFullShadeTransition = mResources.getDimensionPixelSize(
R.dimen.lockscreen_shade_qs_transition_distance);
}
@@ -1410,15 +1419,13 @@
* shade. 0.0f means we're not transitioning yet.
*/
public void setTransitionToFullShadeAmount(float amount) {
- float extraTopInset;
- MediaHeaderView view = mKeyguardMediaController.getSinglePaneContainer();
- if (view == null || view.getHeight() == 0
- || mStatusBarStateController.getState() != KEYGUARD) {
- extraTopInset = 0;
- } else {
- extraTopInset = MathUtils.saturate(amount / mTotalDistanceForFullShadeTransition);
- extraTopInset = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(extraTopInset);
- extraTopInset = extraTopInset * mTotalExtraMediaInsetFullShadeTransition;
+ float extraTopInset = 0.0f;
+ if (mStatusBarStateController.getState() == KEYGUARD) {
+ float overallProgress = MathUtils.saturate(amount / mView.getHeight());
+ float transitionProgress = Interpolators.getOvershootInterpolation(overallProgress,
+ 0.6f,
+ (float) mTotalDistanceForFullShadeTransition / (float) mView.getHeight());
+ extraTopInset = transitionProgress * mNotificationDragDownMovement;
}
mView.setExtraTopInsetForFullShadeTransition(extraTopInset);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index e931ec4..86465b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -24,8 +24,8 @@
import android.view.View;
import android.view.ViewGroup;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.dagger.SilentHeader;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -156,9 +156,9 @@
private void updateClipping(StackScrollAlgorithmState algorithmState,
AmbientState ambientState) {
- float drawStart = !ambientState.isOnKeyguard()
- ? ambientState.getStackY() - ambientState.getScrollY() : 0;
- float clipStart = 0;
+ float drawStart = ambientState.isOnKeyguard() ? 0
+ : ambientState.getStackY() - ambientState.getScrollY();
+ float clipStart = ambientState.getNotificationScrimTop();
int childCount = algorithmState.visibleChildren.size();
boolean firstHeadsUp = true;
for (int i = 0; i < childCount; i++) {
@@ -380,11 +380,15 @@
ExpandableViewState viewState = view.getViewState();
viewState.location = ExpandableViewState.LOCATION_UNKNOWN;
- if (ambientState.isExpansionChanging() && !ambientState.isOnKeyguard()) {
- viewState.alpha = Interpolators.getNotificationScrimAlpha(
- ambientState.getExpansionFraction());
- } else {
- viewState.alpha = 1f - ambientState.getHideAmount();
+ final boolean isHunGoingToShade = ambientState.isShadeExpanded()
+ && view == ambientState.getTrackedHeadsUpRow();
+ if (!isHunGoingToShade) {
+ if (ambientState.isExpansionChanging() && !ambientState.isOnKeyguard()) {
+ viewState.alpha = Interpolators.getNotificationScrimAlpha(
+ ambientState.getExpansionFraction(), true /* notification */);
+ } else {
+ viewState.alpha = 1f - ambientState.getHideAmount();
+ }
}
if (view.mustStayOnScreen() && viewState.yTranslation >= 0) {
@@ -414,13 +418,15 @@
}
if (view instanceof FooterView) {
+ final boolean shadeClosed = !ambientState.isShadeExpanded();
final boolean isShelfShowing = algorithmState.firstViewInShelf != null;
final float footerEnd = algorithmState.mCurrentExpandedYPosition
+ view.getIntrinsicHeight();
final boolean noSpaceForFooter = footerEnd > ambientState.getStackEndHeight();
- viewState.hidden = isShelfShowing || noSpaceForFooter;
+ viewState.hidden = shadeClosed || isShelfShowing || noSpaceForFooter;
+
} else if (view != ambientState.getTrackedHeadsUpRow()) {
if (ambientState.isExpansionChanging()) {
// Show all views. Views below the shelf will later be clipped (essentially hidden)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 684760e..69360b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -30,7 +30,6 @@
import android.app.Fragment;
import android.os.Bundle;
import android.os.Parcelable;
-import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
@@ -230,7 +229,6 @@
if (displayId != getContext().getDisplayId()) {
return;
}
- Log.d(TAG, "disable: ");
state1 = adjustDisableFlags(state1);
final int old1 = mDisabled1;
final int diff1 = state1 ^ old1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 7f919b5..4d8e7de3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -24,6 +24,8 @@
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK;
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON;
import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_UNLOCK;
+import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE;
+import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -39,7 +41,6 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
-import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -49,13 +50,10 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.MediaStore;
-import android.provider.Settings;
import android.service.media.CameraPrewarmService;
import android.service.quickaccesswallet.GetWalletCardsError;
-import android.service.quickaccesswallet.GetWalletCardsRequest;
import android.service.quickaccesswallet.GetWalletCardsResponse;
import android.service.quickaccesswallet.QuickAccessWalletClient;
-import android.service.quickaccesswallet.QuickAccessWalletClientImpl;
import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -71,7 +69,6 @@
import android.widget.TextView;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.widget.LockPatternUtils;
@@ -97,11 +94,9 @@
import com.android.systemui.statusbar.policy.PreviewInflater;
import com.android.systemui.tuner.LockscreenFragment.LockButtonFactory;
import com.android.systemui.tuner.TunerService;
-import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.systemui.wallet.ui.WalletActivity;
-import java.util.concurrent.Executor;
-
/**
* Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
* text.
@@ -137,10 +132,9 @@
private KeyguardAffordanceView mLeftAffordanceView;
private ImageView mWalletButton;
- private boolean mWalletEnabled = false;
private boolean mHasCard = false;
private WalletCardRetriever mCardRetriever = new WalletCardRetriever();
- private QuickAccessWalletClient mQuickAccessWalletClient;
+ private QuickAccessWalletController mQuickAccessWalletController;
private ViewGroup mIndicationArea;
private TextView mIndicationText;
@@ -159,7 +153,6 @@
private StatusBar mStatusBar;
private KeyguardAffordanceHelper mAffordanceHelper;
private FalsingManager mFalsingManager;
- @Nullable private Executor mUiExecutor;
private boolean mUserSetupComplete;
private boolean mPrewarmBound;
private Messenger mPrewarmMessenger;
@@ -193,8 +186,6 @@
private int mBurnInYOffset;
private ActivityIntentHelper mActivityIntentHelper;
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private ContentObserver mWalletPreferenceObserver;
- private SecureSettings mSecureSettings;
public KeyguardBottomAreaView(Context context) {
this(context, null);
@@ -332,8 +323,9 @@
getContext().unregisterReceiver(mDevicePolicyReceiver);
mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
- if (mWalletPreferenceObserver != null) {
- mSecureSettings.unregisterContentObserver(mWalletPreferenceObserver);
+ if (mQuickAccessWalletController != null) {
+ mQuickAccessWalletController.unregisterWalletChangeObservers(
+ WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
}
}
@@ -456,7 +448,10 @@
}
private void updateWalletVisibility() {
- if (mDozing || !mWalletEnabled || !mHasCard) {
+ if (mDozing
+ || mQuickAccessWalletController == null
+ || !mQuickAccessWalletController.isWalletEnabled()
+ || !mHasCard) {
mWalletButton.setVisibility(GONE);
mIndicationArea.setPadding(0, 0, 0, 0);
} else {
@@ -690,7 +685,9 @@
@Override
public void onKeyguardShowingChanged() {
if (mKeyguardStateController.isShowing()) {
- queryWalletCards();
+ if (mQuickAccessWalletController != null) {
+ mQuickAccessWalletController.queryWalletCards(mCardRetriever);
+ }
}
}
@@ -935,50 +932,17 @@
/**
* Initialize the wallet feature, only enabling if the feature is enabled within the platform.
*/
- public void initWallet(QuickAccessWalletClient client, Executor uiExecutor,
- SecureSettings secureSettings) {
- mQuickAccessWalletClient = client;
- mSecureSettings = secureSettings;
- setupWalletPreferenceObserver();
- updateWalletPreference();
-
- mUiExecutor = uiExecutor;
- queryWalletCards();
+ public void initWallet(
+ QuickAccessWalletController controller) {
+ mQuickAccessWalletController = controller;
+ mQuickAccessWalletController.setupWalletChangeObservers(
+ mCardRetriever, WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
+ mQuickAccessWalletController.updateWalletPreference();
+ mQuickAccessWalletController.queryWalletCards(mCardRetriever);
updateWalletVisibility();
}
- private void setupWalletPreferenceObserver() {
- if (mWalletPreferenceObserver == null) {
- mWalletPreferenceObserver = new ContentObserver(null /* handler */) {
- @Override
- public void onChange(boolean selfChange) {
- mUiExecutor.execute(() -> updateWalletPreference());
- }
- };
-
- mSecureSettings.registerContentObserver(
- Settings.Secure.getUriFor(QuickAccessWalletClientImpl.SETTING_KEY),
- false /* notifyForDescendants */,
- mWalletPreferenceObserver);
- }
- }
-
- private void updateWalletPreference() {
- mWalletEnabled = mQuickAccessWalletClient.isWalletFeatureAvailable()
- && mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked();
- }
-
- private void queryWalletCards() {
- if (!mWalletEnabled || mUiExecutor == null) {
- return;
- }
- GetWalletCardsRequest request =
- new GetWalletCardsRequest(1 /* cardWidth */, 1 /* cardHeight */,
- 1 /* iconSizePx */, 1 /* maxCards */);
- mQuickAccessWalletClient.getWalletCards(mUiExecutor, request, mCardRetriever);
- }
-
private void onWalletClick(View v) {
// More coming here; need to inform the user about how to proceed
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
@@ -991,12 +955,13 @@
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
} else {
- if (mQuickAccessWalletClient.createWalletIntent() == null) {
+ if (mQuickAccessWalletController.getWalletClient().createWalletIntent() == null) {
Log.w(TAG, "Could not get intent of the wallet app.");
return;
}
mActivityStarter.postStartActivityDismissingKeyguard(
- mQuickAccessWalletClient.createWalletIntent(), /* delay= */ 0);
+ mQuickAccessWalletController.getWalletClient().createWalletIntent(),
+ /* delay= */ 0);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index f4710f4..7c2723d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -325,7 +325,9 @@
*/
private float getClockAlpha(int y) {
float alphaKeyguard = Math.max(0, y / Math.max(1f, getClockY(1f, mDarkAmount)));
- alphaKeyguard *= (1f - mQsExpansion);
+ float qsAlphaFactor = MathUtils.saturate(mQsExpansion / 0.3f);
+ qsAlphaFactor = 1f - qsAlphaFactor;
+ alphaKeyguard *= qsAlphaFactor;
alphaKeyguard = Interpolators.ACCELERATE.getInterpolation(alphaKeyguard);
return MathUtils.lerp(alphaKeyguard, 1f, mDarkAmount);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index d84bb90..68e2070 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -142,7 +142,6 @@
Animator yTranslate =
ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, 0, -getYTranslationPixels());
yTranslate.setDuration(getFadeOutDuration());
- fadeOut.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
animatorSet.playTogether(fadeOut, yTranslate);
return animatorSet;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 0c4bec2c..eef2420 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -116,6 +116,12 @@
// right and left padding applied to this view to account for cutouts and rounded corners
private Pair<Integer, Integer> mPadding = new Pair(0, 0);
+ /**
+ * The clipping on the top
+ */
+ private int mTopClipping;
+ private final Rect mClipRect = new Rect(0, 0, 0, 0);
+
public KeyguardStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
mUserManager = UserManager.get(getContext());
@@ -549,4 +555,25 @@
public void onSystemChromeAnimationUpdate(ValueAnimator anim) {
mSystemIconsContainer.setAlpha((float) anim.getAnimatedValue());
}
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ updateClipping();
+ }
+
+ /**
+ * Set the clipping on the top of the view.
+ */
+ public void setTopClipping(int topClipping) {
+ if (topClipping != mTopClipping) {
+ mTopClipping = topClipping;
+ updateClipping();
+ }
+ }
+
+ private void updateClipping() {
+ mClipRect.set(0, mTopClipping, getWidth(), getHeight());
+ setClipBounds(mClipRect);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 0f3af09..d9ba494 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -24,6 +24,8 @@
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
+import com.android.systemui.R;
+
public class NotificationPanelView extends PanelView {
private static final boolean DEBUG = false;
@@ -92,6 +94,10 @@
mRtlChangeListener = listener;
}
+ public TapAgainView getTapAgainView() {
+ return findViewById(R.id.shade_falsing_tap_again);
+ }
+
interface RtlChangeListener {
void onRtlPropertielsChanged(int layoutDirection);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index e4e1be2..7737420 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -27,7 +27,6 @@
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
-import static com.android.systemui.util.Utils.shouldUseSplitNotificationShade;
import static java.lang.Float.isNaN;
@@ -54,7 +53,6 @@
import android.os.SystemClock;
import android.os.UserManager;
import android.os.VibrationEffect;
-import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.util.Log;
import android.util.MathUtils;
import android.view.DisplayCutout;
@@ -97,8 +95,8 @@
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeLog;
-import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
+import com.android.systemui.fragments.FragmentService;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
@@ -153,6 +151,7 @@
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.util.Utils;
import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.wm.shell.animation.FlingAnimationUtils;
import java.io.FileDescriptor;
@@ -306,14 +305,17 @@
private final KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
private final KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
private final QSDetailDisplayer mQSDetailDisplayer;
+ private final FragmentService mFragmentService;
private final FeatureFlags mFeatureFlags;
private final ScrimController mScrimController;
private final PrivacyDotViewController mPrivacyDotViewController;
+ private final QuickAccessWalletController mQuickAccessWalletController;
// Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
// If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications
private final int mMaxKeyguardNotifications;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ private final TapAgainViewController mTapAgainViewController;
private boolean mShouldUseSplitNotificationShade;
// Current max allowed keyguard notifications determined by measuring the panel
private int mMaxAllowedKeyguardNotifications;
@@ -331,7 +333,7 @@
private LockIconViewController mLockIconViewController;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
private boolean mAnimateNextPositionUpdate;
-
+ private float mQuickQsOffsetHeight;
private int mTrackingPointer;
private VelocityTracker mQsVelocityTracker;
private boolean mQsTracking;
@@ -372,6 +374,7 @@
private float mDownX;
private float mDownY;
private int mDisplayCutoutTopInset = 0; // in pixels
+ private int mDisplayCutoutLeftInset = 0; // in pixels
private int mSplitShadeNotificationsTopPadding;
private final KeyguardClockPositionAlgorithm
@@ -507,6 +510,13 @@
private float mSectionPadding;
/**
+ * The padding between the start of notifications and the qs boundary on the lockscreen.
+ * On lockscreen, notifications aren't inset this extra amount, but we still want the
+ * qs boundary to be padded.
+ */
+ private int mLockscreenNotificationQSPadding;
+
+ /**
* The amount of progress we are currently in if we're transitioning to the full shade.
* 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
* shade. This value can also go beyond 1.1 when we're overshooting!
@@ -528,7 +538,7 @@
/**
* The maximum overshoot allowed for the top padding for the full shade transition
*/
- private int mMaxOverscrollAmountForDragDown;
+ private int mMaxOverscrollAmountForPulse;
/**
* Should we animate the next bounds update
@@ -572,8 +582,8 @@
private int mScrimCornerRadius;
private int mScreenCornerRadius;
private int mNotificationScrimPadding;
+ private boolean mQSAnimatingHiddenFromCollapsed;
- private final QuickAccessWalletClient mQuickAccessWalletClient;
private final Executor mUiExecutor;
private final SecureSettings mSecureSettings;
@@ -603,7 +613,12 @@
private final FalsingTapListener mFalsingTapListener = new FalsingTapListener() {
@Override
public void onDoubleTapRequired() {
- showTransientIndication(R.string.notification_tap_again);
+ if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED) {
+ mTapAgainViewController.show();
+ } else {
+ mKeyguardIndicationController.showTransientIndication(
+ R.string.notification_tap_again);
+ }
mVibratorHelper.vibrate(VibrationEffect.EFFECT_STRENGTH_MEDIUM);
}
};
@@ -649,9 +664,11 @@
AmbientState ambientState,
LockIconViewController lockIconViewController,
FeatureFlags featureFlags,
- QuickAccessWalletClient quickAccessWalletClient,
KeyguardMediaController keyguardMediaController,
PrivacyDotViewController privacyDotViewController,
+ TapAgainViewController tapAgainViewController,
+ FragmentService fragmentService,
+ QuickAccessWalletController quickAccessWalletController,
@Main Executor uiExecutor,
SecureSettings secureSettings) {
super(view, falsingManager, dozeLog, keyguardStateController,
@@ -662,6 +679,7 @@
mVibratorHelper = vibratorHelper;
mKeyguardMediaController = keyguardMediaController;
mPrivacyDotViewController = privacyDotViewController;
+ mQuickAccessWalletController = quickAccessWalletController;
mMetricsLogger = metricsLogger;
mActivityManager = activityManager;
mConfigurationController = configurationController;
@@ -678,6 +696,7 @@
mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory;
mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory;
mQSDetailDisplayer = qsDetailDisplayer;
+ mFragmentService = fragmentService;
mKeyguardUserSwitcherEnabled = mResources.getBoolean(
com.android.internal.R.bool.config_keyguardUserSwitcher);
mKeyguardQsUserSwitchEnabled =
@@ -703,7 +722,7 @@
mScrimController.setClipsQsScrim(!mShouldUseSplitNotificationShade);
mUserManager = userManager;
mMediaDataManager = mediaDataManager;
- mQuickAccessWalletClient = quickAccessWalletClient;
+ mTapAgainViewController = tapAgainViewController;
mUiExecutor = uiExecutor;
mSecureSettings = secureSettings;
pulseExpansionHandler.setPulseExpandAbortListener(() -> {
@@ -811,7 +830,7 @@
amount -> {
float progress = amount / mView.getHeight();
float overstretch = Interpolators.getOvershootInterpolation(progress,
- (float) mMaxOverscrollAmountForDragDown / mView.getHeight(),
+ (float) mMaxOverscrollAmountForPulse / mView.getHeight(),
0.2f);
setOverStrechAmount(overstretch);
});
@@ -842,6 +861,8 @@
if (mShouldUseSplitNotificationShade) {
updateResources();
}
+
+ mTapAgainViewController.init();
}
@Override
@@ -872,14 +893,16 @@
R.dimen.heads_up_status_bar_padding);
mDistanceForQSFullShadeTransition = mResources.getDimensionPixelSize(
R.dimen.lockscreen_shade_qs_transition_distance);
- mMaxOverscrollAmountForDragDown = mResources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_max_top_overshoot);
+ mMaxOverscrollAmountForPulse = mResources.getDimensionPixelSize(
+ R.dimen.pulse_expansion_max_top_overshoot);
mScrimCornerRadius = mResources.getDimensionPixelSize(
R.dimen.notification_scrim_corner_radius);
mScreenCornerRadius = mResources.getDimensionPixelSize(
com.android.internal.R.dimen.rounded_corner_radius);
mNotificationScrimPadding = mResources.getDimensionPixelSize(
R.dimen.notification_side_paddings);
+ mLockscreenNotificationQSPadding = mResources.getDimensionPixelSize(
+ R.dimen.notification_side_paddings);
}
private void updateViewControllers(KeyguardStatusView keyguardStatusView,
@@ -942,6 +965,8 @@
}
public void updateResources() {
+ mQuickQsOffsetHeight = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.quick_qs_offset_height);
mSplitShadeNotificationsTopPadding =
mResources.getDimensionPixelSize(R.dimen.notifications_top_padding_split_shade);
int qsWidth = mResources.getDimensionPixelSize(R.dimen.qs_panel_width);
@@ -1097,7 +1122,7 @@
mKeyguardBottomArea.setFalsingManager(mFalsingManager);
if (mFeatureFlags.isQuickAccessWalletEnabled()) {
- mKeyguardBottomArea.initWallet(mQuickAccessWalletClient, mUiExecutor, mSecureSettings);
+ mKeyguardBottomArea.initWallet(mQuickAccessWalletController);
}
}
@@ -1234,7 +1259,7 @@
bypassEnabled, getUnlockedStackScrollerPadding(),
computeQsExpansionFraction(),
mDisplayCutoutTopInset,
- shouldUseSplitNotificationShade(mFeatureFlags, mResources));
+ mShouldUseSplitNotificationShade);
mClockPositionAlgorithm.run(mClockPositionResult);
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
boolean animateClock = animate || mAnimateNextPositionUpdate;
@@ -1418,7 +1443,7 @@
}
mStatusBar.getGutsManager().closeAndSaveGuts(true /* leavebehind */, true /* force */,
true /* controls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
- if (animate) {
+ if (animate && !isFullyCollapsed()) {
animateCloseQs(true /* animateAway */);
} else {
closeQs();
@@ -1702,6 +1727,11 @@
}
private float computeQsExpansionFraction() {
+ if (mQSAnimatingHiddenFromCollapsed) {
+ // When hiding QS from collapsed state, the expansion can sometimes temporarily
+ // be larger than 0 because of the timing, leading to flickers.
+ return 0.0f;
+ }
return Math.min(
1f, (mQsExpansionHeight - mQsMinExpansionHeight) / (mQsMaxExpansionHeight
- mQsMinExpansionHeight));
@@ -2169,13 +2199,14 @@
// can be wrong during transitions when waiting for the keyguard to unlock
top = mTransitionToFullShadeQSPosition;
} else {
- float notificationTop = getQSEdgePosition();
+ final float notificationTop = getQSEdgePosition();
+ mAmbientState.setNotificationScrimTop(notificationTop);
top = (int) (isOnKeyguard() ? Math.min(qsPanelBottomY, notificationTop)
: notificationTop);
}
bottom = getView().getBottom();
- left = getView().getLeft();
- right = getView().getRight();
+ left = getView().getLeft() - mDisplayCutoutLeftInset;
+ right = getView().getRight() - mDisplayCutoutLeftInset;
} else if (qsPanelBottomY > 0) { // so bounds are empty on lockscreen
top = Math.min(qsPanelBottomY, mSplitShadeNotificationsTopPadding);
bottom = mNotificationStackScrollLayoutController.getHeight();
@@ -2234,24 +2265,30 @@
boolean visible) {
// Fancy clipping for quick settings
int radius = mScrimCornerRadius;
+ int statusBarClipTop = 0;
+ boolean clipStatusView = false;
if (!mShouldUseSplitNotificationShade) {
// The padding on this area is large enough that we can use a cheaper clipping strategy
mKeyguardStatusAreaClipBounds.set(left, top, right, bottom);
- mKeyguardStatusViewController.setClipBounds(visible
- ? mKeyguardStatusAreaClipBounds : null);
+ clipStatusView = visible;
radius = (int) MathUtils.lerp(mScreenCornerRadius, mScrimCornerRadius,
Math.min(top / (float) mScrimCornerRadius, 1f));
+ statusBarClipTop = top - mKeyguardStatusBar.getTop();
}
if (mQs != null) {
mQs.setFancyClipping(top, bottom, radius, visible);
}
+ mKeyguardStatusViewController.setClipBounds(
+ clipStatusView ? mKeyguardStatusAreaClipBounds : null);
mScrimController.setNotificationsBounds(left, top, right, bottom);
mScrimController.setScrimCornerRadius(radius);
+ mKeyguardStatusBar.setTopClipping(statusBarClipTop);
}
private float getQSEdgePosition() {
// TODO: replace StackY with unified calculation
- return mAmbientState.getStackY() - mAmbientState.getScrollY();
+ return Math.max(mQuickQsOffsetHeight * mAmbientState.getExpansionFraction(),
+ mAmbientState.getStackY() - mAmbientState.getScrollY());
}
private int calculateQsBottomPosition(float qsExpansionFraction) {
@@ -2362,7 +2399,6 @@
public void setTransitionToFullShadeAmount(float pxAmount, boolean animate, long delay) {
mAnimateNextNotificationBounds = animate && !mShouldUseSplitNotificationShade;
mNotificationBoundsAnimationDelay = delay;
- float progress = MathUtils.saturate(pxAmount / mView.getHeight());
float endPosition = 0;
if (pxAmount > 0.0f) {
@@ -2370,29 +2406,28 @@
&& !mMediaDataManager.hasActiveMedia()) {
// No notifications are visible, let's animate to the height of qs instead
if (mQs != null) {
- // Let's interpolate to the header height
- endPosition = mQs.getHeader().getHeight();
+ // Let's interpolate to the header height instead of the top padding,
+ // because the toppadding is way too low because of the large clock.
+ // we still want to take into account the edgePosition though as that nicely
+ // overshoots in the stackscroller
+ endPosition = getQSEdgePosition()
+ - mNotificationStackScrollLayoutController.getTopPadding()
+ + mQs.getHeader().getHeight();
}
} else {
// Interpolating to the new bottom edge position!
- endPosition = getQSEdgePosition() - mOverStretchAmount;
-
- // If we have media, we need to put the boundary below it, as the media header
- // still uses the space during the transition.
- endPosition +=
- mNotificationStackScrollLayoutController.getFullShadeTransitionInset();
+ endPosition = getQSEdgePosition()
+ + mNotificationStackScrollLayoutController.getFullShadeTransitionInset();
+ if (isOnKeyguard()) {
+ endPosition -= mLockscreenNotificationQSPadding;
+ }
}
}
// Calculate the overshoot amount such that we're reaching the target after our desired
// distance, but only reach it fully once we drag a full shade length.
- float transitionProgress = 0;
- if (endPosition != 0 && progress != 0) {
- transitionProgress = Interpolators.getOvershootInterpolation(progress,
- mMaxOverscrollAmountForDragDown / endPosition,
- (float) mDistanceForQSFullShadeTransition / (float) mView.getHeight());
- }
- mTransitioningToFullShadeProgress = transitionProgress;
+ mTransitioningToFullShadeProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+ MathUtils.saturate(pxAmount / mDistanceForQSFullShadeTransition));
int position = (int) MathUtils.lerp((float) 0, endPosition,
mTransitioningToFullShadeProgress);
@@ -2400,8 +2435,6 @@
// we want at least 1 pixel otherwise the panel won't be clipped
position = Math.max(1, position);
}
- float overStretchAmount = Math.max(position - endPosition, 0.0f);
- setOverStrechAmount(overStretchAmount);
mTransitionToFullShadeQSPosition = position;
updateQsExpansion();
}
@@ -2504,6 +2537,7 @@
@Override
public void onAnimationEnd(Animator animation) {
+ mQSAnimatingHiddenFromCollapsed = false;
mAnimatingQS = false;
notifyExpandingFinished();
mNotificationStackScrollLayoutController.resetCheckSnoozeLeavebehind();
@@ -2520,6 +2554,7 @@
animator.start();
mQsExpansionAnimator = animator;
mQsAnimatorExpand = expanding;
+ mQSAnimatingHiddenFromCollapsed = computeQsExpansionFraction() == 0.0f && target == 0;
}
/**
@@ -3670,10 +3705,6 @@
updateMaxDisplayedNotifications(true);
}
- public void showTransientIndication(int id) {
- mKeyguardIndicationController.showTransientIndication(id);
- }
-
public void setAlpha(float alpha) {
mView.setAlpha(alpha);
}
@@ -4259,7 +4290,8 @@
private class OnAttachStateChangeListener implements View.OnAttachStateChangeListener {
@Override
public void onViewAttachedToWindow(View v) {
- FragmentHostManager.get(mView).addTagListener(QS.TAG, mFragmentListener);
+ mFragmentService.getFragmentHostManager(mView)
+ .addTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.addCallback(mStatusBarStateListener);
mConfigurationController.addCallback(mConfigurationListener);
mUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
@@ -4273,7 +4305,8 @@
@Override
public void onViewDetachedFromWindow(View v) {
- FragmentHostManager.get(mView).removeTagListener(QS.TAG, mFragmentListener);
+ mFragmentService.getFragmentHostManager(mView)
+ .removeTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
mConfigurationController.removeCallback(mConfigurationListener);
mUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
@@ -4414,6 +4447,7 @@
public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
final DisplayCutout displayCutout = v.getRootWindowInsets().getDisplayCutout();
mDisplayCutoutTopInset = displayCutout != null ? displayCutout.getSafeInsetTop() : 0;
+ mDisplayCutoutLeftInset = displayCutout != null ? displayCutout.getSafeInsetLeft() : 0;
mNavigationBarBottomHeight = insets.getStableInsetBottom();
updateMaxHeadsUpTranslation();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index ae018ba..52f9aca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -152,6 +152,16 @@
mCallbacks.add(new WeakReference<StatusBarWindowCallback>(callback));
}
+ @Override
+ public void unregisterCallback(StatusBarWindowCallback callback) {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ if (mCallbacks.get(i).get() == callback) {
+ mCallbacks.remove(i);
+ return;
+ }
+ }
+ }
+
/**
* Register a listener to monitor scrims visibility
* @param listener A listener to monitor scrims visibility
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 7c63763..b92f7c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -548,8 +548,11 @@
*/
public void setNotificationsBounds(float left, float top, float right, float bottom) {
if (mClipsQsScrim) {
- // "top - 1" to have 1 px of scrims overlap, see: b/186644628
- mNotificationsScrim.setDrawableBounds(left, top - 1, right, bottom);
+ // notification scrim's rounded corners are anti-aliased, but clipping of the QS scrim
+ // can't be and it's causing jagged corners. That's why notification scrim needs
+ // to overlap QS scrim by one pixel - both vertically (top - 1) and
+ // horizontally (left - 1 and right + 1), see: b/186644628
+ mNotificationsScrim.setDrawableBounds(left - 1, top - 1, right + 1, bottom);
mScrimBehind.setBottomEdgePosition((int) top);
} else {
mNotificationsScrim.setDrawableBounds(left, top, right, bottom);
@@ -883,7 +886,7 @@
}
private float getInterpolatedFraction() {
- return Interpolators.getNotificationScrimAlpha(mPanelExpansion);
+ return Interpolators.getNotificationScrimAlpha(mPanelExpansion, false /* notification */);
}
private void setScrimAlpha(ScrimView scrim, float alpha) {
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 eec896a..c27497e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -73,9 +73,9 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
-import android.graphics.RectF;
import android.media.AudioAttributes;
import android.metrics.LogMaker;
import android.net.Uri;
@@ -150,6 +150,7 @@
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.DelegateLaunchAnimatorController;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.biometrics.AuthRippleController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.camera.CameraIntents;
import com.android.systemui.charging.WirelessChargingAnimation;
@@ -326,9 +327,15 @@
public static final int FADE_KEYGUARD_DURATION = 300;
public static final int FADE_KEYGUARD_DURATION_PULSING = 96;
+ public static final long[] CAMERA_LAUNCH_GESTURE_VIBRATION_TIMINGS =
+ new long[]{20, 20, 20, 20, 100, 20};
+ public static final int[] CAMERA_LAUNCH_GESTURE_VIBRATION_AMPLITUDES =
+ new int[]{39, 82, 139, 213, 0, 127};
- /** If true, the system is in the half-boot-to-decryption-screen state.
- * Prudently disable QS and notifications. */
+ /**
+ * If true, the system is in the half-boot-to-decryption-screen state.
+ * Prudently disable QS and notifications.
+ */
public static final boolean ONLY_CORE_APPS;
/** If true, the lockscreen will show a distinct wallpaper */
@@ -380,6 +387,7 @@
protected NotificationShadeWindowView mNotificationShadeWindowView;
protected StatusBarWindowView mPhoneStatusBarWindow;
protected PhoneStatusBarView mStatusBarView;
+ private AuthRippleController mAuthRippleController;
private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
protected NotificationShadeWindowController mNotificationShadeWindowController;
protected StatusBarWindowController mStatusBarWindowController;
@@ -456,6 +464,7 @@
protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final BrightnessSlider.Factory mBrightnessSliderFactory;
private final FeatureFlags mFeatureFlags;
+ private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private final List<ExpansionChangedListener> mExpansionChangedListeners;
@@ -600,7 +609,7 @@
private int mLastCameraLaunchSource;
protected PowerManager.WakeLock mGestureWakeLock;
private Vibrator mVibrator;
- private long[] mCameraLaunchGestureVibePattern;
+ private VibrationEffect mCameraLaunchGestureVibrationEffect;
private final int[] mTmpInt2 = new int[2];
@@ -877,6 +886,8 @@
mAnimationScheduler = animationScheduler;
mStatusBarLocationPublisher = locationPublisher;
mFeatureFlags = featureFlags;
+ mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
+
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
lockscreenShadeTransitionController.setStatusbar(this);
@@ -1311,12 +1322,8 @@
mGestureWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
"GestureWakeLock");
mVibrator = mContext.getSystemService(Vibrator.class);
- int[] pattern = mContext.getResources().getIntArray(
- R.array.config_cameraLaunchGestureVibePattern);
- mCameraLaunchGestureVibePattern = new long[pattern.length];
- for (int i = 0; i < pattern.length; i++) {
- mCameraLaunchGestureVibePattern[i] = pattern[i];
- }
+ mCameraLaunchGestureVibrationEffect = getCameraGestureVibrationEffect(
+ mVibrator, context.getResources());
// receive broadcasts
registerBroadcastReceiver();
@@ -1365,7 +1372,8 @@
// are already animating the keyguard dismiss (since we will need to either finish or cancel
// the animation).
if (trackingTouch
- || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) {
+ || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()
+ || mKeyguardUnlockAnimationController.isUnlockingWithSmartSpaceTransition()) {
mKeyguardStateController.notifyKeyguardDismissAmountChanged(
1f - expansion, trackingTouch);
}
@@ -1556,7 +1564,9 @@
mPhoneStatusBarWindow = mSuperStatusBarViewFactory.getStatusBarWindowView();
mNotificationPanelViewController = statusBarComponent.getNotificationPanelViewController();
statusBarComponent.getLockIconViewController().init();
- statusBarComponent.getAuthRippleController().init();
+
+ mAuthRippleController = statusBarComponent.getAuthRippleController();
+ mAuthRippleController.init();
}
protected void startKeyguard() {
@@ -2801,7 +2811,7 @@
int[] result = new int[]{ActivityManager.START_CANCELED};
mActivityLaunchAnimator.startIntentWithAnimation(animController,
- areLaunchAnimationsEnabled(), (adapter) -> {
+ areLaunchAnimationsEnabled(), intent.getPackage(), (adapter) -> {
ActivityOptions options = new ActivityOptions(
getActivityOptions(mDisplayId, adapter));
options.setDisallowEnterPictureInPictureWhileLaunching(
@@ -3609,10 +3619,16 @@
boolean visibleNotOccluded = mStatusBarKeyguardViewManager.isShowing()
&& !mStatusBarKeyguardViewManager.isOccluded();
+ // If we're dozing and we'll be animating the screen off, the keyguard isn't currently
+ // visible but will be shortly for the animation, so we should proceed as if it's visible.
+ boolean visibleNotOccludedOrWillBe =
+ visibleNotOccluded || (mDozing && mDozeParameters.shouldControlUnlockedScreenOff());
+
boolean wakeAndUnlock = mBiometricUnlockController.getMode()
== BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup() && !wakeAndUnlock)
- || (mDozing && mDozeServiceHost.shouldAnimateScreenOff() && visibleNotOccluded);
+ || (mDozing && mDozeServiceHost.shouldAnimateScreenOff()
+ && visibleNotOccludedOrWillBe);
mNotificationPanelViewController.setDozing(mDozing, animate, mWakeUpTouchLocation);
updateQsExpansionEnabled();
@@ -3791,7 +3807,8 @@
@Override
public void onDozeAmountChanged(float linear, float eased) {
- if (mFeatureFlags.useNewLockscreenAnimations()) {
+ if (mFeatureFlags.useNewLockscreenAnimations()
+ && !mCircleRevealAnimator.isRunning()) {
mLightRevealScrim.setRevealAmount(1f - linear);
}
}
@@ -3828,6 +3845,23 @@
Trace.endSection();
}
+ /**
+ * Update the parameters for the dozing circle reveal that animates when the user authenticates
+ * from AOD using the fingerprint sensor.
+ */
+ public void updateCircleReveal() {
+ final PointF fpLocation = mAuthRippleController.getFingerprintSensorLocation();
+ if (fpLocation != null) {
+ mCircleReveal =
+ new CircleReveal(
+ fpLocation.x,
+ fpLocation.y,
+ 0,
+ Math.max(Math.max(fpLocation.x, getDisplayWidth() - fpLocation.x),
+ Math.max(fpLocation.y, getDisplayHeight() - fpLocation.y)));
+ }
+ }
+
private void startCircleReveal() {
mLightRevealScrim.setRevealEffect(mCircleReveal);
mCircleRevealAnimator.cancel();
@@ -3840,7 +3874,6 @@
private boolean shouldShowCircleReveal() {
return mCircleReveal != null && !mCircleRevealAnimator.isRunning()
- && mKeyguardUpdateMonitor.isUdfpsEnrolled()
&& mBiometricUnlockController.getBiometricType() == FINGERPRINT;
}
@@ -4062,12 +4095,37 @@
private void vibrateForCameraGesture() {
// Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
- mVibrator.vibrate(mCameraLaunchGestureVibePattern, -1 /* repeat */);
+ mVibrator.vibrate(mCameraLaunchGestureVibrationEffect);
+ }
+
+ private static VibrationEffect getCameraGestureVibrationEffect(Vibrator vibrator,
+ Resources resources) {
+ if (vibrator.areAllPrimitivesSupported(
+ VibrationEffect.Composition.PRIMITIVE_QUICK_RISE,
+ VibrationEffect.Composition.PRIMITIVE_CLICK)) {
+ return VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE)
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 50)
+ .compose();
+ }
+ if (vibrator.hasAmplitudeControl()) {
+ return VibrationEffect.createWaveform(
+ CAMERA_LAUNCH_GESTURE_VIBRATION_TIMINGS,
+ CAMERA_LAUNCH_GESTURE_VIBRATION_AMPLITUDES,
+ /* repeat= */ -1);
+ }
+
+ int[] pattern = resources.getIntArray(R.array.config_cameraLaunchGestureVibePattern);
+ long[] timings = new long[pattern.length];
+ for (int i = 0; i < pattern.length; i++) {
+ timings[i] = pattern[i];
+ }
+ return VibrationEffect.createWaveform(timings, /* repeat= */ -1);
}
/**
* @return true if the screen is currently fully off, i.e. has finished turning off and has
- * since not started turning on.
+ * since not started turning on.
*/
public boolean isScreenFullyOff() {
return mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_OFF;
@@ -4278,15 +4336,6 @@
updateScrimController();
}
- /**
- * Set the location of the sensor on UDFPS if existent.
- */
- public void setSensorRect(RectF rect) {
- final float startRadius = (rect.right - rect.left) / 2f;
- mCircleReveal = new CircleReveal(rect.centerX(), rect.centerY(),
- startRadius, rect.centerY() - startRadius);
- }
-
@VisibleForTesting
public void updateScrimController() {
Trace.beginSection("StatusBar#updateScrimController");
@@ -4341,6 +4390,7 @@
} else {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
}
+ updateLightRevealScrimVisibility();
Trace.endSection();
}
@@ -4565,7 +4615,7 @@
animationController, this, intent.isActivity()) : null;
mActivityLaunchAnimator.startPendingIntentWithAnimation(
- controller, areLaunchAnimationsEnabled(),
+ controller, areLaunchAnimationsEnabled(), intent.getCreatorPackage(),
(animationAdapter) -> intent.sendAndReturnResult(null, 0, null, null, null,
null, getActivityOptions(mDisplayId, animationAdapter)));
} catch (PendingIntent.CanceledException e) {
@@ -4773,6 +4823,11 @@
return;
}
+ if (mDozeServiceHost.isPulsing()) {
+ mLightRevealScrim.setVisibility(View.GONE);
+ return;
+ }
+
if (mFeatureFlags.useNewLockscreenAnimations()
&& (mDozeParameters.getAlwaysOn() || mDozeParameters.isQuickPickupEnabled())) {
mLightRevealScrim.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
new file mode 100644
index 0000000..edcf261
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone
+
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.Rect
+import android.util.Pair
+import android.view.DisplayCutout
+import android.view.View.LAYOUT_DIRECTION_RTL
+import android.view.WindowManager
+import android.view.WindowMetrics
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.Dumpable
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.policy.CallbackController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.util.leak.RotationUtils
+import com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE
+import com.android.systemui.util.leak.RotationUtils.ROTATION_NONE
+import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE
+import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN
+import com.android.systemui.util.leak.RotationUtils.Rotation
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import java.lang.Math.max
+import javax.inject.Inject
+
+/**
+ * Encapsulates logic that can solve for the left/right insets required for the status bar contents.
+ * Takes into account:
+ * 1. rounded_corner_content_padding
+ * 2. status_bar_padding_start, status_bar_padding_end
+ * 2. display cutout insets from left or right
+ * 3. waterfall insets
+ *
+ *
+ * Importantly, these functions can determine status bar content left/right insets for any rotation
+ * before having done a layout pass in that rotation.
+ *
+ * NOTE: This class is not threadsafe
+ */
+@SysUISingleton
+class StatusBarContentInsetsProvider @Inject constructor(
+ val context: Context,
+ val configurationController: ConfigurationController,
+ val windowManager: WindowManager,
+ val dumpManager: DumpManager
+) : CallbackController<StatusBarContentInsetsChangedListener>,
+ ConfigurationController.ConfigurationListener,
+ Dumpable {
+ // Indexed by @Rotation
+ private val insetsByCorner = arrayOfNulls<Rect>(4)
+ private val listeners = mutableSetOf<StatusBarContentInsetsChangedListener>()
+
+ init {
+ configurationController.addCallback(this)
+ dumpManager.registerDumpable(TAG, this)
+ }
+
+ override fun addCallback(listener: StatusBarContentInsetsChangedListener) {
+ listeners.add(listener)
+ }
+
+ override fun removeCallback(listener: StatusBarContentInsetsChangedListener) {
+ listeners.remove(listener)
+ }
+
+ override fun onDensityOrFontScaleChanged() {
+ clearCachedInsets()
+ }
+
+ override fun onOverlayChanged() {
+ clearCachedInsets()
+ }
+
+ private fun clearCachedInsets() {
+ insetsByCorner[0] = null
+ insetsByCorner[1] = null
+ insetsByCorner[2] = null
+ insetsByCorner[3] = null
+
+ notifyInsetsChanged()
+ }
+
+ private fun notifyInsetsChanged() {
+ listeners.forEach {
+ it.onStatusBarContentInsetsChanged()
+ }
+ }
+
+ /**
+ * Calculates the maximum bounding rectangle for the privacy chip animation + ongoing privacy
+ * dot in the coordinates relative to the given rotation.
+ */
+ fun getBoundingRectForPrivacyChipForRotation(@Rotation rotation: Int): Rect {
+ var insets = insetsByCorner[rotation]
+ val rotatedResources = RotationUtils.getResourcesForRotation(rotation, context)
+ if (insets == null) {
+ insets = getAndSetInsetsForRotation(rotation, rotatedResources)
+ }
+
+ val dotWidth = rotatedResources.getDimensionPixelSize(R.dimen.ongoing_appops_dot_diameter)
+ val chipWidth = rotatedResources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_chip_max_width)
+
+ val isRtl = context.resources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL
+ return getPrivacyChipBoundingRectForInsets(insets, dotWidth, chipWidth, isRtl)
+ }
+
+ /**
+ * Calculates the necessary left and right locations for the status bar contents invariant of
+ * the current device rotation, in the target rotation's coordinates
+ */
+ fun getStatusBarContentInsetsForRotation(@Rotation rotation: Int): Rect {
+ var insets = insetsByCorner[rotation]
+ if (insets == null) {
+ val rotatedResources = RotationUtils.getResourcesForRotation(rotation, context)
+ insets = getAndSetInsetsForRotation(rotation, rotatedResources)
+ }
+
+ return insets
+ }
+
+ private fun getAndSetInsetsForRotation(
+ @Rotation rot: Int,
+ rotatedResources: Resources
+ ): Rect {
+ val insets = getCalculatedInsetsForRotation(rot, rotatedResources)
+ insetsByCorner[rot] = insets
+
+ return insets
+ }
+
+ private fun getCalculatedInsetsForRotation(
+ @Rotation targetRotation: Int,
+ rotatedResources: Resources
+ ): Rect {
+ val dc = context.display.cutout
+ val currentRotation = RotationUtils.getExactRotation(context)
+
+ return calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowManager.maximumWindowMetrics,
+ rotatedResources.getDimensionPixelSize(R.dimen.status_bar_height),
+ rotatedResources.getDimensionPixelSize(R.dimen.rounded_corner_content_padding))
+ }
+
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+ insetsByCorner.forEachIndexed { index, rect ->
+ pw.println("${RotationUtils.toString(index)} -> $rect")
+ }
+ }
+}
+
+interface StatusBarContentInsetsChangedListener {
+ fun onStatusBarContentInsetsChanged()
+}
+
+private const val TAG = "StatusBarInsetsProvider"
+
+private fun getRotationZeroDisplayBounds(wm: WindowMetrics, @Rotation exactRotation: Int): Rect {
+ val bounds = wm.bounds
+
+ if (exactRotation == ROTATION_NONE || exactRotation == ROTATION_UPSIDE_DOWN) {
+ return bounds
+ }
+
+ // bounds are horizontal, swap height and width
+ return Rect(0, 0, bounds.bottom, bounds.right)
+}
+
+@VisibleForTesting
+fun getPrivacyChipBoundingRectForInsets(
+ contentRect: Rect,
+ dotWidth: Int,
+ chipWidth: Int,
+ isRtl: Boolean
+): Rect {
+ return if (isRtl) {
+ Rect(contentRect.left - dotWidth,
+ contentRect.top,
+ contentRect.left + chipWidth,
+ contentRect.bottom)
+ } else {
+ Rect(contentRect.right - chipWidth,
+ contentRect.top,
+ contentRect.right + dotWidth,
+ contentRect.bottom)
+ }
+}
+
+/**
+ * Calculates the exact left and right positions for the status bar contents for the given
+ * rotation
+ *
+ * @param rot rotation for which to query the margins
+ * @param context systemui context
+ * @param rotatedResources resources constructed with the proper orientation set
+ *
+ * @see [RotationUtils#getResourcesForRotation]
+ */
+fun calculateInsetsForRotationWithRotatedResources(
+ @Rotation currentRotation: Int,
+ @Rotation targetRotation: Int,
+ displayCutout: DisplayCutout?,
+ windowMetrics: WindowMetrics,
+ statusBarHeight: Int,
+ roundedCornerPadding: Int
+): Rect {
+ /*
+ TODO: Check if this is ever used for devices with no rounded corners
+ val left = if (isRtl) paddingEnd else paddingStart
+ val right = if (isRtl) paddingStart else paddingEnd
+ */
+
+ val rotZeroBounds = getRotationZeroDisplayBounds(windowMetrics, currentRotation)
+ val currentBounds = windowMetrics.bounds
+
+ val sbLeftRight = getStatusBarLeftRight(
+ displayCutout,
+ statusBarHeight,
+ rotZeroBounds.right,
+ rotZeroBounds.bottom,
+ currentBounds.width(),
+ currentBounds.height(),
+ roundedCornerPadding,
+ targetRotation,
+ currentRotation)
+
+ return sbLeftRight
+}
+
+/**
+ * Calculate the insets needed from the left and right edges for the given rotation.
+ *
+ * @param dc Device display cutout
+ * @param sbHeight appropriate status bar height for this rotation
+ * @param width display width calculated for ROTATION_NONE
+ * @param height display height calculated for ROTATION_NONE
+ * @param roundedCornerPadding rounded_corner_content_padding dimension
+ * @param targetRotation the rotation for which to calculate margins
+ * @param currentRotation the rotation from which the display cutout was generated
+ *
+ * @return a Rect which exactly calculates the Status Bar's content rect relative to the target
+ * rotation
+ */
+private fun getStatusBarLeftRight(
+ dc: DisplayCutout?,
+ sbHeight: Int,
+ width: Int,
+ height: Int,
+ cWidth: Int,
+ cHeight: Int,
+ roundedCornerPadding: Int,
+ @Rotation targetRotation: Int,
+ @Rotation currentRotation: Int
+): Rect {
+
+ val logicalDisplayWidth = if (targetRotation.isHorizontal()) height else width
+
+ val cutoutRects = dc?.boundingRects
+ if (cutoutRects == null || cutoutRects.isEmpty()) {
+ return Rect(roundedCornerPadding,
+ 0,
+ logicalDisplayWidth - roundedCornerPadding,
+ sbHeight)
+ }
+
+ val relativeRotation = if (currentRotation - targetRotation < 0) {
+ currentRotation - targetRotation + 4
+ } else {
+ currentRotation - targetRotation
+ }
+
+ // Size of the status bar window for the given rotation relative to our exact rotation
+ val sbRect = sbRect(relativeRotation, sbHeight, Pair(cWidth, cHeight))
+
+ var leftMargin = roundedCornerPadding
+ var rightMargin = roundedCornerPadding
+ for (cutoutRect in cutoutRects) {
+ // There is at most one non-functional area per short edge of the device. So if the status
+ // bar doesn't share a short edge with the cutout, we can ignore its insets because there
+ // will be no letter-boxing to worry about
+ if (!shareShortEdge(sbRect, cutoutRect, cWidth, cHeight)) {
+ continue
+ }
+
+ if (cutoutRect.touchesLeftEdge(relativeRotation, cWidth, cHeight)) {
+
+ val l = max(roundedCornerPadding, cutoutRect.logicalWidth(relativeRotation))
+ leftMargin = max(l, leftMargin)
+ } else if (cutoutRect.touchesRightEdge(relativeRotation, cWidth, cHeight)) {
+ val logicalWidth = cutoutRect.logicalWidth(relativeRotation)
+ rightMargin = max(roundedCornerPadding, logicalWidth)
+ }
+ }
+
+ return Rect(leftMargin, 0, logicalDisplayWidth - rightMargin, sbHeight)
+}
+
+private fun sbRect(
+ @Rotation relativeRotation: Int,
+ sbHeight: Int,
+ displaySize: Pair<Int, Int>
+): Rect {
+ val w = displaySize.first
+ val h = displaySize.second
+ return when (relativeRotation) {
+ ROTATION_NONE -> Rect(0, 0, w, sbHeight)
+ ROTATION_LANDSCAPE -> Rect(0, 0, sbHeight, h)
+ ROTATION_UPSIDE_DOWN -> Rect(0, h - sbHeight, w, h)
+ else -> Rect(w - sbHeight, 0, w, h)
+ }
+}
+
+private fun shareShortEdge(
+ sbRect: Rect,
+ cutoutRect: Rect,
+ currentWidth: Int,
+ currentHeight: Int
+): Boolean {
+ if (currentWidth < currentHeight) {
+ // Check top/bottom edges by extending the width of the display cutout rect and checking
+ // for intersections
+ return sbRect.intersects(0, cutoutRect.top, currentWidth, cutoutRect.bottom)
+ } else if (currentWidth > currentHeight) {
+ // Short edge is the height, extend that one this time
+ return sbRect.intersects(cutoutRect.left, 0, cutoutRect.right, currentHeight)
+ }
+
+ return false
+}
+
+private fun Rect.touchesRightEdge(@Rotation rot: Int, width: Int, height: Int): Boolean {
+ return when (rot) {
+ ROTATION_NONE -> right >= width
+ ROTATION_LANDSCAPE -> top <= 0
+ ROTATION_UPSIDE_DOWN -> left <= 0
+ else /* SEASCAPE */ -> bottom >= height
+ }
+}
+
+private fun Rect.touchesLeftEdge(@Rotation rot: Int, width: Int, height: Int): Boolean {
+ return when (rot) {
+ ROTATION_NONE -> left <= 0
+ ROTATION_LANDSCAPE -> bottom >= height
+ ROTATION_UPSIDE_DOWN -> right >= width
+ else /* SEASCAPE */ -> top <= 0
+ }
+}
+
+private fun Rect.logicalTop(@Rotation rot: Int): Int {
+ return when (rot) {
+ ROTATION_NONE -> top
+ ROTATION_LANDSCAPE -> left
+ ROTATION_UPSIDE_DOWN -> bottom
+ else /* SEASCAPE */ -> right
+ }
+}
+
+private fun Rect.logicalRight(@Rotation rot: Int): Int {
+ return when (rot) {
+ ROTATION_NONE -> right
+ ROTATION_LANDSCAPE -> top
+ ROTATION_UPSIDE_DOWN -> left
+ else /* SEASCAPE */ -> bottom
+ }
+}
+
+private fun Rect.logicalLeft(@Rotation rot: Int): Int {
+ return when (rot) {
+ ROTATION_NONE -> left
+ ROTATION_LANDSCAPE -> bottom
+ ROTATION_UPSIDE_DOWN -> right
+ else /* SEASCAPE */ -> top
+ }
+}
+
+private fun Rect.logicalWidth(@Rotation rot: Int): Int {
+ return when (rot) {
+ ROTATION_NONE, ROTATION_UPSIDE_DOWN -> width()
+ else /* LANDSCAPE, SEASCAPE */ -> height()
+ }
+}
+
+private fun Int.isHorizontal(): Boolean {
+ return this == ROTATION_LANDSCAPE || this == ROTATION_SEASCAPE
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index ab58aae6..5cd4e13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -437,7 +437,7 @@
mActivityLaunchAnimator.startPendingIntentWithAnimation(animationController,
!wasOccluded && mStatusBar.areLaunchAnimationsEnabled(),
- (adapter) -> {
+ intent.getCreatorPackage(), (adapter) -> {
long eventTime = row.getAndResetLastActionUpTime();
Bundle options = eventTime > 0
? getActivityOptions(
@@ -469,6 +469,7 @@
mActivityLaunchAnimator.startIntentWithAnimation(
animationController, mStatusBar.areLaunchAnimationsEnabled(),
+ intent.getPackage(),
(adapter) -> TaskStackBuilder.create(mContext)
.addNextIntentWithParentStack(intent)
.startActivities(getActivityOptions(
@@ -499,7 +500,7 @@
true /* isActivityIntent */);
mActivityLaunchAnimator.startIntentWithAnimation(animationController,
- mStatusBar.areLaunchAnimationsEnabled(),
+ mStatusBar.areLaunchAnimationsEnabled(), intent.getPackage(),
(adapter) -> tsb.startActivities(
getActivityOptions(mStatusBar.getDisplayId(), adapter),
UserHandle.CURRENT));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index ebf2465..d3953df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -23,7 +23,6 @@
import android.util.Log;
import com.android.settingslib.mobile.TelephonyIcons;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.policy.NetworkController;
@@ -63,6 +62,7 @@
private final SecurityController mSecurityController;
private final Handler mHandler = Handler.getMain();
private final CarrierConfigTracker mCarrierConfigTracker;
+ private final TunerService mTunerService;
private boolean mHideAirplane;
private boolean mHideMobile;
@@ -83,9 +83,16 @@
@Inject
public StatusBarSignalPolicy(Context context, StatusBarIconController iconController,
- CarrierConfigTracker carrierConfigTracker) {
+ CarrierConfigTracker carrierConfigTracker, NetworkController networkController,
+ SecurityController securityController, TunerService tunerService) {
mContext = context;
+ mIconController = iconController;
+ mCarrierConfigTracker = carrierConfigTracker;
+ mNetworkController = networkController;
+ mSecurityController = securityController;
+ mTunerService = tunerService;
+
mSlotAirplane = mContext.getString(com.android.internal.R.string.status_bar_airplane);
mSlotMobile = mContext.getString(com.android.internal.R.string.status_bar_mobile);
mSlotWifi = mContext.getString(com.android.internal.R.string.status_bar_wifi);
@@ -96,18 +103,14 @@
mContext.getString(com.android.internal.R.string.status_bar_call_strength);
mActivityEnabled = mContext.getResources().getBoolean(R.bool.config_showActivity);
- mIconController = iconController;
- mCarrierConfigTracker = carrierConfigTracker;
- mNetworkController = Dependency.get(NetworkController.class);
- mSecurityController = Dependency.get(SecurityController.class);
- Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
+ tunerService.addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
mNetworkController.addCallback(this);
mSecurityController.addCallback(this);
}
public void destroy() {
- Dependency.get(TunerService.class).removeTunable(this);
+ mTunerService.removeTunable(this);
mNetworkController.removeCallback(this);
mSecurityController.removeCallback(this);
}
@@ -172,7 +175,7 @@
&& !mIsAirplaneMode) {
newState.visible = true;
newState.resId = R.drawable.ic_qs_no_internet_unavailable;
- } else if (mWifiIconState.noValidatedNetwork && !mWifiIconState.noNetworksAvailable
+ } else if (mWifiIconState.noDefaultNetwork && !mWifiIconState.noNetworksAvailable
&& (!mIsAirplaneMode || (mIsAirplaneMode && mIsWifiEnabled))) {
newState.visible = true;
newState.resId = R.drawable.ic_qs_no_internet_available;
@@ -377,7 +380,7 @@
if (noDefaultNetwork && noNetworksAvailable && !mIsAirplaneMode) {
newState.visible = true;
newState.resId = R.drawable.ic_qs_no_internet_unavailable;
- } else if (noValidatedNetwork && !noNetworksAvailable
+ } else if (noDefaultNetwork && !noNetworksAvailable
&& (!mIsAirplaneMode || (mIsAirplaneMode && mIsWifiEnabled))) {
newState.visible = true;
newState.resId = R.drawable.ic_qs_no_internet_available;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index 30b8c5c..9a25a70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -20,12 +20,20 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
+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 static com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN;
+
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
import android.os.Binder;
+import android.os.RemoteException;
import android.util.Log;
import android.view.Gravity;
+import android.view.IWindowManager;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -46,7 +54,9 @@
private final Context mContext;
private final WindowManager mWindowManager;
+ private final IWindowManager mIWindowManager;
private final SuperStatusBarViewFactory mSuperStatusBarViewFactory;
+ private final StatusBarContentInsetsProvider mContentInsetsProvider;
private final Resources mResources;
private int mBarHeight = -1;
private final State mCurrentState = new State();
@@ -57,11 +67,17 @@
private final WindowManager.LayoutParams mLpChanged;
@Inject
- public StatusBarWindowController(Context context, WindowManager windowManager,
+ public StatusBarWindowController(
+ Context context,
+ WindowManager windowManager,
+ IWindowManager iWindowManager,
SuperStatusBarViewFactory superStatusBarViewFactory,
+ StatusBarContentInsetsProvider contentInsetsProvider,
@Main Resources resources) {
mContext = context;
mWindowManager = windowManager;
+ mIWindowManager = iWindowManager;
+ mContentInsetsProvider = contentInsetsProvider;
mSuperStatusBarViewFactory = superStatusBarViewFactory;
mStatusBarView = mSuperStatusBarViewFactory.getStatusBarWindowView();
mLaunchAnimationContainer = mStatusBarView.findViewById(
@@ -120,6 +136,27 @@
mWindowManager.addView(mStatusBarView, mLp);
mLpChanged.copyFrom(mLp);
+
+ mContentInsetsProvider.addCallback(this::calculateStatusBarLocationsForAllRotations);
+ calculateStatusBarLocationsForAllRotations();
+ }
+
+ private void calculateStatusBarLocationsForAllRotations() {
+ Rect[] bounds = new Rect[4];
+ bounds[0] = mContentInsetsProvider
+ .getBoundingRectForPrivacyChipForRotation(ROTATION_NONE);
+ bounds[1] = mContentInsetsProvider
+ .getBoundingRectForPrivacyChipForRotation(ROTATION_LANDSCAPE);
+ bounds[2] = mContentInsetsProvider
+ .getBoundingRectForPrivacyChipForRotation(ROTATION_UPSIDE_DOWN);
+ bounds[3] = mContentInsetsProvider
+ .getBoundingRectForPrivacyChipForRotation(ROTATION_SEASCAPE);
+
+ try {
+ mIWindowManager.updateStaticPrivacyIndicatorBounds(mContext.getDisplayId(), bounds);
+ } catch (RemoteException e) {
+ //Swallow
+ }
}
/** Set force status bar visible. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java
new file mode 100644
index 0000000..52e0e8a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainView.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+import com.android.wm.shell.animation.Interpolators;
+
+/**
+ * View to show a toast-like popup on the notification shade and quick settings.
+ */
+public class TapAgainView extends TextView {
+ private TextView mTextView;
+
+ public TapAgainView(
+ @NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ updateColor();
+ }
+
+ void updateColor() {
+ int textColor = getResources().getColor(R.color.notif_pill_text, mContext.getTheme());
+ setTextColor(textColor);
+ setBackground(getResources().getDrawable(R.drawable.rounded_bg_full, mContext.getTheme()));
+ }
+
+ /** Make the view visible. */
+ public void animateIn() {
+ int yTranslation = mContext.getResources().getDimensionPixelSize(
+ R.dimen.keyguard_indication_y_translation);
+
+ AnimatorSet animatorSet = new AnimatorSet();
+ ObjectAnimator fadeIn = ObjectAnimator.ofFloat(this, View.ALPHA, 1f);
+ fadeIn.setStartDelay(150); // From KeyguardIndicationTextView#getFadeInDelay
+ fadeIn.setDuration(317); // From KeyguardIndicationTextView#getFadeInDuration
+ fadeIn.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+
+ Animator yTranslate =
+ ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, yTranslation, 0);
+ yTranslate.setDuration(600); // From KeyguardIndicationTextView#getYInDuration
+ yTranslate.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ setTranslationY(0);
+ }
+ });
+ animatorSet.playTogether(yTranslate, fadeIn);
+ animatorSet.start();
+ setVisibility(View.VISIBLE);
+ }
+
+ /** Make the view gone. */
+ public void animateOut() {
+ long fadeOutDuration = 167L; // From KeyguardIndicationTextView#getFadeOutDuration
+ int yTranslation = mContext.getResources().getDimensionPixelSize(
+ com.android.systemui.R.dimen.keyguard_indication_y_translation);
+
+ AnimatorSet animatorSet = new AnimatorSet();
+ ObjectAnimator fadeOut = ObjectAnimator.ofFloat(this, View.ALPHA, 0f);
+ fadeOut.setDuration(fadeOutDuration);
+ fadeOut.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+
+ Animator yTranslate =
+ ObjectAnimator.ofFloat(this, View.TRANSLATION_Y, 0, -yTranslation);
+ yTranslate.setDuration(fadeOutDuration);
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ setVisibility(GONE);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ setVisibility(GONE);
+ }
+ });
+ animatorSet.playTogether(yTranslate, fadeOut);
+ animatorSet.start();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainViewController.java
new file mode 100644
index 0000000..0c5502b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TapAgainViewController.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static com.android.systemui.classifier.FalsingModule.DOUBLE_TAP_TIMEOUT_MS;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.util.ViewController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * Controller for {@link TapAgainView}.
+ */
+@StatusBarComponent.StatusBarScope
+public class TapAgainViewController extends ViewController<TapAgainView> {
+ private final DelayableExecutor mDelayableExecutor;
+ private final ConfigurationController mConfigurationController;
+ private final long mDoubleTapTimeMs;
+
+ private Runnable mHideCanceler;
+
+ @VisibleForTesting
+ final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
+ @Override
+ public void onOverlayChanged() {
+ mView.updateColor();
+ }
+
+ @Override
+ public void onUiModeChanged() {
+ mView.updateColor();
+ }
+
+ @Override
+ public void onThemeChanged() {
+ mView.updateColor();
+ }
+ };
+
+ @Inject
+ protected TapAgainViewController(TapAgainView view,
+ @Main DelayableExecutor delayableExecutor,
+ ConfigurationController configurationController,
+ @Named(DOUBLE_TAP_TIMEOUT_MS) long doubleTapTimeMs) {
+ super(view);
+ mDelayableExecutor = delayableExecutor;
+ mConfigurationController = configurationController;
+ mDoubleTapTimeMs = doubleTapTimeMs;
+ }
+
+ @Override
+ protected void onViewAttached() {
+ mConfigurationController.addCallback(mConfigurationListener);
+ }
+
+ @Override
+ protected void onViewDetached() {
+ mConfigurationController.removeCallback(mConfigurationListener);
+ }
+
+ /** Shows the associated view, possibly animating it. */
+ public void show() {
+ if (mHideCanceler != null) {
+ mHideCanceler.run();
+ }
+ mView.animateIn();
+ mHideCanceler = mDelayableExecutor.executeDelayed(this::hide, mDoubleTapTimeMs);
+ }
+
+ /** Hides the associated view, possibly animating it. */
+ public void hide() {
+ mHideCanceler = null;
+ mView.animateOut();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index 008c0ae..27d71ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -23,6 +23,7 @@
import com.android.systemui.biometrics.AuthRippleView;
import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
+import com.android.systemui.statusbar.phone.TapAgainView;
import dagger.Module;
import dagger.Provides;
@@ -53,4 +54,11 @@
NotificationShadeWindowView notificationShadeWindowView) {
return notificationShadeWindowView.findViewById(R.id.auth_ripple);
}
+
+ /** */
+ @Provides
+ @StatusBarComponent.StatusBarScope
+ public static TapAgainView getTapAgainView(NotificationPanelView npv) {
+ return npv.getTapAgainView();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 9bf13b8..7dccf01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -150,9 +150,11 @@
val currentChipView = chipView
val timeView =
- currentChipView?.findViewById<Chronometer>(R.id.ongoing_call_chip_time)
+ currentChipView?.findViewById<Chronometer>(R.id.ongoing_call_chip_time)
+ val backgroundView =
+ currentChipView?.findViewById<View>(R.id.ongoing_call_chip_background)
- if (currentChipView != null && timeView != null) {
+ if (currentChipView != null && timeView != null && backgroundView != null) {
timeView.base = currentOngoingCallInfo.callStartTime -
System.currentTimeMillis() +
systemClock.elapsedRealtime()
@@ -162,7 +164,7 @@
logger.logChipClicked()
activityStarter.postStartActivityDismissingKeyguard(
currentOngoingCallInfo.intent, 0,
- ActivityLaunchAnimator.Controller.fromView(it))
+ ActivityLaunchAnimator.Controller.fromView(backgroundView))
}
setUpUidObserver(currentOngoingCallInfo)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
index e7201f8..af7bf95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
@@ -50,6 +50,13 @@
boolean canDismissLockScreen();
/**
+ * Whether we can currently perform the shared element SmartSpace transition. This is true if
+ * we're on the lockscreen, it can be dismissed with a swipe, and the Launcher is underneath the
+ * keyguard and displaying a SmartSpace that it has registered with System UI.
+ */
+ boolean canPerformSmartSpaceTransition();
+
+ /**
* If the device has PIN/pattern/password or a lock screen at all.
*/
boolean isMethodSecure();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index e69c1f2..0945a3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -32,6 +32,7 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -53,6 +54,7 @@
private final LockPatternUtils mLockPatternUtils;
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
new UpdateMonitorCallback();
+ private final SmartspaceTransitionController mSmartspaceTransitionController;
private boolean mCanDismissLockScreen;
private boolean mShowing;
@@ -96,10 +98,12 @@
*/
@Inject
public KeyguardStateControllerImpl(Context context,
- KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils) {
+ KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils,
+ SmartspaceTransitionController smartspaceTransitionController) {
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLockPatternUtils = lockPatternUtils;
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
+ mSmartspaceTransitionController = smartspaceTransitionController;
update(true /* updateAlways */);
if (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB) {
@@ -158,6 +162,11 @@
mShowing = showing;
mOccluded = occluded;
notifyKeyguardChanged();
+
+ // Update the dismiss amount to the full 0f/1f if we explicitly show or hide the keyguard.
+ // Otherwise, the dismiss amount could be left at a random value if we show/hide during a
+ // dismiss gesture, canceling the gesture.
+ notifyKeyguardDismissAmountChanged(showing ? 0f : 1f, false);
}
private void notifyKeyguardChanged() {
@@ -228,6 +237,12 @@
}
@Override
+ public boolean canPerformSmartSpaceTransition() {
+ return canDismissLockScreen()
+ && mSmartspaceTransitionController.isSmartspaceTransitionPossible();
+ }
+
+ @Override
public boolean isFaceAuthEnabled() {
return mFaceAuthEnabled;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 07e9fed..4ab07af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -1023,6 +1023,11 @@
mValidatedTransports.clear();
if (mLastDefaultNetworkCapabilities != null) {
for (int transportType : mLastDefaultNetworkCapabilities.getTransportTypes()) {
+ if (transportType != NetworkCapabilities.TRANSPORT_CELLULAR
+ && transportType != NetworkCapabilities.TRANSPORT_WIFI
+ && transportType != NetworkCapabilities.TRANSPORT_ETHERNET) {
+ continue;
+ }
if (transportType == NetworkCapabilities.TRANSPORT_CELLULAR
&& Utils.tryGetWifiInfoForVcn(mLastDefaultNetworkCapabilities) != null) {
mConnectedTransports.set(NetworkCapabilities.TRANSPORT_WIFI);
@@ -1045,11 +1050,15 @@
Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports);
}
- mInetCondition = !mValidatedTransports.isEmpty();
+ mInetCondition = mValidatedTransports.get(NetworkCapabilities.TRANSPORT_CELLULAR)
+ || mValidatedTransports.get(NetworkCapabilities.TRANSPORT_WIFI)
+ || mValidatedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
pushConnectivityToSignals();
if (mProviderModel) {
- mNoDefaultNetwork = mConnectedTransports.isEmpty();
+ mNoDefaultNetwork = !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_CELLULAR)
+ && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_WIFI)
+ && !mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET);
mCallbackHandler.setConnectivityStatus(mNoDefaultNetwork, !mInetCondition,
mNoNetworksAvailable);
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 4b4a428..4be4b11 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -103,11 +103,11 @@
private final boolean mIsMonetEnabled;
private UserTracker mUserTracker;
private DeviceProvisionedController mDeviceProvisionedController;
- private WallpaperColors mSystemColors;
+ private WallpaperColors mCurrentColors;
private WallpaperManager mWallpaperManager;
// If fabricated overlays were already created for the current theme.
private boolean mNeedsOverlayCreation;
- // Dominant olor extracted from wallpaper, NOT the color used on the overlay
+ // Dominant color extracted from wallpaper, NOT the color used on the overlay
protected int mMainWallpaperColor = Color.TRANSPARENT;
// Accent color extracted from wallpaper, NOT the color used on the overlay
protected int mWallpaperAccentColor = Color.TRANSPARENT;
@@ -162,10 +162,17 @@
handleWallpaperColors(wallpaperColors, which);
};
+ private int getLatestWallpaperType() {
+ return mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK)
+ > mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_SYSTEM)
+ ? WallpaperManager.FLAG_LOCK : WallpaperManager.FLAG_SYSTEM;
+ }
+
private void handleWallpaperColors(WallpaperColors wallpaperColors, int flags) {
- final boolean hadWallpaperColors = mSystemColors != null;
- if ((flags & WallpaperManager.FLAG_SYSTEM) != 0) {
- mSystemColors = wallpaperColors;
+ final boolean hadWallpaperColors = mCurrentColors != null;
+ int latestWallpaperType = getLatestWallpaperType();
+ if ((flags & latestWallpaperType) != 0) {
+ mCurrentColors = wallpaperColors;
if (DEBUG) Log.d(TAG, "got new colors: " + wallpaperColors + " where: " + flags);
}
@@ -183,7 +190,7 @@
} else {
if (DEBUG) {
Log.i(TAG, "During user setup, but allowing first color event: had? "
- + hadWallpaperColors + " has? " + (mSystemColors != null));
+ + hadWallpaperColors + " has? " + (mCurrentColors != null));
}
}
}
@@ -198,7 +205,8 @@
if (!TextUtils.isEmpty(overlayPackageJson)) {
try {
JSONObject jsonObject = new JSONObject(overlayPackageJson);
- if (!COLOR_SOURCE_PRESET.equals(jsonObject.optString(OVERLAY_COLOR_SOURCE))) {
+ if (!COLOR_SOURCE_PRESET.equals(jsonObject.optString(OVERLAY_COLOR_SOURCE))
+ && ((flags & latestWallpaperType) != 0)) {
mSkipSettingChange = true;
if (jsonObject.has(OVERLAY_CATEGORY_ACCENT_COLOR) || jsonObject.has(
OVERLAY_CATEGORY_SYSTEM_PALETTE)) {
@@ -314,10 +322,10 @@
// Upon boot, make sure we have the most up to date colors
Runnable updateColors = () -> {
WallpaperColors systemColor = mWallpaperManager.getWallpaperColors(
- WallpaperManager.FLAG_SYSTEM);
+ getLatestWallpaperType());
mMainExecutor.execute(() -> {
if (DEBUG) Log.d(TAG, "Boot colors: " + systemColor);
- mSystemColors = systemColor;
+ mCurrentColors = systemColor;
reevaluateSystemTheme(false /* forceReload */);
});
};
@@ -348,7 +356,7 @@
}
private void reevaluateSystemTheme(boolean forceReload) {
- final WallpaperColors currentColors = mSystemColors;
+ final WallpaperColors currentColors = mCurrentColors;
final int mainColor;
final int accentCandidate;
if (currentColors == null) {
@@ -506,7 +514,7 @@
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
- pw.println("mSystemColors=" + mSystemColors);
+ pw.println("mSystemColors=" + mCurrentColors);
pw.println("mMainWallpaperColor=" + Integer.toHexString(mMainWallpaperColor));
pw.println("mWallpaperAccentColor=" + Integer.toHexString(mWallpaperAccentColor));
pw.println("mSecondaryOverlay=" + mSecondaryOverlay);
diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
index 4284148..c5e35a4 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
@@ -22,16 +22,19 @@
import android.app.Application;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.UserHandle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
-import android.widget.ToastPresenter;
import com.android.internal.R;
import com.android.launcher3.icons.IconFactory;
@@ -52,7 +55,6 @@
private final String mPackageName;
private final int mUserId;
private final LayoutInflater mLayoutInflater;
- private final boolean mToastStyleEnabled;
final int mDefaultX = 0;
final int mDefaultHorizontalMargin = 0;
@@ -66,15 +68,14 @@
@Nullable private final Animator mOutAnimator;
SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text,
- String packageName, int userId, boolean toastStyleEnabled, int orientation) {
+ String packageName, int userId, int orientation) {
this(layoutInflater, context, text, null, packageName, userId,
- toastStyleEnabled, orientation);
+ orientation);
}
SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text,
ToastPlugin.Toast pluginToast, String packageName, int userId,
- boolean toastStyleEnabled, int orientation) {
- mToastStyleEnabled = toastStyleEnabled;
+ int orientation) {
mLayoutInflater = layoutInflater;
mContext = context;
mText = text;
@@ -167,23 +168,45 @@
return mPluginToast.getView();
}
- View toastView;
- if (mToastStyleEnabled) {
- toastView = mLayoutInflater.inflate(
+ final View toastView = mLayoutInflater.inflate(
com.android.systemui.R.layout.text_toast, null);
- ((TextView) toastView.findViewById(com.android.systemui.R.id.text)).setText(mText);
+ final TextView textView = toastView.findViewById(com.android.systemui.R.id.text);
+ final ImageView iconView = toastView.findViewById(com.android.systemui.R.id.icon);
+ textView.setText(mText);
- Drawable icon = getBadgedIcon(mContext, mPackageName, mUserId);
- if (icon == null) {
- toastView.findViewById(com.android.systemui.R.id.icon).setVisibility(View.GONE);
- } else {
- ((ImageView) toastView.findViewById(com.android.systemui.R.id.icon))
- .setImageDrawable(icon);
- }
- } else {
- toastView = ToastPresenter.getTextToastView(mContext, mText);
+ ApplicationInfo appInfo = null;
+ try {
+ appInfo = mContext.getPackageManager()
+ .getApplicationInfoAsUser(mPackageName, 0, mUserId);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Package name not found package=" + mPackageName
+ + " user=" + mUserId);
}
+ if (appInfo != null && appInfo.targetSdkVersion < Build.VERSION_CODES.S) {
+ // no two-line limit
+ textView.setMaxLines(Integer.MAX_VALUE);
+
+ // no app icon
+ toastView.findViewById(com.android.systemui.R.id.icon).setVisibility(View.GONE);
+ } else {
+ Drawable icon = getBadgedIcon(mContext, mPackageName, mUserId);
+ if (icon == null) {
+ iconView.setVisibility(View.GONE);
+ } else {
+ iconView.setImageDrawable(icon);
+ if (appInfo.labelRes != 0) {
+ try {
+ Resources res = mContext.getPackageManager().getResourcesForApplication(
+ appInfo,
+ new Configuration(mContext.getResources().getConfiguration()));
+ iconView.setContentDescription(res.getString(appInfo.labelRes));
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.d(TAG, "Cannot find application resources for icon label.");
+ }
+ }
+ }
+ }
return toastView;
}
@@ -205,18 +228,14 @@
return mPluginToast.getInAnimation();
}
- return mToastStyleEnabled
- ? ToastDefaultAnimation.Companion.toastIn(getView())
- : null;
+ return ToastDefaultAnimation.Companion.toastIn(getView());
}
private Animator createOutAnimator() {
if (isPluginToast() && mPluginToast.getOutAnimation() != null) {
return mPluginToast.getOutAnimation();
}
- return mToastStyleEnabled
- ? ToastDefaultAnimation.Companion.toastOut(getView())
- : null;
+ return ToastDefaultAnimation.Companion.toastOut(getView());
}
/**
@@ -225,6 +244,10 @@
*/
public static Drawable getBadgedIcon(@NonNull Context context, String packageName,
int userId) {
+ if (!(context.getApplicationContext() instanceof Application)) {
+ return null;
+ }
+
final ApplicationsState appState =
ApplicationsState.getInstance((Application) context.getApplicationContext());
if (!appState.isUserAdded(userId)) {
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt b/packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt
index 603d690..8187956 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt
@@ -76,29 +76,41 @@
}
val linearInterp = LinearInterpolator()
val scaleInterp = PathInterpolator(0.3f, 0f, 1f, 1f)
- val sX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.9f).apply {
+ val viewScaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.9f).apply {
interpolator = scaleInterp
duration = 250
}
- val sY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.9f).apply {
+ val viewScaleY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.9f).apply {
interpolator = scaleInterp
duration = 250
}
- val vA = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f).apply {
+ val viewElevation = ObjectAnimator.ofFloat(view, "elevation",
+ view.elevation, 0f).apply {
+ interpolator = linearInterp
+ duration = 40
+ startDelay = 150
+ }
+ val viewAlpha = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f).apply {
interpolator = linearInterp
duration = 100
startDelay = 150
}
- val tA = ObjectAnimator.ofFloat(text, "alpha", 1f, 0f).apply {
+ val textAlpha = ObjectAnimator.ofFloat(text, "alpha", 1f, 0f).apply {
interpolator = linearInterp
duration = 166
}
- val iA = ObjectAnimator.ofFloat(icon, "alpha", 1f, 0f).apply {
+ val iconAlpha = ObjectAnimator.ofFloat(icon, "alpha", 1f, 0f).apply {
interpolator = linearInterp
duration = 166
}
return AnimatorSet().apply {
- playTogether(sX, sY, vA, tA, iA)
+ playTogether(
+ viewScaleX,
+ viewScaleY,
+ viewElevation,
+ viewAlpha,
+ textAlpha,
+ iconAlpha)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java b/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
index 8b782d4..148bffa 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
@@ -27,7 +27,6 @@
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.ToastPlugin;
import com.android.systemui.shared.plugins.PluginManager;
-import com.android.systemui.statusbar.FeatureFlags;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -43,17 +42,14 @@
// only one ToastPlugin can be connected at a time.
private ToastPlugin mPlugin;
private final LayoutInflater mLayoutInflater;
- private final boolean mToastStyleEnabled;
@Inject
public ToastFactory(
LayoutInflater layoutInflater,
PluginManager pluginManager,
- DumpManager dumpManager,
- FeatureFlags featureFlags) {
+ DumpManager dumpManager) {
mLayoutInflater = layoutInflater;
dumpManager.registerDumpable("ToastFactory", this);
- mToastStyleEnabled = featureFlags.isToastStyleEnabled();
pluginManager.addPluginListener(
new PluginListener<ToastPlugin>() {
@Override
@@ -77,10 +73,10 @@
int userId, int orientation) {
if (isPluginAvailable()) {
return new SystemUIToast(mLayoutInflater, context, text, mPlugin.createToast(text,
- packageName, userId), packageName, userId, mToastStyleEnabled, orientation);
+ packageName, userId), packageName, userId, orientation);
}
return new SystemUIToast(mLayoutInflater, context, text, packageName, userId,
- mToastStyleEnabled, orientation);
+ orientation);
}
private boolean isPluginAvailable() {
@@ -91,6 +87,5 @@
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("ToastFactory:");
pw.println(" mAttachedPlugin=" + mPlugin);
- pw.println(" mToastStyleEnabled=" + mToastStyleEnabled);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
index 92ea1d0..42f6687 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
@@ -19,6 +19,7 @@
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -34,7 +35,8 @@
import android.view.accessibility.IAccessibilityManager;
import android.widget.ToastPresenter;
-import com.android.internal.annotations.VisibleForTesting;
+import androidx.annotation.VisibleForTesting;
+
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.CommandQueue;
@@ -60,11 +62,11 @@
private final AccessibilityManager mAccessibilityManager;
private final ToastFactory mToastFactory;
private final ToastLogger mToastLogger;
- private SystemUIToast mToast;
@Nullable private ToastPresenter mPresenter;
@Nullable private ITransientNotificationCallback mCallback;
private ToastOutAnimatorListener mToastOutAnimatorListener;
+ @VisibleForTesting SystemUIToast mToast;
private int mOrientation = ORIENTATION_PORTRAIT;
@Inject
@@ -191,7 +193,7 @@
/**
* Once the out animation for a toast is finished, start showing the next toast.
*/
- class ToastOutAnimatorListener implements Animator.AnimatorListener {
+ class ToastOutAnimatorListener extends AnimatorListenerAdapter {
final ToastPresenter mPrevPresenter;
final ITransientNotificationCallback mPrevCallback;
@Nullable Runnable mShowNextToastRunnable;
@@ -210,10 +212,6 @@
}
@Override
- public void onAnimationStart(Animator animation) {
- }
-
- @Override
public void onAnimationEnd(Animator animation) {
mPrevPresenter.hide(mPrevCallback);
if (mShowNextToastRunnable != null) {
@@ -221,15 +219,5 @@
}
mToastOutAnimatorListener = null;
}
-
- @Override
- public void onAnimationCancel(Animator animation) {
- onAnimationEnd(animation);
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
-
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactory.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactory.java
index 7a5ceb5..fbec9e7 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactory.java
@@ -30,12 +30,20 @@
*/
public interface ThreadFactory {
/**
+ * Returns a {@link Looper} running on a named thread.
+ *
+ * The thread is implicitly started and may be left running indefinitely, depending on the
+ * implementation. Assume this is the case and use responsibly.
+ */
+ Looper buildLooperOnNewThread(String threadName);
+
+ /**
* Returns a {@link Handler} running on a named thread.
*
* The thread is implicitly started and may be left running indefinitely, depending on the
* implementation. Assume this is the case and use responsibly.
*/
- Handler builderHandlerOnNewThread(String threadName);
+ Handler buildHandlerOnNewThread(String threadName);
/**
* Return an {@link java.util.concurrent.Executor} running on a named thread.
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactoryImpl.java
index 184b831..051f433 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ThreadFactoryImpl.java
@@ -29,10 +29,15 @@
ThreadFactoryImpl() {}
@Override
- public Handler builderHandlerOnNewThread(String threadName) {
+ public Looper buildLooperOnNewThread(String threadName) {
HandlerThread handlerThread = new HandlerThread(threadName);
handlerThread.start();
- return new Handler(handlerThread.getLooper());
+ return handlerThread.getLooper();
+ }
+
+ @Override
+ public Handler buildHandlerOnNewThread(String threadName) {
+ return new Handler(buildLooperOnNewThread(threadName));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java b/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
index e44981e..0b2f004 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
@@ -14,16 +14,40 @@
package com.android.systemui.util.leak;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+
+import android.annotation.IntDef;
import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.view.Surface;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
public class RotationUtils {
public static final int ROTATION_NONE = 0;
public static final int ROTATION_LANDSCAPE = 1;
- public static final int ROTATION_SEASCAPE = 2;
- public static final int ROTATION_UPSIDE_DOWN = 3;
+ public static final int ROTATION_UPSIDE_DOWN = 2;
+ public static final int ROTATION_SEASCAPE = 3;
+ // Not to be confused with Surface.Rotation
+ @IntDef(prefix = { "ROTATION_" }, value = {
+ ROTATION_NONE,
+ ROTATION_LANDSCAPE,
+ ROTATION_SEASCAPE,
+ ROTATION_UPSIDE_DOWN,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Rotation {};
+
+ /**
+ * @return the current rotation, differentiating between none (rot_0), landscape (rot_90), and
+ * seascape (rot_180). upside down is not distinguished here
+ */
+ @Rotation
public static int getRotation(Context context) {
int rot = context.getDisplay().getRotation();
if (rot == Surface.ROTATION_90) {
@@ -35,6 +59,11 @@
}
}
+ /**
+ * @return the current rotation, differentiating between landscape (rot_90), seascape
+ * (rot_270), and upside down (rot_180)
+ */
+ @Rotation
public static int getExactRotation(Context context) {
int rot = context.getDisplay().getRotation();
if (rot == Surface.ROTATION_90) {
@@ -47,4 +76,49 @@
return ROTATION_NONE;
}
}
+
+ /** * To string */
+ public static String toString(@Rotation int rot) {
+ switch (rot) {
+ case ROTATION_NONE:
+ return "None (0)";
+ case ROTATION_LANDSCAPE:
+ return "Landscape (1)";
+ case ROTATION_UPSIDE_DOWN:
+ return "Upside down (2)";
+ case ROTATION_SEASCAPE:
+ return "Seascape (3)";
+ default:
+ return "Unknown (" + rot + ")";
+ }
+ }
+
+ /**
+ * Create a Resources using the specified rotation for the configuration. Use this to retrieve
+ * resources in values or values-land without needing an actual rotation to happen.
+ *
+ * @param rot the target rotation for which to create the resources
+ * @param context a context
+ * @return a Resources object configured for the given orientation
+ */
+ public static Resources getResourcesForRotation(@Rotation int rot, Context context) {
+ int orientation;
+ switch (rot) {
+ case ROTATION_NONE:
+ case ROTATION_UPSIDE_DOWN:
+ orientation = ORIENTATION_PORTRAIT;
+ break;
+ case ROTATION_LANDSCAPE:
+ case ROTATION_SEASCAPE:
+ orientation = ORIENTATION_LANDSCAPE;
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown rotation: " + rot);
+ }
+ Configuration c = new Configuration(context.getResources().getConfiguration());
+ c.orientation = orientation;
+ Context rotated = context.createConfigurationContext(c);
+ return rotated.getResources();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 3aba7ca..a5ccc47 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -38,11 +38,9 @@
import android.media.session.MediaSession.Token;
import android.net.Uri;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.VibrationEffect;
import android.os.Vibrator;
@@ -66,9 +64,9 @@
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.qs.tiles.DndTile;
-import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.RingerModeLiveData;
import com.android.systemui.util.RingerModeTracker;
+import com.android.systemui.util.concurrency.ThreadFactory;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -80,8 +78,6 @@
import javax.inject.Inject;
-import dagger.Lazy;
-
/**
* Source of truth for all state / events related to the volume dialog. No presentation.
*
@@ -118,12 +114,13 @@
STREAMS.put(AudioSystem.STREAM_VOICE_CALL, R.string.stream_voice_call);
}
- private final HandlerThread mWorkerThread;
private final W mWorker;
private final Context mContext;
+ private final Looper mWorkerLooper;
+ private final PackageManager mPackageManager;
+ private final WakefulnessLifecycle mWakefulnessLifecycle;
private AudioManager mAudio;
private IAudioService mAudioService;
- private final Optional<Lazy<StatusBar>> mStatusBarOptionalLazy;
private final NotificationManager mNoMan;
private final SettingObserver mObserver;
private final Receiver mReceiver = new Receiver();
@@ -132,13 +129,13 @@
protected C mCallbacks = new C();
private final State mState = new State();
protected final MediaSessionsCallbacks mMediaSessionsCallbacksW = new MediaSessionsCallbacks();
- private final Vibrator mVibrator;
+ private final Optional<Vibrator> mVibrator;
private final boolean mHasVibrator;
private boolean mShowA11yStream;
private boolean mShowVolumeDialog;
private boolean mShowSafetyWarning;
private long mLastToggledRingerOn;
- private final NotificationManager mNotificationManager;
+ private boolean mDeviceInteractive;
private boolean mDestroyed;
private VolumePolicy mVolumePolicy;
@@ -149,26 +146,42 @@
protected final VC mVolumeController = new VC();
protected final BroadcastDispatcher mBroadcastDispatcher;
- @Inject
- public VolumeDialogControllerImpl(Context context, BroadcastDispatcher broadcastDispatcher,
- Optional<Lazy<StatusBar>> statusBarOptionalLazy, RingerModeTracker ringerModeTracker) {
- mContext = context.getApplicationContext();
- // TODO(b/150663459): remove this TV workaround once StatusBar is "unbound" on TVs
- if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
- mStatusBarOptionalLazy = Optional.empty();
- } else {
- mStatusBarOptionalLazy = statusBarOptionalLazy;
+ private final WakefulnessLifecycle.Observer mWakefullnessLifecycleObserver =
+ new WakefulnessLifecycle.Observer() {
+ @Override
+ public void onStartedWakingUp() {
+ mDeviceInteractive = true;
}
- mNotificationManager = (NotificationManager) mContext.getSystemService(
- Context.NOTIFICATION_SERVICE);
+
+ @Override
+ public void onFinishedGoingToSleep() {
+ mDeviceInteractive = false;
+ }
+ };
+
+ @Inject
+ public VolumeDialogControllerImpl(
+ Context context,
+ BroadcastDispatcher broadcastDispatcher,
+ RingerModeTracker ringerModeTracker,
+ ThreadFactory theadFactory,
+ AudioManager audioManager,
+ NotificationManager notificationManager,
+ Optional<Vibrator> optionalVibrator,
+ IAudioService iAudioService,
+ AccessibilityManager accessibilityManager,
+ PackageManager packageManager,
+ WakefulnessLifecycle wakefulnessLifecycle) {
+ mContext = context.getApplicationContext();
+ mPackageManager = packageManager;
+ mWakefulnessLifecycle = wakefulnessLifecycle;
Events.writeEvent(Events.EVENT_COLLECTION_STARTED);
- mWorkerThread = new HandlerThread(VolumeDialogControllerImpl.class.getSimpleName());
- mWorkerThread.start();
- mWorker = new W(mWorkerThread.getLooper());
- mMediaSessions = createMediaSessions(mContext, mWorkerThread.getLooper(),
- mMediaSessionsCallbacksW);
- mAudio = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- mNoMan = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ mWorkerLooper = theadFactory.buildLooperOnNewThread(
+ VolumeDialogControllerImpl.class.getSimpleName());
+ mWorker = new W(mWorkerLooper);
+ mMediaSessions = createMediaSessions(mContext, mWorkerLooper, mMediaSessionsCallbacksW);
+ mAudio = audioManager;
+ mNoMan = notificationManager;
mObserver = new SettingObserver(mWorker);
mRingerModeObservers = new RingerModeObservers(
(RingerModeLiveData) ringerModeTracker.getRingerMode(),
@@ -178,16 +191,17 @@
mBroadcastDispatcher = broadcastDispatcher;
mObserver.init();
mReceiver.init();
- mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
- mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
- mAudioService = IAudioService.Stub.asInterface(
- ServiceManager.getService(Context.AUDIO_SERVICE));
+ mVibrator = optionalVibrator;
+ mHasVibrator = mVibrator.isPresent() && mVibrator.get().hasVibrator();
+ mAudioService = iAudioService;
- boolean accessibilityVolumeStreamActive = context.getSystemService(
- AccessibilityManager.class).isAccessibilityVolumeStreamActive();
+ boolean accessibilityVolumeStreamActive = accessibilityManager
+ .isAccessibilityVolumeStreamActive();
mVolumeController.setA11yMode(accessibilityVolumeStreamActive ?
VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
+
+ mWakefulnessLifecycle.addObserver(mWakefullnessLifecycleObserver);
}
public AudioManager getAudioManager() {
@@ -203,7 +217,6 @@
mAudio.setVolumeController(mVolumeController);
} catch (SecurityException e) {
Log.w(TAG, "Unable to set the volume controller", e);
- return;
}
}
@@ -249,18 +262,6 @@
return new MediaSessions(context, looper, callbacks);
}
- public void destroy() {
- if (D.BUG) Log.d(TAG, "destroy");
- if (mDestroyed) return;
- mDestroyed = true;
- Events.writeEvent(Events.EVENT_COLLECTION_STOPPED);
- mMediaSessions.destroy();
- mObserver.destroy();
- mReceiver.destroy();
- mRingerModeObservers.destroy();
- mWorkerThread.quitSafely();
- }
-
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(VolumeDialogControllerImpl.class.getSimpleName() + " state:");
pw.print(" mDestroyed: "); pw.println(mDestroyed);
@@ -383,9 +384,8 @@
}
public void vibrate(VibrationEffect effect) {
- if (mHasVibrator) {
- mVibrator.vibrate(effect, SONIFICIATION_VIBRATION_ATTRIBUTES);
- }
+ mVibrator.ifPresent(
+ vibrator -> vibrator.vibrate(effect, SONIFICIATION_VIBRATION_ATTRIBUTES));
}
public boolean hasVibrator() {
@@ -437,9 +437,8 @@
return;
}
- PackageManager packageManager = mContext.getPackageManager();
mCallbacks.onCaptionComponentStateChanged(
- packageManager.getComponentEnabledSetting(componentName)
+ mPackageManager.getComponentEnabledSetting(componentName)
== PackageManager.COMPONENT_ENABLED_STATE_ENABLED, fromTooltip);
} catch (Exception ex) {
Log.e(TAG,
@@ -466,17 +465,11 @@
}
private boolean shouldShowUI(int flags) {
- // if status bar isn't null, check if phone is in AOD, else check flags
- // since we could be using a different status bar
- return mStatusBarOptionalLazy.map(statusBarLazy -> {
- StatusBar statusBar = statusBarLazy.get();
- return statusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
- && statusBar.getWakefulnessState()
- != WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
- && statusBar.isDeviceInteractive() && (flags & AudioManager.FLAG_SHOW_UI) != 0
- && mShowVolumeDialog;
- }).orElse(
- mShowVolumeDialog && (flags & AudioManager.FLAG_SHOW_UI) != 0);
+ int wakefulness = mWakefulnessLifecycle.getWakefulness();
+ return wakefulness != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
+ && wakefulness != WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
+ && mDeviceInteractive && (flags & AudioManager.FLAG_SHOW_UI) != 0
+ && mShowVolumeDialog;
}
boolean onVolumeChangedW(int stream, int flags) {
@@ -600,15 +593,15 @@
private boolean updateEffectsSuppressorW(ComponentName effectsSuppressor) {
if (Objects.equals(mState.effectsSuppressor, effectsSuppressor)) return false;
mState.effectsSuppressor = effectsSuppressor;
- mState.effectsSuppressorName = getApplicationName(mContext, mState.effectsSuppressor);
+ mState.effectsSuppressorName =
+ getApplicationName(mPackageManager, mState.effectsSuppressor);
Events.writeEvent(Events.EVENT_SUPPRESSOR_CHANGED, mState.effectsSuppressor,
mState.effectsSuppressorName);
return true;
}
- private static String getApplicationName(Context context, ComponentName component) {
+ private static String getApplicationName(PackageManager pm, ComponentName component) {
if (component == null) return null;
- final PackageManager pm = context.getPackageManager();
final String pkg = component.getPackageName();
try {
final ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
@@ -630,8 +623,7 @@
}
private boolean updateZenConfig() {
- final NotificationManager.Policy policy =
- mNotificationManager.getConsolidatedNotificationPolicy();
+ final NotificationManager.Policy policy = mNoMan.getConsolidatedNotificationPolicy();
boolean disallowAlarms = (policy.priorityCategories & NotificationManager.Policy
.PRIORITY_CATEGORY_ALARMS) == 0;
boolean disallowMedia = (policy.priorityCategories & NotificationManager.Policy
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index b9f896e..961822a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -28,6 +28,7 @@
import static android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE;
import static android.view.View.GONE;
import static android.view.View.INVISIBLE;
+import static android.view.View.LAYOUT_DIRECTION_RTL;
import static android.view.View.VISIBLE;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
@@ -52,6 +53,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.graphics.Outline;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
@@ -74,11 +76,13 @@
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.view.ContextThemeWrapper;
+import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.AccessibilityDelegate;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
import android.view.ViewPropertyAnimator;
import android.view.ViewStub;
import android.view.ViewTreeObserver;
@@ -147,7 +151,10 @@
private final int mDialogShowAnimationDurationMs;
private final int mDialogHideAnimationDurationMs;
+ private final int mDialogWidth;
+ private final int mDialogCornerRadius;
private final int mRingerDrawerItemSize;
+ private final int mRingerRowsPadding;
private final boolean mShowVibrate;
private final int mRingerCount;
private final boolean mShowLowMediaVolumeIcon;
@@ -162,11 +169,25 @@
private Window mWindow;
private CustomDialog mDialog;
private ViewGroup mDialogView;
+ private ViewGroup mDialogRowsViewContainer;
private ViewGroup mDialogRowsView;
private ViewGroup mRinger;
- @Nullable private View mRingerAndRowsContainer;
- @Nullable private Drawable mRingerAndRowsContainerBackground;
+ /**
+ * Container for the top part of the dialog, which contains the ringer, the ringer drawer, the
+ * volume rows, and the ellipsis button. This does not include the live caption button.
+ */
+ @Nullable private View mTopContainer;
+
+ /** Container for the ringer icon, and for the (initially hidden) ringer drawer view. */
+ @Nullable private View mRingerAndDrawerContainer;
+
+ /**
+ * Background drawable for the ringer and drawer container. The background's top bound is
+ * initially inset by the height of the (hidden) ringer drawer. When the drawer is animated in,
+ * this top bound is animated to accommodate it.
+ */
+ @Nullable private Drawable mRingerAndDrawerContainerBackground;
private ViewGroup mSelectedRingerContainer;
private ImageView mSelectedRingerIcon;
@@ -196,6 +217,7 @@
private final ValueAnimator mAnimateUpBackgroundToMatchDrawer = ValueAnimator.ofFloat(1f, 0f);
private boolean mIsRingerDrawerOpen = false;
+ private float mRingerDrawerClosedAmount = 1f;
private ImageButton mRingerIcon;
private ViewGroup mODICaptionsView;
@@ -266,8 +288,14 @@
mDialogRowsView.invalidate();
};
}
+ mDialogWidth = mContext.getResources().getDimensionPixelSize(
+ R.dimen.volume_dialog_panel_width);
+ mDialogCornerRadius = mContext.getResources().getDimensionPixelSize(
+ R.dimen.volume_dialog_panel_width_half);
mRingerDrawerItemSize = mContext.getResources().getDimensionPixelSize(
R.dimen.volume_ringer_drawer_item_size);
+ mRingerRowsPadding = mContext.getResources().getDimensionPixelSize(
+ R.dimen.volume_dialog_ringer_rows_padding);
mShowVibrate = mController.hasVibrator();
// Normal, mute, and possibly vibrate.
@@ -309,37 +337,44 @@
mTouchableRegion.setEmpty();
- // Set the touchable region to the union of all child view bounds. We don't use touches on
- // the volume dialog container itself, so this is fine.
+ // Set the touchable region to the union of all child view bounds and the live caption
+ // tooltip. We don't use touches on the volume dialog container itself, so this is fine.
for (int i = 0; i < mDialogView.getChildCount(); i++) {
- final View view = mDialogView.getChildAt(i);
- final int[] locInWindow = new int[2];
- view.getLocationInWindow(locInWindow);
+ unionViewBoundstoTouchableRegion(mDialogView.getChildAt(i));
+ }
- float x = locInWindow[0];
- float y = locInWindow[1];
-
- // The ringer and rows container has extra height at the top to fit the expanded ringer
- // drawer. This area should not be touchable unless the ringer drawer is open.
- if (view == mRingerAndRowsContainer && !mIsRingerDrawerOpen) {
- if (!isLandscape()) {
- y += getRingerDrawerOpenExtraSize();
- } else {
- x += getRingerDrawerOpenExtraSize();
- }
- }
-
- mTouchableRegion.op(
- (int) x,
- (int) y,
- locInWindow[0] + view.getWidth(),
- locInWindow[1] + view.getHeight(),
- Region.Op.UNION);
+ if (mODICaptionsTooltipView != null && mODICaptionsTooltipView.getVisibility() == VISIBLE) {
+ unionViewBoundstoTouchableRegion(mODICaptionsTooltipView);
}
internalInsetsInfo.touchableRegion.set(mTouchableRegion);
}
+ private void unionViewBoundstoTouchableRegion(final View view) {
+ final int[] locInWindow = new int[2];
+ view.getLocationInWindow(locInWindow);
+
+ float x = locInWindow[0];
+ float y = locInWindow[1];
+
+ // The ringer and rows container has extra height at the top to fit the expanded ringer
+ // drawer. This area should not be touchable unless the ringer drawer is open.
+ if (view == mTopContainer && !mIsRingerDrawerOpen) {
+ if (!isLandscape()) {
+ y += getRingerDrawerOpenExtraSize();
+ } else {
+ x += getRingerDrawerOpenExtraSize();
+ }
+ }
+
+ mTouchableRegion.op(
+ (int) x,
+ (int) y,
+ locInWindow[0] + view.getWidth(),
+ locInWindow[1] + view.getHeight(),
+ Region.Op.UNION);
+ }
+
private void initDialog() {
mDialog = new CustomDialog(mContext);
@@ -431,6 +466,46 @@
});
}
+ mDialogRowsViewContainer = mDialogView.findViewById(R.id.volume_dialog_rows_container);
+ mTopContainer = mDialogView.findViewById(R.id.volume_dialog_top_container);
+ mRingerAndDrawerContainer = mDialogView.findViewById(
+ R.id.volume_ringer_and_drawer_container);
+
+ if (mRingerAndDrawerContainer != null) {
+ if (isLandscape()) {
+ // In landscape, we need to add padding to the bottom of the ringer drawer so that
+ // when it expands to the left, it doesn't overlap any additional volume rows.
+ mRingerAndDrawerContainer.setPadding(
+ mRingerAndDrawerContainer.getPaddingLeft(),
+ mRingerAndDrawerContainer.getPaddingTop(),
+ mRingerAndDrawerContainer.getPaddingRight(),
+ mRingerRowsPadding);
+
+ // Since the ringer drawer is expanding to the left, outside of the background of
+ // the dialog, it needs its own rounded background drawable. We also need that
+ // background to be rounded on all sides. We'll use a background rounded on all four
+ // corners, and then extend the container's background later to fill in the bottom
+ // corners when the drawer is closed.
+ mRingerAndDrawerContainer.setBackgroundDrawable(
+ mContext.getDrawable(R.drawable.volume_background_top_rounded));
+ }
+
+ // Post to wait for layout so that the background bounds are set.
+ mRingerAndDrawerContainer.post(() -> {
+ final LayerDrawable ringerAndDrawerBg =
+ (LayerDrawable) mRingerAndDrawerContainer.getBackground();
+
+ // Retrieve the ShapeDrawable from within the background - this is what we will
+ // animate up and down when the drawer is opened/closed.
+ if (ringerAndDrawerBg != null && ringerAndDrawerBg.getNumberOfLayers() > 0) {
+ mRingerAndDrawerContainerBackground = ringerAndDrawerBg.getDrawable(0);
+
+ updateBackgroundForDrawerClosedAmount();
+ setTopContainerBackgroundDrawable();
+ }
+ });
+ }
+
mRinger = mDialog.findViewById(R.id.ringer);
if (mRinger != null) {
mRingerIcon = mRinger.findViewById(R.id.ringer_icon);
@@ -510,6 +585,11 @@
Configuration.ORIENTATION_LANDSCAPE;
}
+ private boolean isRtl() {
+ return mContext.getResources().getConfiguration().getLayoutDirection()
+ == LAYOUT_DIRECTION_RTL;
+ }
+
public void setStreamImportant(int stream, boolean important) {
mHandler.obtainMessage(H.SET_STREAM_IMPORTANT, stream, important ? 1 : 0).sendToTarget();
}
@@ -612,23 +692,6 @@
row.anim = null;
- mRingerAndRowsContainer = mDialogView.findViewById(
- R.id.volume_dialog_ringer_and_rows_container);
-
- if (mRingerAndRowsContainer != null) {
- // Wait for layout so the background bounds are set, then set the background top to the
- // ringer drawer closed position.
- mRingerAndRowsContainer.post(() -> {
- final LayerDrawable bgWrapper =
- ((LayerDrawable) mRingerAndRowsContainer.getBackground());
-
- if (bgWrapper != null) {
- mRingerAndRowsContainerBackground = bgWrapper.getDrawable(0);
- setRingerAndRowsBackgroundTop(1f /* closedAmount */);
- }
- });
- }
-
final LayerDrawable seekbarDrawable =
(LayerDrawable) mContext.getDrawable(R.drawable.volume_row_seekbar);
@@ -764,8 +827,10 @@
});
mRingerDrawerIconColorAnimator.setDuration(DRAWER_ANIMATION_DURATION_SHORT);
- mAnimateUpBackgroundToMatchDrawer.addUpdateListener(valueAnimator ->
- setRingerAndRowsBackgroundTop((float) valueAnimator.getAnimatedValue()));
+ mAnimateUpBackgroundToMatchDrawer.addUpdateListener(valueAnimator -> {
+ mRingerDrawerClosedAmount = (float) valueAnimator.getAnimatedValue();
+ updateBackgroundForDrawerClosedAmount();
+ });
}
private ImageView getDrawerIconViewForMode(int mode) {
@@ -792,6 +857,10 @@
/** Animates in the ringer drawer. */
private void showRingerDrawer() {
+ if (mIsRingerDrawerOpen) {
+ return;
+ }
+
// Show all ringer icons except the currently selected one, since we're going to animate the
// ringer button to that position.
mRingerDrawerVibrateIcon.setVisibility(
@@ -874,6 +943,10 @@
return;
}
+ if (!mIsRingerDrawerOpen) {
+ return;
+ }
+
// Hide the drawer icon for the selected ringer - it's visible in the ringer button and we
// don't want to be able to see it while it animates away.
getDrawerIconViewForMode(mState.ringerModeInternal).setVisibility(INVISIBLE);
@@ -992,21 +1065,38 @@
}
if (mODICaptionsTooltipView != null) {
- mODICaptionsTooltipView.setAlpha(0.f);
- mODICaptionsTooltipView.animate()
- .alpha(1.f)
- .setStartDelay(mDialogShowAnimationDurationMs)
- .withEndAction(() -> {
- if (D.BUG) Log.d(TAG, "tool:checkODICaptionsTooltip() putBoolean true");
- Prefs.putBoolean(mContext,
- Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, true);
- mHasSeenODICaptionsTooltip = true;
- if (mODICaptionsIcon != null) {
- mODICaptionsIcon
- .postOnAnimation(getSinglePressFor(mODICaptionsIcon));
- }
- })
- .start();
+ mODICaptionsTooltipView.setAlpha(0.0f);
+
+ // We need to wait for layout and then center the caption view. Since the height of the
+ // dialog is now dynamic (with the variable ringer drawer height changing the height of
+ // the dialog), we need to do this here in code vs. in XML.
+ mHandler.post(() -> {
+ final int[] odiTooltipLocation = mODICaptionsTooltipView.getLocationOnScreen();
+ final int[] odiButtonLocation = mODICaptionsIcon.getLocationOnScreen();
+
+ final float heightDiffForCentering =
+ (mODICaptionsTooltipView.getHeight() - mODICaptionsIcon.getHeight()) / 2f;
+
+ mODICaptionsTooltipView.setTranslationY(
+ odiButtonLocation[1] - odiTooltipLocation[1] - heightDiffForCentering);
+
+ mODICaptionsTooltipView.animate()
+ .alpha(1.0f)
+ .setStartDelay(mDialogShowAnimationDurationMs)
+ .withEndAction(() -> {
+ if (D.BUG) {
+ Log.d(TAG, "tool:checkODICaptionsTooltip() putBoolean true");
+ }
+ Prefs.putBoolean(mContext,
+ Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, true);
+ mHasSeenODICaptionsTooltip = true;
+ if (mODICaptionsIcon != null) {
+ mODICaptionsIcon
+ .postOnAnimation(getSinglePressFor(mODICaptionsIcon));
+ }
+ })
+ .start();
+ });
}
}
@@ -1143,6 +1233,7 @@
mController.notifyVisible(true);
mController.getCaptionsComponentState(false);
checkODICaptionsTooltip(false);
+ updateBackgroundForDrawerClosedAmount();
}
protected void rescheduleTimeoutH() {
@@ -1258,15 +1349,65 @@
if (!mShowing) {
trimObsoleteH();
}
+
+ // Index of the last row that is actually visible.
+ int rightmostVisibleRowIndex = !isRtl() ? -1 : Short.MAX_VALUE;
+
// apply changes to all rows
for (final VolumeRow row : mRows) {
final boolean isActive = row == activeRow;
final boolean shouldBeVisible = shouldBeVisibleH(row, activeRow);
Util.setVisOrGone(row.view, shouldBeVisible);
+
+ if (shouldBeVisible && mRingerAndDrawerContainerBackground != null) {
+ // For RTL, the rightmost row has the lowest index since child views are laid out
+ // from right to left.
+ rightmostVisibleRowIndex =
+ !isRtl()
+ ? Math.max(rightmostVisibleRowIndex,
+ mDialogRowsView.indexOfChild(row.view))
+ : Math.min(rightmostVisibleRowIndex,
+ mDialogRowsView.indexOfChild(row.view));
+
+ // Add spacing between each of the visible rows - we'll remove the spacing from the
+ // last row after the loop.
+ final ViewGroup.LayoutParams layoutParams = row.view.getLayoutParams();
+ if (layoutParams instanceof LinearLayout.LayoutParams) {
+ final LinearLayout.LayoutParams linearLayoutParams =
+ ((LinearLayout.LayoutParams) layoutParams);
+ if (!isRtl()) {
+ linearLayoutParams.setMarginEnd(mRingerRowsPadding);
+ } else {
+ linearLayoutParams.setMarginStart(mRingerRowsPadding);
+ }
+ }
+
+ // Set the background on each of the rows. We'll remove this from the last row after
+ // the loop, since the last row's background is drawn by the main volume container.
+ row.view.setBackgroundDrawable(
+ mContext.getDrawable(R.drawable.volume_row_rounded_background));
+ }
+
if (row.view.isShown()) {
updateVolumeRowTintH(row, isActive);
}
}
+
+ if (rightmostVisibleRowIndex > -1 && rightmostVisibleRowIndex < Short.MAX_VALUE) {
+ final View lastVisibleChild = mDialogRowsView.getChildAt(rightmostVisibleRowIndex);
+ final ViewGroup.LayoutParams layoutParams = lastVisibleChild.getLayoutParams();
+ // Remove the spacing on the last row, and remove its background since the container is
+ // drawing a background for this row.
+ if (layoutParams instanceof LinearLayout.LayoutParams) {
+ final LinearLayout.LayoutParams linearLayoutParams =
+ ((LinearLayout.LayoutParams) layoutParams);
+ linearLayoutParams.setMarginStart(0);
+ linearLayoutParams.setMarginEnd(0);
+ lastVisibleChild.setBackgroundColor(Color.TRANSPARENT);
+ }
+ }
+
+ updateBackgroundForDrawerClosedAmount();
}
protected void updateRingerH() {
@@ -1742,18 +1883,74 @@
return (mRingerCount - 1) * mRingerDrawerItemSize;
}
- /**
- * Sets the top of the background drawable behind the container view for the ringer icon and the
- * volume rows, depending on whether the ringer drawer is open or closed.
- */
- private void setRingerAndRowsBackgroundTop(float drawerClosedAmount) {
- if (mRingerAndRowsContainerBackground == null) {
+ private void updateBackgroundForDrawerClosedAmount() {
+ if (mRingerAndDrawerContainerBackground == null) {
return;
}
- final Rect bounds = mRingerAndRowsContainerBackground.copyBounds();
- bounds.top = (int) (drawerClosedAmount * getRingerDrawerOpenExtraSize());
- mRingerAndRowsContainerBackground.setBounds(bounds);
+ final Rect bounds = mRingerAndDrawerContainerBackground.copyBounds();
+ if (!isLandscape()) {
+ bounds.top = (int) (mRingerDrawerClosedAmount * getRingerDrawerOpenExtraSize());
+ } else {
+ bounds.left = (int) (mRingerDrawerClosedAmount * getRingerDrawerOpenExtraSize());
+ }
+ mRingerAndDrawerContainerBackground.setBounds(bounds);
+ }
+
+ /*
+ * The top container is responsible for drawing the solid color background behind the rightmost
+ * (primary) volume row. This is because the volume drawer animates in from below, initially
+ * overlapping the primary row. We need the drawer to draw below the row's SeekBar, since it
+ * looks strange to overlap it, but above the row's background color, since otherwise it will be
+ * clipped.
+ *
+ * Since we can't be both above and below the volume row view, we'll be below it, and render the
+ * background color in the container since they're both above that.
+ */
+ private void setTopContainerBackgroundDrawable() {
+ if (mTopContainer == null) {
+ return;
+ }
+
+ final ColorDrawable solidDrawable = new ColorDrawable(
+ Utils.getColorAttrDefaultColor(mContext, com.android.internal.R.attr.colorSurface));
+
+ final LayerDrawable background = new LayerDrawable(new Drawable[] { solidDrawable });
+
+ // Size the solid color to match the primary volume row. In landscape, extend it upwards
+ // slightly so that it fills in the bottom corners of the ringer icon, whose background is
+ // rounded on all sides so that it can expand to the left, outside the dialog's background.
+ background.setLayerSize(0, mDialogWidth,
+ !isLandscape()
+ ? mDialogRowsView.getHeight()
+ : mDialogRowsView.getHeight() + mDialogCornerRadius);
+ // Inset the top so that the color only renders below the ringer drawer, which has its own
+ // background. In landscape, reduce the inset slightly since we are using the background to
+ // fill in the corners of the closed ringer drawer.
+ background.setLayerInsetTop(0,
+ !isLandscape()
+ ? mDialogRowsViewContainer.getTop()
+ : mDialogRowsViewContainer.getTop() - mDialogCornerRadius);
+
+ // Set gravity to top-right, since additional rows will be added on the left.
+ background.setLayerGravity(0, Gravity.TOP | Gravity.RIGHT);
+
+ // In landscape, the ringer drawer animates out to the left (instead of down). Since the
+ // drawer comes from the right (beyond the bounds of the dialog), we should clip it so it
+ // doesn't draw outside the dialog background. This isn't an issue in portrait, since the
+ // drawer animates downward, below the volume row.
+ if (isLandscape()) {
+ mRingerAndDrawerContainer.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(
+ 0, 0, view.getWidth(), view.getHeight(), mDialogCornerRadius);
+ }
+ });
+ mRingerAndDrawerContainer.setClipToOutline(true);
+ }
+
+ mTopContainer.setBackground(background);
}
private final VolumeDialogController.Callbacks mControllerCallbackH
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
new file mode 100644
index 0000000..9d0cc6a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wallet.controller;
+
+import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE;
+import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.provider.Settings;
+import android.service.quickaccesswallet.GetWalletCardsRequest;
+import android.service.quickaccesswallet.QuickAccessWalletClient;
+import android.service.quickaccesswallet.QuickAccessWalletClientImpl;
+import android.util.Log;
+
+import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.util.settings.SecureSettings;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/**
+ * Controller to handle communication between SystemUI and Quick Access Wallet Client.
+ */
+@SysUISingleton
+public class QuickAccessWalletController {
+
+ /**
+ * Event for the wallet status change, e.g. the default payment app change and the wallet
+ * preference change.
+ */
+ public enum WalletChangeEvent {
+ DEFAULT_PAYMENT_APP_CHANGE,
+ WALLET_PREFERENCE_CHANGE,
+ }
+
+ private static final String TAG = "QAWController";
+ private final Context mContext;
+ private final Executor mExecutor;
+ private final SecureSettings mSecureSettings;
+
+ private QuickAccessWalletClient mQuickAccessWalletClient;
+ private ContentObserver mWalletPreferenceObserver;
+ private ContentObserver mDefaultPaymentAppObserver;
+ private int mWalletPreferenceChangeEvents = 0;
+ private int mDefaultPaymentAppChangeEvents = 0;
+ private boolean mWalletEnabled = false;
+
+ @Inject
+ public QuickAccessWalletController(
+ Context context,
+ @Main Executor executor,
+ SecureSettings secureSettings,
+ QuickAccessWalletClient quickAccessWalletClient) {
+ mContext = context;
+ mExecutor = executor;
+ mSecureSettings = secureSettings;
+ mQuickAccessWalletClient = quickAccessWalletClient;
+ }
+
+ /**
+ * Returns true if the Quick Access Wallet service & feature is available.
+ */
+ public boolean isWalletEnabled() {
+ return mWalletEnabled;
+ }
+
+ /**
+ * Returns the current instance of {@link QuickAccessWalletClient} in the controller.
+ */
+ public QuickAccessWalletClient getWalletClient() {
+ return mQuickAccessWalletClient;
+ }
+
+ /**
+ * Setup the wallet change observers per {@link WalletChangeEvent}
+ *
+ * @param cardsRetriever a callback that retrieves the wallet cards
+ * @param events {@link WalletChangeEvent} need to be handled.
+ */
+ public void setupWalletChangeObservers(
+ QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever,
+ WalletChangeEvent... events) {
+ for (WalletChangeEvent event : events) {
+ if (event == WALLET_PREFERENCE_CHANGE) {
+ setupWalletPreferenceObserver();
+ } else if (event == DEFAULT_PAYMENT_APP_CHANGE) {
+ setupDefaultPaymentAppObserver(cardsRetriever);
+ }
+ }
+ }
+
+ /**
+ * Unregister wallet change observers per {@link WalletChangeEvent} if needed.
+ *
+ */
+ public void unregisterWalletChangeObservers(WalletChangeEvent... events) {
+ for (WalletChangeEvent event : events) {
+ if (event == WALLET_PREFERENCE_CHANGE && mWalletPreferenceObserver != null) {
+ mWalletPreferenceChangeEvents--;
+ if (mWalletPreferenceChangeEvents == 0) {
+ mSecureSettings.unregisterContentObserver(mWalletPreferenceObserver);
+ }
+ } else if (event == DEFAULT_PAYMENT_APP_CHANGE && mDefaultPaymentAppObserver != null) {
+ mDefaultPaymentAppChangeEvents--;
+ if (mDefaultPaymentAppChangeEvents == 0) {
+ mSecureSettings.unregisterContentObserver(mDefaultPaymentAppObserver);
+ }
+ }
+ }
+ }
+
+ /**
+ * Update the "show wallet" preference.
+ */
+ public void updateWalletPreference() {
+ mWalletEnabled = mQuickAccessWalletClient.isWalletServiceAvailable()
+ && mQuickAccessWalletClient.isWalletFeatureAvailable()
+ && mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked();
+ }
+
+ /**
+ * Query the wallet cards from {@link QuickAccessWalletClient}.
+ *
+ * @param cardsRetriever a callback to retrieve wallet cards.
+ */
+ public void queryWalletCards(
+ QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever) {
+ if (!mWalletEnabled) {
+ Log.w(TAG, "QuickAccessWallet is unavailable, unable to query cards.");
+ return;
+ }
+ int cardWidth =
+ mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_width);
+ int cardHeight =
+ mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_height);
+ int iconSizePx = mContext.getResources().getDimensionPixelSize(R.dimen.wallet_icon_size);
+ GetWalletCardsRequest request =
+ new GetWalletCardsRequest(cardWidth, cardHeight, iconSizePx, /* maxCards= */ 1);
+ mQuickAccessWalletClient.getWalletCards(mExecutor, request, cardsRetriever);
+ }
+
+ /**
+ * Re-create the {@link QuickAccessWalletClient} of the controller.
+ */
+ public void reCreateWalletClient() {
+ mQuickAccessWalletClient = QuickAccessWalletClient.create(mContext);
+ }
+
+ private void setupDefaultPaymentAppObserver(
+ QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever) {
+ if (mDefaultPaymentAppObserver == null) {
+ mDefaultPaymentAppObserver = new ContentObserver(null /* handler */) {
+ @Override
+ public void onChange(boolean selfChange) {
+ mExecutor.execute(() -> {
+ reCreateWalletClient();
+ updateWalletPreference();
+ queryWalletCards(cardsRetriever);
+ });
+ }
+ };
+
+ mSecureSettings.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT),
+ false /* notifyForDescendants */,
+ mDefaultPaymentAppObserver);
+ }
+ mDefaultPaymentAppChangeEvents++;
+ }
+
+ private void setupWalletPreferenceObserver() {
+ if (mWalletPreferenceObserver == null) {
+ mWalletPreferenceObserver = new ContentObserver(null /* handler */) {
+ @Override
+ public void onChange(boolean selfChange) {
+ mExecutor.execute(() -> {
+ updateWalletPreference();
+ });
+ }
+ };
+
+ mSecureSettings.registerContentObserver(
+ Settings.Secure.getUriFor(QuickAccessWalletClientImpl.SETTING_KEY),
+ false /* notifyForDescendants */,
+ mWalletPreferenceObserver);
+ }
+ mWalletPreferenceChangeEvents++;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
index 83aa01f..c6123e7 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java
@@ -24,6 +24,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.service.quickaccesswallet.QuickAccessWalletClient;
+import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
@@ -52,7 +53,7 @@
*/
public class WalletActivity extends LifecycleActivity {
- private final QuickAccessWalletClient mQuickAccessWalletClient;
+ private static final String TAG = "WalletActivity";
private final KeyguardStateController mKeyguardStateController;
private final KeyguardDismissUtil mKeyguardDismissUtil;
private final ActivityStarter mActivityStarter;
@@ -65,7 +66,6 @@
@Inject
public WalletActivity(
- QuickAccessWalletClient quickAccessWalletClient,
KeyguardStateController keyguardStateController,
KeyguardDismissUtil keyguardDismissUtil,
ActivityStarter activityStarter,
@@ -74,7 +74,6 @@
FalsingManager falsingManager,
UserTracker userTracker,
StatusBarKeyguardViewManager keyguardViewManager) {
- mQuickAccessWalletClient = quickAccessWalletClient;
mKeyguardStateController = keyguardStateController;
mKeyguardDismissUtil = keyguardDismissUtil;
mActivityStarter = activityStarter;
@@ -103,10 +102,11 @@
getActionBar().setHomeActionContentDescription(R.string.accessibility_desc_close);
WalletView walletView = requireViewById(R.id.wallet_view);
+ QuickAccessWalletClient walletClient = QuickAccessWalletClient.create(this);
mWalletScreenController = new WalletScreenController(
this,
walletView,
- mQuickAccessWalletClient,
+ walletClient,
mActivityStarter,
mExecutor,
mHandler,
@@ -116,6 +116,10 @@
walletView.getAppButton().setOnClickListener(
v -> {
+ if (walletClient.createWalletIntent() == null) {
+ Log.w(TAG, "Unable to create wallet app intent.");
+ return;
+ }
if (!mKeyguardStateController.isUnlocked()
&& mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return;
@@ -123,12 +127,12 @@
if (mKeyguardStateController.isUnlocked()) {
mActivityStarter.startActivity(
- mQuickAccessWalletClient.createWalletIntent(), true);
+ walletClient.createWalletIntent(), true);
finish();
} else {
mKeyguardDismissUtil.executeWhenUnlocked(() -> {
mActivityStarter.startActivity(
- mQuickAccessWalletClient.createWalletIntent(), true);
+ walletClient.createWalletIntent(), true);
finish();
return false;
}, false, true);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 10322f2..06b0bb2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -40,8 +40,10 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -86,6 +88,9 @@
@Mock
Resources mResources;
+ KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ @Mock
+ SmartspaceTransitionController mSmartSpaceTransitionController;
@Mock
private ClockPlugin mClockPlugin;
@Mock
@@ -135,7 +140,10 @@
mBatteryController,
mKeyguardUpdateMonitor,
mBypassController,
- mSmartspaceController);
+ mSmartspaceController,
+ mKeyguardUnlockAnimationController,
+ mSmartSpaceTransitionController
+ );
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 49f1655..f9b6d44 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -22,6 +22,8 @@
import android.testing.AndroidTestingRunner;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -50,6 +52,10 @@
ConfigurationController mConfigurationController;
@Mock
DozeParameters mDozeParameters;
+ @Mock
+ KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
+ @Mock
+ SmartspaceTransitionController mSmartSpaceTransitionController;
private KeyguardStatusViewController mController;
@@ -64,7 +70,9 @@
mKeyguardStateController,
mKeyguardUpdateMonitor,
mConfigurationController,
- mDozeParameters);
+ mDozeParameters,
+ mKeyguardUnlockAnimationController,
+ mSmartSpaceTransitionController);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index d9a240f..936ec80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -100,8 +100,6 @@
private AccessibilityManager mAccessibilityManager;
@Mock
private SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
- @Mock
- private Handler mHandler;
private TestableWindowManager mWindowManager;
private ViewPropertyAnimator mViewPropertyAnimator;
private MagnificationModeSwitch mMagnificationModeSwitch;
@@ -152,12 +150,12 @@
}
@Test
- public void showWindowModeButton_fullscreenMode_addViewAndSetImageResource() {
- mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+ public void showFullscreenModeButton_addViewAndSetImageResource() {
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
verify(mSpyImageView).setImageResource(
- getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW));
- verify(mWindowManager).addView(eq(mSpyImageView), any(WindowManager.LayoutParams.class));
+ getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN));
+ assertEquals(mSpyImageView, mWindowManager.getAttachedView());
assertShowFadingAnimation(FADE_IN_ALPHA);
assertShowFadingAnimation(FADE_OUT_ALPHA);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 5fa63bc..ad99e4d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -59,6 +59,7 @@
import android.view.accessibility.AccessibilityNodeInfo;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.LargeTest;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
@@ -72,7 +73,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
-import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@@ -91,7 +91,7 @@
@Mock
private WindowMagnifierCallback mWindowMagnifierCallback;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
- private SurfaceControl.Transaction mTransaction;
+ private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
private TestableWindowManager mWindowManager;
private SysUiState mSysUiState = new SysUiState();
private Resources mResources;
@@ -138,6 +138,7 @@
}
@Test
+ @FlakyTest(bugId = 188889181)
public void enableWindowMagnification_showControlAndNotifyBoundsChanged() {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
@@ -145,16 +146,9 @@
});
verify(mMirrorWindowControl).showControl();
- ArgumentCaptor<Rect> boundsCaptor = ArgumentCaptor.forClass(Rect.class);
verify(mWindowMagnifierCallback,
- timeout(LAYOUT_CHANGE_TIMEOUT_MS)).onWindowMagnifierBoundsChanged(
- eq(mContext.getDisplayId()), boundsCaptor.capture());
- final Rect actualBounds = new Rect();
- final View mirrorView = mWindowManager.getAttachedView();
- assertNotNull(mirrorView);
- mirrorView.getBoundsOnScreen(actualBounds);
- assertEquals(actualBounds, boundsCaptor.getValue());
-
+ timeout(LAYOUT_CHANGE_TIMEOUT_MS).atLeastOnce()).onWindowMagnifierBoundsChanged(
+ eq(mContext.getDisplayId()), any(Rect.class));
}
@Test
@@ -203,6 +197,12 @@
@Test
public void setScale_enabled_expectedValueAndUpdateStateDescription() {
+ doAnswer(invocation -> {
+ final Runnable runnable = invocation.getArgument(0);
+ runnable.run();
+ return null;
+ }).when(mHandler).postDelayed(any(Runnable.class), anyLong());
+
mInstrumentation.runOnMainSync(
() -> mWindowMagnificationController.enableWindowMagnification(2.0f, Float.NaN,
Float.NaN));
@@ -210,9 +210,6 @@
mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.setScale(3.0f));
assertEquals(3.0f, mWindowMagnificationController.getScale(), 0);
- ArgumentCaptor<Runnable> runnableArgumentCaptor = ArgumentCaptor.forClass(Runnable.class);
- verify(mHandler).postDelayed(runnableArgumentCaptor.capture(), anyLong());
- runnableArgumentCaptor.getValue().run();
final View mirrorView = mWindowManager.getAttachedView();
assertNotNull(mirrorView);
assertThat(mirrorView.getStateDescription().toString(), containsString("300"));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
index 897d78b..f2ef5c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
@@ -51,7 +51,11 @@
// We start in a new thread so that we can ensure that the callbacks are called in the main
// thread.
thread {
- activityLaunchAnimator.startIntentWithAnimation(controller, animate, intentStarter)
+ activityLaunchAnimator.startIntentWithAnimation(
+ controller = controller,
+ animate = animate,
+ intentStarter = intentStarter
+ )
}.join()
}
@@ -135,11 +139,14 @@
verify(controller).onLaunchAnimationStart(anyBoolean())
}
- private fun fakeWindow() = RemoteAnimationTarget(
- 0, RemoteAnimationTarget.MODE_OPENING, SurfaceControl(), false, Rect(), Rect(), 0,
- Point(), Rect(), Rect(), WindowConfiguration(), false, SurfaceControl(), Rect(),
- ActivityManager.RunningTaskInfo()
- )
+ private fun fakeWindow(): RemoteAnimationTarget {
+ val bounds = Rect(10 /* left */, 20 /* top */, 30 /* right */, 40 /* bottom */)
+ return RemoteAnimationTarget(
+ 0, RemoteAnimationTarget.MODE_OPENING, SurfaceControl(), false, Rect(), Rect(), 0,
+ Point(), Rect(), bounds, WindowConfiguration(), false, SurfaceControl(), Rect(),
+ ActivityManager.RunningTaskInfo()
+ )
+ }
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
new file mode 100644
index 0000000..5f3d3cb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
+
+ @Mock AuthBiometricView.Callback mCallback;
+
+ private AuthBiometricFaceToFingerprintView mFaceToFpView;
+
+ @Mock private Button mNegativeButton;
+ @Mock private Button mCancelButton;
+ @Mock private Button mConfirmButton;
+ @Mock private Button mUseCredentialButton;
+ @Mock private Button mTryAgainButton;
+
+ @Mock private TextView mTitleView;
+ @Mock private TextView mSubtitleView;
+ @Mock private TextView mDescriptionView;
+ @Mock private TextView mIndicatorView;
+ @Mock private ImageView mIconView;
+ @Mock private View mIconHolderView;
+
+ @Mock private TextView mErrorView;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ mFaceToFpView = new TestableView(mContext);
+ mFaceToFpView.mIconController = mock(AuthBiometricFaceView.IconController.class);
+ mFaceToFpView.setCallback(mCallback);
+
+ mFaceToFpView.mNegativeButton = mNegativeButton;
+ mFaceToFpView.mCancelButton = mCancelButton;
+ mFaceToFpView.mUseCredentialButton = mUseCredentialButton;
+ mFaceToFpView.mConfirmButton = mConfirmButton;
+ mFaceToFpView.mTryAgainButton = mTryAgainButton;
+
+ mFaceToFpView.mIndicatorView = mErrorView;
+ }
+
+ @Test
+ public void testStateUpdated_whenDialogAnimatedIn() {
+ mFaceToFpView.onDialogAnimatedIn();
+ verify(mFaceToFpView.mIconController)
+ .updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
+ }
+
+ @Test
+ public void testIconUpdatesState_whenDialogStateUpdated() {
+ mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING);
+ verify(mFaceToFpView.mIconController)
+ .updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
+
+ mFaceToFpView.updateState(AuthBiometricFaceView.STATE_AUTHENTICATED);
+ verify(mFaceToFpView.mIconController).updateState(
+ eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING),
+ eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED));
+ }
+
+ @Test
+ public void testStateUpdated_whenSwitchToFingerprint() {
+ mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING);
+ verify(mFaceToFpView.mIconController)
+ .updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
+
+ mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_ERROR);
+ mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING);
+
+ InOrder order = inOrder(mFaceToFpView.mIconController);
+ order.verify(mFaceToFpView.mIconController).updateState(
+ eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING),
+ eq(AuthBiometricFaceToFingerprintView.STATE_ERROR));
+ order.verify(mFaceToFpView.mIconController).updateState(
+ eq(AuthBiometricFaceToFingerprintView.STATE_ERROR),
+ eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
+
+ verify(mConfirmButton).setVisibility(eq(View.GONE));
+ }
+
+ public class TestableView extends AuthBiometricFaceToFingerprintView {
+ public TestableView(Context context) {
+ super(context, null, new MockInjector());
+ }
+
+ @Override
+ protected int getDelayAfterAuthenticatedDurationMs() {
+ return 0;
+ }
+
+ @Override
+ protected IconController createUdfpsIconController() {
+ return mIconController;
+ }
+ }
+
+ private class MockInjector extends AuthBiometricView.Injector {
+ @Override
+ public Button getNegativeButton() {
+ return mNegativeButton;
+ }
+
+ @Override
+ public Button getCancelButton() {
+ return mCancelButton;
+ }
+
+ @Override
+ public Button getUseCredentialButton() {
+ return mUseCredentialButton;
+ }
+
+ @Override
+ public Button getConfirmButton() {
+ return mConfirmButton;
+ }
+
+ @Override
+ public Button getTryAgainButton() {
+ return mTryAgainButton;
+ }
+
+ @Override
+ public TextView getTitleView() {
+ return mTitleView;
+ }
+
+ @Override
+ public TextView getSubtitleView() {
+ return mSubtitleView;
+ }
+
+ @Override
+ public TextView getDescriptionView() {
+ return mDescriptionView;
+ }
+
+ @Override
+ public TextView getIndicatorView() {
+ return mIndicatorView;
+ }
+
+ @Override
+ public ImageView getIconView() {
+ return mIconView;
+ }
+
+ @Override
+ public View getIconHolderView() {
+ return mIconHolderView;
+ }
+
+ @Override
+ public int getDelayAfterError() {
+ return 0;
+ }
+
+ @Override
+ public int getMediumToLargeAnimationDurationMs() {
+ return 0;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
index 36a031a..06f9253 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
@@ -26,6 +26,7 @@
import static org.mockito.Mockito.verify;
import android.content.Context;
+import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.PromptInfo;
import android.os.Bundle;
import android.test.suitebuilder.annotation.SmallTest;
@@ -202,7 +203,7 @@
waitForIdleSync();
verify(mCallback).onAction(AuthBiometricView.Callback.ACTION_ERROR);
- assertEquals(AuthBiometricView.STATE_ERROR, mBiometricView.mState);
+ assertEquals(AuthBiometricView.STATE_IDLE, mBiometricView.mState);
}
@Test
@@ -253,6 +254,12 @@
public TextView getIndicatorView() {
return indicatorView;
}
+
+ @Override
+ public int getDelayAfterError() {
+ // keep a real delay to test saving in the error state
+ return BiometricPrompt.HIDE_DIALOG_DELAY;
+ }
});
final String failureMessage = "testFailureMessage";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 47fdcaf..db5648a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -17,6 +17,7 @@
package com.android.systemui.biometrics;
import static android.hardware.biometrics.BiometricManager.Authenticators;
+import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
@@ -41,6 +42,7 @@
import android.content.res.Configuration;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.IBiometricSysuiReceiver;
@@ -60,7 +62,6 @@
import com.android.internal.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import org.junit.Before;
@@ -94,8 +95,6 @@
@Mock
private CommandQueue mCommandQueue;
@Mock
- private StatusBarStateController mStatusBarStateController;
- @Mock
private ActivityTaskManager mActivityTaskManager;
@Mock
private FingerprintManager mFingerprintManager;
@@ -150,7 +149,7 @@
when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props);
mAuthController = new TestableAuthController(context, mCommandQueue,
- mStatusBarStateController, mActivityTaskManager, mFingerprintManager, mFaceManager,
+ mActivityTaskManager, mFingerprintManager, mFaceManager,
() -> mUdfpsController, () -> mSidefpsController);
mAuthController.start();
@@ -528,7 +527,8 @@
true /* requireConfirmation */,
0 /* userId */,
"testPackage",
- 0 /* operationId */);
+ 0 /* operationId */,
+ BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT);
}
private PromptInfo createTestPromptInfo() {
@@ -558,13 +558,12 @@
private PromptInfo mLastBiometricPromptInfo;
TestableAuthController(Context context, CommandQueue commandQueue,
- StatusBarStateController statusBarStateController,
ActivityTaskManager activityTaskManager,
FingerprintManager fingerprintManager,
FaceManager faceManager,
Provider<UdfpsController> udfpsControllerFactory,
Provider<SidefpsController> sidefpsControllerFactory) {
- super(context, commandQueue, statusBarStateController, activityTaskManager,
+ super(context, commandQueue, activityTaskManager,
fingerprintManager, faceManager, udfpsControllerFactory,
sidefpsControllerFactory);
}
@@ -572,7 +571,8 @@
@Override
protected AuthDialog buildDialog(PromptInfo promptInfo,
boolean requireConfirmation, int userId, int[] sensorIds, boolean credentialAllowed,
- String opPackageName, boolean skipIntro, long operationId) {
+ String opPackageName, boolean skipIntro, long operationId,
+ @BiometricManager.BiometricMultiSensorMode int multiSensorConfig) {
mLastBiometricPromptInfo = promptInfo;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index 247748a..240fdf3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -26,6 +26,7 @@
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.StatusBar
import com.android.systemui.statusbar.policy.ConfigurationController
import org.junit.Before
import org.junit.Test
@@ -44,6 +45,7 @@
@RunWith(AndroidTestingRunner::class)
class AuthRippleControllerTest : SysuiTestCase() {
private lateinit var controller: AuthRippleController
+ @Mock private lateinit var statusBar: StatusBar
@Mock private lateinit var rippleView: AuthRippleView
@Mock private lateinit var commandRegistry: CommandRegistry
@Mock private lateinit var configurationController: ConfigurationController
@@ -56,6 +58,7 @@
fun setUp() {
MockitoAnnotations.initMocks(this)
controller = AuthRippleController(
+ statusBar,
context,
authController,
configurationController,
@@ -72,7 +75,7 @@
fun testFingerprintTrigger_Ripple() {
// GIVEN fp exists, keyguard is visible, user doesn't need strong auth
val fpsLocation = PointF(5f, 5f)
- `when`(authController.udfpsSensorLocation).thenReturn(fpsLocation)
+ `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
controller.onViewAttached()
`when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
`when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
@@ -193,7 +196,7 @@
@Test
fun testNullFingerprintSensorLocationDoesNothing() {
- `when`(authController.udfpsSensorLocation).thenReturn(null)
+ `when`(authController.fingerprintSensorLocation).thenReturn(null)
controller.onViewAttached()
val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index e1f1dc1..2d19f7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -23,6 +23,7 @@
import android.media.MediaMetadata
import android.media.session.MediaSession
import android.media.session.PlaybackState
+import android.os.Handler
import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -54,7 +55,6 @@
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Mock
-import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@@ -110,8 +110,10 @@
private lateinit var action2: ImageButton
private lateinit var action3: ImageButton
private lateinit var action4: ImageButton
- private lateinit var settingsText: TextView
+ @Mock private lateinit var longPressText: TextView
+ @Mock private lateinit var handler: Handler
private lateinit var settings: View
+ private lateinit var settingsText: TextView
private lateinit var cancel: View
private lateinit var dismiss: FrameLayout
private lateinit var dismissLabel: View
@@ -170,10 +172,12 @@
whenever(holder.action3).thenReturn(action3)
action4 = ImageButton(context)
whenever(holder.action4).thenReturn(action4)
- settingsText = TextView(context)
- whenever(holder.settingsText).thenReturn(settingsText)
+ whenever(holder.longPressText).thenReturn(longPressText)
+ whenever(longPressText.handler).thenReturn(handler)
settings = View(context)
whenever(holder.settings).thenReturn(settings)
+ settingsText = TextView(context)
+ whenever(holder.settingsText).thenReturn(settingsText)
cancel = View(context)
whenever(holder.cancel).thenReturn(cancel)
dismiss = FrameLayout(context)
@@ -324,11 +328,6 @@
assertThat(dismiss.isEnabled).isEqualTo(true)
dismiss.callOnClick()
- val captor = ArgumentCaptor.forClass(ActivityStarter.OnDismissAction::class.java)
- verify(keyguardDismissUtil).executeWhenUnlocked(captor.capture(), anyBoolean(),
- eq(false))
-
- captor.value.onDismiss()
verify(mediaDataManager).dismissMediaData(eq(mediaKey), anyLong())
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index c6aef4a..bf87a4a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -20,6 +20,7 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.ViewGroup
+import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq
@@ -33,6 +34,7 @@
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.animation.UniqueObjectHostView
+import junit.framework.Assert
import org.junit.Assert.assertNotNull
import org.junit.Before
import org.junit.Rule
@@ -65,8 +67,6 @@
@Mock
private lateinit var bypassController: KeyguardBypassController
@Mock
- private lateinit var mediaFrame: ViewGroup
- @Mock
private lateinit var keyguardStateController: KeyguardStateController
@Mock
private lateinit var statusBarStateController: SysuiStatusBarStateController
@@ -90,9 +90,11 @@
@Rule
val mockito = MockitoJUnit.rule()
private lateinit var mediaHiearchyManager: MediaHierarchyManager
+ private lateinit var mediaFrame: ViewGroup
@Before
fun setup() {
+ mediaFrame = FrameLayout(context)
`when`(mediaCarouselController.mediaFrame).thenReturn(mediaFrame)
mediaHiearchyManager = MediaHierarchyManager(
context,
@@ -112,6 +114,9 @@
`when`(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
`when`(mediaCarouselController.mediaCarouselScrollHandler)
.thenReturn(mediaCarouselScrollHandler)
+ val observer = wakefullnessObserver.value
+ assertNotNull("lifecycle observer wasn't registered", observer)
+ observer.onFinishedWakingUp()
// We'll use the viewmanager to verify a few calls below, let's reset this.
clearInvocations(mediaCarouselController)
}
@@ -120,6 +125,7 @@
`when`(host.location).thenReturn(location)
`when`(host.currentBounds).thenReturn(Rect())
`when`(host.hostView).thenReturn(UniqueObjectHostView(context))
+ `when`(host.visible).thenReturn(true)
mediaHiearchyManager.register(host)
}
@@ -160,6 +166,73 @@
}
@Test
+ fun testGoingToFullShade() {
+ // Let's set it onto Lock screen
+ `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(
+ true)
+ statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
+ clearInvocations(mediaCarouselController)
+
+ // Let's transition all the way to full shade
+ mediaHiearchyManager.setTransitionToFullShadeAmount(100000f)
+ verify(mediaCarouselController).onDesiredLocationChanged(
+ eq(MediaHierarchyManager.LOCATION_QQS),
+ any(MediaHostState::class.java),
+ eq(false),
+ anyLong(),
+ anyLong())
+ clearInvocations(mediaCarouselController)
+
+ // Let's go back to the lock screen
+ mediaHiearchyManager.setTransitionToFullShadeAmount(0.0f)
+ verify(mediaCarouselController).onDesiredLocationChanged(
+ eq(MediaHierarchyManager.LOCATION_LOCKSCREEN),
+ any(MediaHostState::class.java),
+ eq(false),
+ anyLong(),
+ anyLong())
+
+ // Let's make sure alpha is set
+ mediaHiearchyManager.setTransitionToFullShadeAmount(2.0f)
+ Assert.assertTrue("alpha should not be 1.0f when cross fading", mediaFrame.alpha != 1.0f)
+ }
+
+ @Test
+ fun testTransformationOnLockScreenIsFading() {
+ // Let's set it onto Lock screen
+ `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(
+ true)
+ statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
+ clearInvocations(mediaCarouselController)
+
+ // Let's transition from lockscreen to qs
+ mediaHiearchyManager.qsExpansion = 1.0f
+ val transformType = mediaHiearchyManager.calculateTransformationType()
+ Assert.assertTrue("media isn't transforming to qs with a fade",
+ transformType == MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
+ }
+
+ @Test
+ fun testTransformationOnLockScreenToQQSisFading() {
+ // Let's set it onto Lock screen
+ `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(
+ true)
+ statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
+ clearInvocations(mediaCarouselController)
+
+ // Let's transition from lockscreen to qs
+ `when`(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
+ statusBarCallback.value.onStatePreChange(StatusBarState.KEYGUARD,
+ StatusBarState.SHADE_LOCKED)
+ val transformType = mediaHiearchyManager.calculateTransformationType()
+ Assert.assertTrue("media isn't transforming to qqswith a fade",
+ transformType == MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
+ }
+
+ @Test
fun testCloseGutsRelayToCarousel() {
mediaHiearchyManager.closeGuts()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
index 96d1d94..4e1627f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
@@ -89,6 +89,7 @@
@Mock private lateinit var dumpManager: DumpManager
@Captor lateinit var callbackCaptor: ArgumentCaptor<ResumeMediaBrowser.Callback>
+ @Captor lateinit var actionCaptor: ArgumentCaptor<Runnable>
private lateinit var executor: FakeExecutor
private lateinit var data: MediaData
@@ -224,9 +225,6 @@
// But we do not tell it to add new controls
verify(mediaDataManager, never())
.addResumptionControls(anyInt(), any(), any(), any(), any(), any(), any())
-
- // Finally, make sure the resume browser disconnected
- verify(resumeBrowser).disconnect()
}
@Test
@@ -267,4 +265,39 @@
verify(mediaDataManager, times(3)).addResumptionControls(anyInt(),
any(), any(), any(), any(), any(), eq(PACKAGE_NAME))
}
+
+ @Test
+ fun testGetResumeAction_restarts() {
+ // Set up mocks to successfully find a MBS that returns valid media
+ val pm = mock(PackageManager::class.java)
+ whenever(mockContext.packageManager).thenReturn(pm)
+ val resolveInfo = ResolveInfo()
+ val serviceInfo = ServiceInfo()
+ serviceInfo.packageName = PACKAGE_NAME
+ resolveInfo.serviceInfo = serviceInfo
+ resolveInfo.serviceInfo.name = CLASS_NAME
+ val resumeInfo = listOf(resolveInfo)
+ whenever(pm.queryIntentServices(any(), anyInt())).thenReturn(resumeInfo)
+
+ val description = MediaDescription.Builder().setTitle(TITLE).build()
+ val component = ComponentName(PACKAGE_NAME, CLASS_NAME)
+ whenever(resumeBrowser.testConnection()).thenAnswer {
+ callbackCaptor.value.addTrack(description, component, resumeBrowser)
+ }
+
+ // When media data is loaded that has not been checked yet, and does have a MBS
+ val dataCopy = data.copy(resumeAction = null, hasCheckedForResume = false)
+ resumeListener.onMediaDataLoaded(KEY, null, dataCopy)
+
+ // Then we test whether the service is valid and set the resume action
+ executor.runAllReady()
+ verify(resumeBrowser).testConnection()
+ verify(mediaDataManager).setResumeAction(eq(KEY), capture(actionCaptor))
+
+ // When the resume action is run
+ actionCaptor.value.run()
+
+ // Then we call restart
+ verify(resumeBrowser).restart()
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt
index d26229e..dfa7c66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt
@@ -91,8 +91,9 @@
setupBrowserFailed()
resumeBrowser.testConnection()
- // Then it calls onError
+ // Then it calls onError and disconnects
verify(callback).onError()
+ verify(browser).disconnect()
}
@Test
@@ -111,8 +112,9 @@
setupBrowserConnectionNoResults()
resumeBrowser.testConnection()
- // Then it calls onError
+ // Then it calls onError and disconnects
verify(callback).onError()
+ verify(browser).disconnect()
}
@Test
@@ -132,8 +134,9 @@
setupBrowserFailed()
resumeBrowser.findRecentMedia()
- // Then it calls onError
+ // Then it calls onError and disconnects
verify(callback).onError()
+ verify(browser).disconnect()
}
@Test
@@ -143,8 +146,9 @@
whenever(browser.getRoot()).thenReturn(null)
resumeBrowser.findRecentMedia()
- // Then it calls onError
+ // Then it calls onError and disconnects
verify(callback).onError()
+ verify(browser).disconnect()
}
@Test
@@ -163,8 +167,9 @@
setupBrowserConnectionNoResults()
resumeBrowser.findRecentMedia()
- // Then it calls onError
+ // Then it calls onError and disconnects
verify(callback).onError()
+ verify(browser).disconnect()
}
@Test
@@ -173,8 +178,9 @@
setupBrowserConnectionNotPlayable()
resumeBrowser.findRecentMedia()
- // Then it calls onError
+ // Then it calls onError and disconnects
verify(callback).onError()
+ verify(browser).disconnect()
}
@Test
@@ -193,8 +199,9 @@
setupBrowserFailed()
resumeBrowser.restart()
- // Then it calls onError
+ // Then it calls onError and disconnects
verify(callback).onError()
+ verify(browser).disconnect()
}
@Test
@@ -202,13 +209,11 @@
// When restart is called and we connect successfully
setupBrowserConnection()
resumeBrowser.restart()
+ verify(callback).onConnected()
// Then it creates a new controller and sends play command
verify(transportControls).prepare()
verify(transportControls).play()
-
- // Then it calls onConnected
- verify(callback).onConnected()
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
index fd28c2c..007a3b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
@@ -285,6 +285,73 @@
}
@Test
+ public void testAugmentTileFromNotificationGroupWithImageUri() {
+ Notification notification = new Notification.Builder(mContext, "test")
+ .setContentTitle("TEST_TITLE")
+ .setContentText("TEST_TEXT")
+ .setShortcutId(SHORTCUT_ID_1)
+ .setStyle(new Notification.MessagingStyle(PERSON)
+ .addMessage(new Notification.MessagingStyle.Message(
+ NOTIFICATION_TEXT_1, 0, PERSON)
+ .setData("image/jpeg", URI))
+ )
+ .build();
+ NotificationEntry notificationEntry = new NotificationEntryBuilder()
+ .setNotification(notification)
+ .setShortcutInfo(new ShortcutInfo.Builder(mContext, SHORTCUT_ID_1).build())
+ .setUser(UserHandle.of(0))
+ .setPkg(PACKAGE_NAME)
+ .build();
+ PeopleSpaceTile tile =
+ new PeopleSpaceTile
+ .Builder(SHORTCUT_ID_1, "userName", ICON, new Intent())
+ .setPackageName(PACKAGE_NAME)
+ .setUserHandle(new UserHandle(0))
+ .build();
+ PeopleTileKey key = new PeopleTileKey(tile);
+ PeopleSpaceTile actual = PeopleSpaceUtils
+ .augmentTileFromNotification(mContext, tile, key, notificationEntry, 0,
+ Optional.empty());
+
+ assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_TEXT_1);
+ assertThat(actual.getNotificationDataUri()).isEqualTo(URI);
+ }
+
+ @Test
+ public void testAugmentTileFromNotificationGroupWithAudioUri() {
+ Notification notification = new Notification.Builder(mContext, "test")
+ .setContentTitle("TEST_TITLE")
+ .setContentText("TEST_TEXT")
+ .setShortcutId(SHORTCUT_ID_1)
+ .setStyle(new Notification.MessagingStyle(PERSON)
+ .addMessage(new Notification.MessagingStyle.Message(
+ NOTIFICATION_TEXT_1, 0, PERSON)
+ .setData("audio/ogg", URI))
+ )
+ .build();
+ NotificationEntry notificationEntry = new NotificationEntryBuilder()
+ .setNotification(notification)
+ .setShortcutInfo(new ShortcutInfo.Builder(mContext, SHORTCUT_ID_1).build())
+ .setUser(UserHandle.of(0))
+ .setPkg(PACKAGE_NAME)
+ .build();
+ PeopleSpaceTile tile =
+ new PeopleSpaceTile
+ .Builder(SHORTCUT_ID_1, "userName", ICON, new Intent())
+ .setPackageName(PACKAGE_NAME)
+ .setUserHandle(new UserHandle(0))
+ .build();
+ PeopleTileKey key = new PeopleTileKey(tile);
+ PeopleSpaceTile actual = PeopleSpaceUtils
+ .augmentTileFromNotification(mContext, tile, key, notificationEntry, 0,
+ Optional.empty());
+
+ assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_TEXT_1);
+ assertThat(actual.getNotificationDataUri()).isNull();
+ }
+
+
+ @Test
public void testAugmentTileFromNotificationNoContent() {
PeopleSpaceTile tile =
new PeopleSpaceTile
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
index 3b56f22..67505c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
@@ -69,6 +69,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.time.Duration;
import java.util.Arrays;
@RunWith(AndroidTestingRunner.class)
@@ -185,6 +186,30 @@
}
@Test
+ public void testLastInteractionTime() {
+ long now = System.currentTimeMillis();
+ long fiveDaysAgo = now - Duration.ofDays(5).toMillis();
+ String lastInteractionString = PeopleTileViewHelper.getLastInteractionString(mContext,
+ fiveDaysAgo);
+ assertThat(lastInteractionString).isEqualTo("5 days ago");
+
+ long lessThanOneDayAgo = now - Duration.ofHours(20).toMillis();
+ lastInteractionString = PeopleTileViewHelper.getLastInteractionString(mContext,
+ lessThanOneDayAgo);
+ assertThat(lastInteractionString).isNull();
+
+ long overOneWeekAgo = now - Duration.ofDays(8).toMillis();
+ lastInteractionString = PeopleTileViewHelper.getLastInteractionString(mContext,
+ overOneWeekAgo);
+ assertThat(lastInteractionString).isEqualTo("Over 1 week ago");
+
+ long overTwoWeeksAgo = now - Duration.ofDays(15).toMillis();
+ lastInteractionString = PeopleTileViewHelper.getLastInteractionString(mContext,
+ overTwoWeeksAgo);
+ assertThat(lastInteractionString).isEqualTo("Over 2 weeks ago");
+ }
+
+ @Test
public void testCreateRemoteViewsWithLastInteractionTime() {
PeopleSpaceTile tileWithLastInteraction =
PERSON_TILE_WITHOUT_NOTIFICATION.toBuilder().setLastInteractionTimestamp(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
index 7533cf1..b09afab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
@@ -73,6 +73,7 @@
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
+import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.google.common.util.concurrent.MoreExecutors;
@@ -119,6 +120,8 @@
@Mock
private SecureSettings mSecureSettings;
@Mock
+ private QuickAccessWalletController mController;
+ @Mock
private FeatureFlags mFeatureFlags;
@Captor
ArgumentCaptor<Intent> mIntentCaptor;
@@ -145,6 +148,8 @@
when(mQuickAccessWalletClient.getServiceLabel()).thenReturn(LABEL);
when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(true);
when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(true);
+ when(mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked()).thenReturn(true);
+ when(mController.getWalletClient()).thenReturn(mQuickAccessWalletClient);
mTile = new QuickAccessWalletTile(
mHost,
@@ -155,11 +160,11 @@
mStatusBarStateController,
mActivityStarter,
mQSLogger,
- mQuickAccessWalletClient,
mKeyguardStateController,
mPackageManager,
mSecureSettings,
MoreExecutors.directExecutor(),
+ mController,
mFeatureFlags);
}
@@ -175,6 +180,15 @@
}
@Test
+ public void testWalletServiceUnavailable_recreateWalletClient() {
+ when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
+
+ mTile.handleSetListening(true);
+
+ verify(mController, times(1)).reCreateWalletClient();
+ }
+
+ @Test
public void testIsAvailable_qawFeatureAvailable() {
when(mPackageManager.hasSystemFeature(FEATURE_NFC_HOST_CARD_EMULATION)).thenReturn(true);
when(mPackageManager.hasSystemFeature("org.chromium.arc")).thenReturn(false);
@@ -330,17 +344,8 @@
public void testHandleSetListening_queryCards() {
mTile.handleSetListening(true);
- verify(mQuickAccessWalletClient)
- .getWalletCards(any(), mRequestCaptor.capture(), mCallbackCaptor.capture());
+ verify(mController).queryWalletCards(mCallbackCaptor.capture());
- GetWalletCardsRequest request = mRequestCaptor.getValue();
- assertEquals(
- mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_width),
- request.getCardWidthPx());
- assertEquals(
- mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_height),
- request.getCardHeightPx());
- assertEquals(1, request.getMaxCards());
assertThat(mCallbackCaptor.getValue()).isInstanceOf(
QuickAccessWalletClient.OnWalletCardsRetrievedCallback.class);
}
@@ -354,37 +359,6 @@
}
@Test
- public void testState_queryCards_hasCards_then_noCards() {
- when(mKeyguardStateController.isUnlocked()).thenReturn(true);
- GetWalletCardsResponse responseWithCards =
- new GetWalletCardsResponse(
- Collections.singletonList(createWalletCard(mContext)), 0);
- GetWalletCardsResponse responseWithoutCards =
- new GetWalletCardsResponse(Collections.EMPTY_LIST, 0);
-
- mTile.handleSetListening(true);
-
- verify(mQuickAccessWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
-
- // query wallet cards, has cards
- mCallbackCaptor.getValue().onWalletCardsRetrieved(responseWithCards);
- mTestableLooper.processAllMessages();
-
- assertNotNull(mTile.getState().sideViewCustomDrawable);
-
- mTile.handleSetListening(true);
-
- verify(mQuickAccessWalletClient, times(2))
- .getWalletCards(any(), any(), mCallbackCaptor.capture());
-
- // query wallet cards, has no cards
- mCallbackCaptor.getValue().onWalletCardsRetrieved(responseWithoutCards);
- mTestableLooper.processAllMessages();
-
- assertNull(mTile.getState().sideViewCustomDrawable);
- }
-
- @Test
public void testQueryCards_noCards_notUpdateSideViewDrawable() {
setUpWalletCard(/* hasCard= */ false);
@@ -398,7 +372,7 @@
mTile.handleSetListening(true);
- verify(mQuickAccessWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
+ verify(mController).queryWalletCards(mCallbackCaptor.capture());
mCallbackCaptor.getValue().onWalletCardRetrievalError(error);
mTestableLooper.processAllMessages();
@@ -422,7 +396,7 @@
mTile.handleSetListening(true);
- verify(mQuickAccessWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
+ verify(mController).queryWalletCards(mCallbackCaptor.capture());
mCallbackCaptor.getValue().onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
index f48d693..7c7d2dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
@@ -47,7 +47,7 @@
@Test
fun testApplyBlur_noViewRoot_doesntCrash() {
- blurUtils.applyBlur(null /* viewRootImple */, 10 /* radius */)
+ blurUtils.applyBlur(null /* viewRootImple */, 10 /* radius */, false /* opaque */)
}
@Test
@@ -55,7 +55,7 @@
val surfaceControl = mock(SurfaceControl::class.java)
val viewRootImpl = mock(ViewRootImpl::class.java)
`when`(viewRootImpl.surfaceControl).thenReturn(surfaceControl)
- blurUtils.applyBlur(viewRootImpl, 10 /* radius */)
+ blurUtils.applyBlur(viewRootImpl, 10 /* radius */, false /* opaque */)
}
@Test
@@ -65,8 +65,9 @@
val viewRootImpl = mock(ViewRootImpl::class.java)
`when`(viewRootImpl.surfaceControl).thenReturn(surfaceControl)
`when`(surfaceControl.isValid).thenReturn(true)
- blurUtils.applyBlur(viewRootImpl, radius)
+ blurUtils.applyBlur(viewRootImpl, radius, true /* opaque */)
verify(transaction).setBackgroundBlurRadius(eq(surfaceControl), eq(radius))
+ verify(transaction).setOpaque(eq(surfaceControl), eq(true))
verify(transaction).apply()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 58738e7..d1b846f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -27,6 +27,7 @@
import android.content.ComponentName;
import android.graphics.Rect;
+import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
import android.hardware.fingerprint.IUdfpsHbmListener;
@@ -423,13 +424,15 @@
final int userId = 10;
final String packageName = "test";
final long operationId = 1;
+ final int multiSensorConfig = BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT;
mCommandQueue.showAuthenticationDialog(promptInfo, receiver, sensorIds,
- credentialAllowed, requireConfirmation , userId, packageName, operationId);
+ credentialAllowed, requireConfirmation , userId, packageName, operationId,
+ multiSensorConfig);
waitForIdleSync();
verify(mCallbacks).showAuthenticationDialog(eq(promptInfo), eq(receiver), eq(sensorIds),
eq(credentialAllowed), eq(requireConfirmation), eq(userId), eq(packageName),
- eq(operationId));
+ eq(operationId), eq(multiSensorConfig));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index a0c3ed9..4169cdd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -30,6 +30,7 @@
import com.android.systemui.statusbar.notification.ExpandAnimationParameters
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.phone.ScrimController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.mockito.eq
import org.junit.Before
@@ -38,6 +39,7 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.any
@@ -49,6 +51,7 @@
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
+import java.util.function.Consumer
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
@@ -71,6 +74,7 @@
@Mock private lateinit var globalActionsSpring: NotificationShadeDepthController.DepthAnimation
@Mock private lateinit var listener: NotificationShadeDepthController.DepthListener
@Mock private lateinit var dozeParameters: DozeParameters
+ @Captor private lateinit var scrimVisibilityCaptor: ArgumentCaptor<Consumer<Int>>
@JvmField @Rule val mockitoRule = MockitoJUnit.rule()
private lateinit var statusBarStateListener: StatusBarStateController.StateListener
@@ -102,6 +106,8 @@
val captor = ArgumentCaptor.forClass(StatusBarStateController.StateListener::class.java)
verify(statusBarStateController).addCallback(captor.capture())
statusBarStateListener = captor.value
+ verify(notificationShadeWindowController)
+ .setScrimsVisibilityListener(scrimVisibilityCaptor.capture())
}
@Test
@@ -175,7 +181,7 @@
fun setQsPanelExpansion_appliesBlur() {
notificationShadeDepthController.qsPanelExpansion = 1f
notificationShadeDepthController.updateBlurCallback.doFrame(0)
- verify(blurUtils).applyBlur(any(), eq(maxBlur))
+ verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
}
@Test
@@ -188,7 +194,7 @@
fun updateGlobalDialogVisibility_appliesBlur_withoutHomeControls() {
`when`(globalActionsSpring.radius).thenReturn(maxBlur)
notificationShadeDepthController.updateBlurCallback.doFrame(0)
- verify(blurUtils).applyBlur(any(), eq(maxBlur))
+ verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
}
@Test
@@ -196,7 +202,7 @@
notificationShadeDepthController.showingHomeControls = true
`when`(globalActionsSpring.radius).thenReturn(maxBlur)
notificationShadeDepthController.updateBlurCallback.doFrame(0)
- verify(blurUtils).applyBlur(any(), eq(0))
+ verify(blurUtils).applyBlur(any(), eq(0), eq(false))
}
@Test
@@ -205,7 +211,14 @@
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(wallpaperManager).setWallpaperZoomOut(any(), anyFloat())
verify(listener).onWallpaperZoomOutChanged(anyFloat())
- verify(blurUtils).applyBlur(any(), anyInt())
+ verify(blurUtils).applyBlur(any(), anyInt(), eq(false))
+ }
+
+ @Test
+ fun updateBlurCallback_setsOpaque_whenScrim() {
+ scrimVisibilityCaptor.value.accept(ScrimController.OPAQUE)
+ notificationShadeDepthController.updateBlurCallback.doFrame(0)
+ verify(blurUtils).applyBlur(any(), anyInt(), eq(true))
}
@Test
@@ -213,7 +226,7 @@
`when`(shadeSpring.radius).thenReturn(maxBlur)
`when`(shadeAnimation.radius).thenReturn(maxBlur)
notificationShadeDepthController.updateBlurCallback.doFrame(0)
- verify(blurUtils).applyBlur(any(), eq(maxBlur))
+ verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
}
@Test
@@ -224,7 +237,7 @@
animProgress.linearProgress = 1f
notificationShadeDepthController.notificationLaunchAnimationParams = animProgress
notificationShadeDepthController.updateBlurCallback.doFrame(0)
- verify(blurUtils).applyBlur(any(), eq(0))
+ verify(blurUtils).applyBlur(any(), eq(0), eq(false))
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index 9b5c33d..116f807 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -511,6 +511,9 @@
override fun setNextAlarm(image: Drawable?, description: String?) {
}
+
+ override fun setMediaTarget(target: SmartspaceTarget?) {
+ }
})
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 6b4797f..ee8d120 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -20,12 +20,15 @@
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
+import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
+import static com.android.systemui.statusbar.notification.ViewGroupFadeHelper.reset;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -39,7 +42,6 @@
import android.hardware.biometrics.BiometricSourceType;
import android.os.PowerManager;
import android.os.UserManager;
-import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.DisplayMetrics;
@@ -75,13 +77,17 @@
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.doze.DozeLog;
+import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.fragments.FragmentService;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.qs.QSDetailDisplayer;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardAffordanceView;
+import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -105,6 +111,7 @@
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.wm.shell.animation.FlingAnimationUtils;
import org.junit.Before;
@@ -245,18 +252,28 @@
@Mock
private LockIconViewController mLockIconViewController;
@Mock
- private QuickAccessWalletClient mQuickAccessWalletClient;
- @Mock
private KeyguardMediaController mKeyguardMediaController;
@Mock
private PrivacyDotViewController mPrivacyDotViewController;
@Mock
private SecureSettings mSecureSettings;
+ @Mock
+ private TapAgainViewController mTapAgainViewController;
+ @Mock
+ private KeyguardIndicationController mKeyguardIndicationController;
+ @Mock
+ private FragmentService mFragmentService;
+ @Mock
+ private FragmentHostManager mFragmentHostManager;
+ @Mock
+ private QuickAccessWalletController mQuickAccessWalletController;
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
private View.AccessibilityDelegate mAccessibiltyDelegate;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
+ private List<View.OnAttachStateChangeListener> mOnAttachStateChangeListeners;
+ private FalsingManagerFake mFalsingManager = new FalsingManagerFake();
@Before
public void setup() {
@@ -297,6 +314,7 @@
mNotificationContainerParent.addView(newViewWithId(R.id.keyguard_status_view));
when(mView.findViewById(R.id.notification_container_parent))
.thenReturn(mNotificationContainerParent);
+ when(mFragmentService.getFragmentHostManager(mView)).thenReturn(mFragmentHostManager);
FlingAnimationUtils.Builder flingAnimationUtilsBuilder = new FlingAnimationUtils.Builder(
mDisplayMetrics);
@@ -317,7 +335,7 @@
mKeyguardBypassController, mHeadsUpManager,
mock(NotificationRoundnessManager.class),
mStatusBarStateController,
- new FalsingManagerFake(),
+ mFalsingManager,
mLockscreenShadeTransitionController,
new FalsingCollectorFake());
when(mKeyguardStatusViewComponentFactory.build(any()))
@@ -331,11 +349,12 @@
when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
.thenReturn(mKeyguardStatusBarViewController);
+ reset(mView);
mNotificationPanelViewController = new NotificationPanelViewController(mView,
mResources,
mLayoutInflater,
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
- new FalsingManagerFake(), new FalsingCollectorFake(),
+ mFalsingManager, new FalsingCollectorFake(),
mNotificationLockscreenUserManager, mNotificationEntryManager,
mKeyguardStateController, mStatusBarStateController, mDozeLog,
mDozeParameters, mCommandQueue, mVibratorHelper,
@@ -361,9 +380,11 @@
mAmbientState,
mLockIconViewController,
mFeatureFlags,
- mQuickAccessWalletClient,
mKeyguardMediaController,
mPrivacyDotViewController,
+ mTapAgainViewController,
+ mFragmentService,
+ mQuickAccessWalletController,
new FakeExecutor(new FakeSystemClock()),
mSecureSettings);
mNotificationPanelViewController.initDependencies(
@@ -371,6 +392,13 @@
mNotificationShelfController);
mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
mNotificationPanelViewController.setBar(mPanelBar);
+ mNotificationPanelViewController.setKeyguardIndicationController(
+ mKeyguardIndicationController);
+ ArgumentCaptor<View.OnAttachStateChangeListener> onAttachStateChangeListenerArgumentCaptor =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+ verify(mView, atLeast(1)).addOnAttachStateChangeListener(
+ onAttachStateChangeListenerArgumentCaptor.capture());
+ mOnAttachStateChangeListeners = onAttachStateChangeListenerArgumentCaptor.getAllValues();
ArgumentCaptor<View.AccessibilityDelegate> accessibilityDelegateArgumentCaptor =
ArgumentCaptor.forClass(View.AccessibilityDelegate.class);
@@ -616,6 +644,34 @@
verify(mKeyguardStateController).notifyPanelFlingEnd();
}
+ @Test
+ public void testDoubleTapRequired_Keyguard() {
+ FalsingManager.FalsingTapListener listener = getFalsingTapListener();
+ mStatusBarStateController.setState(KEYGUARD);
+
+ listener.onDoubleTapRequired();
+
+ verify(mKeyguardIndicationController).showTransientIndication(anyInt());
+ }
+
+ @Test
+ public void testDoubleTapRequired_ShadeLocked() {
+ FalsingManager.FalsingTapListener listener = getFalsingTapListener();
+ mStatusBarStateController.setState(SHADE_LOCKED);
+
+ listener.onDoubleTapRequired();
+
+ verify(mTapAgainViewController).show();
+ }
+
+ private FalsingManager.FalsingTapListener getFalsingTapListener() {
+ for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
+ listener.onViewAttachedToWindow(mView);
+ }
+ assertThat(mFalsingManager.getTapListeners().size()).isEqualTo(1);
+ return mFalsingManager.getTapListeners().get(0);
+ }
+
private View newViewWithId(int id) {
View view = new View(mContext);
view.setId(id);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index a431a78..8b0b579 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -1118,7 +1118,7 @@
public void testNotificationTransparency_inKeyguardState() {
mScrimController.transitionTo(ScrimState.KEYGUARD);
- assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0.2f, /* expansion */ 0.8f);
+ assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0.2f, /* expansion */ 0.4f);
assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0.8f, /* expansion */ 0.2f);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
new file mode 100644
index 0000000..4796cd7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone
+
+import android.graphics.Rect
+import android.test.suitebuilder.annotation.SmallTest
+import android.view.DisplayCutout
+import android.view.WindowMetrics
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.leak.RotationUtils
+import com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE
+import com.android.systemui.util.leak.RotationUtils.ROTATION_NONE
+import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE
+import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN
+import com.android.systemui.util.leak.RotationUtils.Rotation
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class StatusBarContentInsetsProviderTest : SysuiTestCase() {
+ @Mock private lateinit var dc: DisplayCutout
+ @Mock private lateinit var windowMetrics: WindowMetrics
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ }
+
+ @Test
+ fun testGetBoundingRectForPrivacyChipForRotation_noCutout() {
+ val screenBounds = Rect(0, 0, 1080, 2160)
+ val roundedCornerPadding = 20
+ val sbHeightPortrait = 100
+ val sbHeightLandscape = 60
+ val currentRotation = ROTATION_NONE
+ val chipWidth = 30
+ val dotWidth = 10
+
+ `when`(windowMetrics.bounds).thenReturn(screenBounds)
+
+ var isRtl = false
+ var targetRotation = ROTATION_NONE
+ var bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ null,
+ windowMetrics,
+ sbHeightPortrait,
+ roundedCornerPadding)
+
+ var chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl)
+ /* 1080 - 20 (rounded corner) - 30 (chip),
+ * 0 (sb top)
+ * 1080 - 20 (rounded corner) + 10 ( dot),
+ * 100 (sb height portrait)
+ */
+ var expected = Rect(1030, 0, 1070, 100)
+ assertRects(expected, chipBounds, currentRotation, targetRotation)
+ isRtl = true
+ chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl)
+ /* 0 + 20 (rounded corner) - 10 (dot),
+ * 0 (sb top)
+ * 0 + 20 (rounded corner) + 30 (chip),
+ * 100 (sb height portrait)
+ */
+ expected = Rect(10, 0, 50, 100)
+ assertRects(expected, chipBounds, currentRotation, targetRotation)
+
+ isRtl = false
+ targetRotation = ROTATION_LANDSCAPE
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightLandscape,
+ roundedCornerPadding)
+
+ chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl)
+ /* 2160 - 20 (rounded corner) - 30 (chip),
+ * 0 (sb top)
+ * 2160 - 20 (rounded corner) + 10 ( dot),
+ * 60 (sb height landscape)
+ */
+ expected = Rect(2110, 0, 2150, 60)
+ assertRects(expected, chipBounds, currentRotation, targetRotation)
+ isRtl = true
+ chipBounds = getPrivacyChipBoundingRectForInsets(bounds, dotWidth, chipWidth, isRtl)
+ /* 0 + 20 (rounded corner) - 10 (dot),
+ * 0 (sb top)
+ * 0 + 20 (rounded corner) + 30 (chip),
+ * 60 (sb height landscape)
+ */
+ expected = Rect(10, 0, 50, 60)
+ assertRects(expected, chipBounds, currentRotation, targetRotation)
+ }
+
+ @Test
+ fun testCalculateInsetsForRotationWithRotatedResources_topLeftCutout() {
+ // GIVEN a device in portrait mode with width < height and a display cutout in the top-left
+ val screenBounds = Rect(0, 0, 1080, 2160)
+ val dcBounds = Rect(0, 0, 100, 100)
+ val roundedCornerPadding = 20
+ val sbHeightPortrait = 100
+ val sbHeightLandscape = 60
+ val currentRotation = ROTATION_NONE
+
+ `when`(windowMetrics.bounds).thenReturn(screenBounds)
+ `when`(dc.boundingRects).thenReturn(listOf(dcBounds))
+
+ // THEN rotations which share a short side should use the greater value between rounded
+ // corner padding and the display cutout's size
+ var targetRotation = ROTATION_NONE
+ var expectedBounds = Rect(dcBounds.right,
+ 0,
+ screenBounds.right - roundedCornerPadding,
+ sbHeightPortrait)
+
+ var bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightPortrait,
+ roundedCornerPadding)
+
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ targetRotation = ROTATION_LANDSCAPE
+ expectedBounds = Rect(dcBounds.height(),
+ 0,
+ screenBounds.height() - roundedCornerPadding,
+ sbHeightLandscape)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightLandscape,
+ roundedCornerPadding)
+
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ // THEN the side that does NOT share a short side with the display cutout ignores the
+ // display cutout bounds
+ targetRotation = ROTATION_UPSIDE_DOWN
+ expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.width() - roundedCornerPadding,
+ sbHeightPortrait)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightPortrait,
+ roundedCornerPadding)
+
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ // Phone in portrait, seascape (rot_270) bounds
+ targetRotation = ROTATION_SEASCAPE
+ expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.height() - dcBounds.height(),
+ sbHeightLandscape)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightLandscape,
+ roundedCornerPadding)
+
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+ }
+
+ @Test
+ fun testCalculateInsetsForRotationWithRotatedResources_nonCornerCutout() {
+ // GIVEN phone in portrait mode, where width < height and the cutout is not in the corner
+ // the assumption here is that if the cutout does NOT touch the corner then we have room to
+ // layout the status bar in the given space.
+
+ val screenBounds = Rect(0, 0, 1080, 2160)
+ // cutout centered at the top
+ val dcBounds = Rect(490, 0, 590, 100)
+ val roundedCornerPadding = 20
+ val sbHeightPortrait = 100
+ val sbHeightLandscape = 60
+ val currentRotation = ROTATION_NONE
+
+ `when`(windowMetrics.bounds).thenReturn(screenBounds)
+ `when`(dc.boundingRects).thenReturn(listOf(dcBounds))
+
+ // THEN only the landscape/seascape rotations should avoid the cutout area because of the
+ // potential letterboxing
+ var targetRotation = ROTATION_NONE
+ var expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.right - roundedCornerPadding,
+ sbHeightPortrait)
+
+ var bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightPortrait,
+ roundedCornerPadding)
+
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ targetRotation = ROTATION_LANDSCAPE
+ expectedBounds = Rect(dcBounds.height(),
+ 0,
+ screenBounds.height() - roundedCornerPadding,
+ sbHeightLandscape)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightLandscape,
+ roundedCornerPadding)
+
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ targetRotation = ROTATION_UPSIDE_DOWN
+ expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.right - roundedCornerPadding,
+ sbHeightPortrait)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightPortrait,
+ roundedCornerPadding)
+
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ targetRotation = ROTATION_SEASCAPE
+ expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.height() - dcBounds.height(),
+ sbHeightLandscape)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ dc,
+ windowMetrics,
+ sbHeightLandscape,
+ roundedCornerPadding)
+
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+ }
+
+ @Test
+ fun testCalculateInsetsForRotationWithRotatedResources_noCutout() {
+ // GIVEN device in portrait mode, where width < height and no cutout
+ val currentRotation = ROTATION_NONE
+ val screenBounds = Rect(0, 0, 1080, 2160)
+ val roundedCornerPadding = 20
+ val sbHeightPortrait = 100
+ val sbHeightLandscape = 60
+
+ `when`(windowMetrics.bounds).thenReturn(screenBounds)
+
+ // THEN content insets should only use rounded corner padding
+ var targetRotation = ROTATION_NONE
+ var expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.right - roundedCornerPadding,
+ sbHeightPortrait)
+
+ var bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ null, /* no cutout */
+ windowMetrics,
+ sbHeightPortrait,
+ roundedCornerPadding)
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ targetRotation = ROTATION_LANDSCAPE
+ expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.height() - roundedCornerPadding,
+ sbHeightLandscape)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ null, /* no cutout */
+ windowMetrics,
+ sbHeightLandscape,
+ roundedCornerPadding)
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ targetRotation = ROTATION_UPSIDE_DOWN
+ expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.width() - roundedCornerPadding,
+ sbHeightPortrait)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ null, /* no cutout */
+ windowMetrics,
+ sbHeightPortrait,
+ roundedCornerPadding)
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+
+ targetRotation = ROTATION_LANDSCAPE
+ expectedBounds = Rect(roundedCornerPadding,
+ 0,
+ screenBounds.height() - roundedCornerPadding,
+ sbHeightLandscape)
+
+ bounds = calculateInsetsForRotationWithRotatedResources(
+ currentRotation,
+ targetRotation,
+ null, /* no cutout */
+ windowMetrics,
+ sbHeightLandscape,
+ roundedCornerPadding)
+ assertRects(expectedBounds, bounds, currentRotation, targetRotation)
+ }
+
+ private fun assertRects(
+ expected: Rect,
+ actual: Rect,
+ @Rotation currentRotation: Int,
+ @Rotation targetRotation: Int
+ ) {
+ assertTrue(
+ "Rects must match. currentRotation=${RotationUtils.toString(currentRotation)}" +
+ " targetRotation=${RotationUtils.toString(targetRotation)}" +
+ " expected=$expected actual=$actual",
+ expected.equals(actual))
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index be86af5..407afbe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -269,7 +269,7 @@
verify(mShadeController, atLeastOnce()).collapsePanel();
verify(mActivityLaunchAnimator).startPendingIntentWithAnimation(any(),
- eq(false) /* animate */, any());
+ eq(false) /* animate */, any(), any());
verify(mAssistManager).hideAssist();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
index 53a2efc..4b87ec8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
@@ -32,6 +32,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import org.junit.Before;
import org.junit.Test;
@@ -49,12 +50,14 @@
@Mock
private LockPatternUtils mLockPatternUtils;
private KeyguardStateController mKeyguardStateController;
+ @Mock
+ private SmartspaceTransitionController mSmartSpaceTransitionController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mKeyguardStateController = new KeyguardStateControllerImpl(mContext,
- mKeyguardUpdateMonitor, mLockPatternUtils);
+ mKeyguardUpdateMonitor, mLockPatternUtils, mSmartSpaceTransitionController);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 7149987..cfaffd0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -258,6 +258,7 @@
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK)).thenReturn(20);
+ when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_SYSTEM)).thenReturn(21);
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
@@ -302,6 +303,63 @@
}
@Test
+ public void onWallpaperColorsChanged_ResetThemeWhenFromLatestWallpaper() {
+ // Should ask for a new theme when the colors of the last applied wallpaper change
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
+ Color.valueOf(Color.BLUE), null);
+
+ String jsonString =
+ "{\"android.theme.customization.system_palette\":\"override.package.name\","
+ + "\"android.theme.customization.color_source\":\"home_wallpaper\","
+ + "\"android.theme.customization.color_index\":\"2\"}";
+
+ when(mSecureSettings.getStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
+ .thenReturn(jsonString);
+ when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK)).thenReturn(1);
+ // SYSTEM wallpaper is the last applied one
+ when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_SYSTEM)).thenReturn(2);
+
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+
+ ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class);
+ verify(mSecureSettings).putString(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture());
+
+ verify(mThemeOverlayApplier)
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ }
+
+ @Test
+ public void onWallpaperColorsChanged_keepThemeIfNotLatestWallpaper() {
+ // Shouldn't ask for a new theme when the colors of the wallpaper that is not the last
+ // applied one change
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
+ Color.valueOf(Color.BLUE), null);
+
+ String jsonString =
+ "{\"android.theme.customization.system_palette\":\"override.package.name\","
+ + "\"android.theme.customization.color_source\":\"home_wallpaper\","
+ + "\"android.theme.customization.color_index\":\"2\"}";
+
+ when(mSecureSettings.getStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
+ .thenReturn(jsonString);
+ when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK)).thenReturn(1);
+ // SYSTEM wallpaper is the last applied one
+ when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_SYSTEM)).thenReturn(2);
+
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_LOCK);
+
+ verify(mSecureSettings, never()).putString(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), any());
+
+
+ verify(mThemeOverlayApplier, never())
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ }
+
+ @Test
public void onProfileAdded_setsTheme() {
mBroadcastReceiver.getValue().onReceive(null,
new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
index 365c62c..9b177e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
@@ -17,7 +17,6 @@
package com.android.systemui.toast;
import static android.view.accessibility.AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
-import static android.widget.ToastPresenter.TEXT_TOAST_LAYOUT;
import static com.google.common.truth.Truth.assertThat;
@@ -31,13 +30,20 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.Application;
import android.app.INotificationManager;
import android.app.ITransientNotificationCallback;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.os.Binder;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -47,12 +53,11 @@
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
-import android.widget.ToastPresenter;
import androidx.test.filters.SmallTest;
-import com.android.internal.R;
import com.android.internal.util.IntPair;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.shared.plugins.PluginManager;
@@ -70,6 +75,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
public class ToastUITest extends SysuiTestCase {
private static final int ANDROID_UID = 1000;
private static final int SYSTEMUI_UID = 10140;
@@ -85,12 +91,14 @@
private static final Binder WINDOW_TOKEN_2 = new Binder();
private static final String TEXT = "Hello World";
- private static final int MESSAGE_RES_ID = R.id.message;
+ private static final int MESSAGE_RES_ID = R.id.text;
private Context mContextSpy;
private ToastUI mToastUI;
- @Mock private LayoutInflater mLayoutInflater;
+ private View mToastView;
+ @Mock private Application mApplication;
@Mock private CommandQueue mCommandQueue;
+ @Mock private LayoutInflater mLayoutInflater;
@Mock private WindowManager mWindowManager;
@Mock private INotificationManager mNotificationManager;
@Mock private IAccessibilityManager mAccessibilityManager;
@@ -98,6 +106,7 @@
@Mock private DumpManager mDumpManager;
@Mock private ToastLogger mToastLogger;
@Mock private FeatureFlags mFeatureFlags;
+ @Mock private PackageManager mPackageManager;
@Mock private ITransientNotificationCallback mCallback;
@Captor private ArgumentCaptor<View> mViewCaptor;
@@ -106,29 +115,33 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- when(mLayoutInflater.inflate(eq(TEXT_TOAST_LAYOUT), any())).thenReturn(
- ToastPresenter.getTextToastView(mContext, TEXT));
- when(mFeatureFlags.isToastStyleEnabled()).thenReturn(false);
-
+ mToastView = LayoutInflater.from(mContext).inflate(R.layout.text_toast, null);
+ when(mLayoutInflater.inflate(anyInt(), eq(null))).thenReturn(mToastView);
mContext.addMockSystemService(WindowManager.class, mWindowManager);
mContextSpy = spy(mContext);
+ when(mContextSpy.getPackageManager()).thenReturn(mPackageManager);
doReturn(mContextSpy).when(mContextSpy).createContextAsUser(any(), anyInt());
-
- doReturn(mContextSpy).when(mContextSpy).createContextAsUser(any(), anyInt());
- mToastUI = new ToastUI(mContextSpy, mCommandQueue, mNotificationManager,
- mAccessibilityManager, new ToastFactory(mLayoutInflater, mPluginManager,
- mDumpManager, mFeatureFlags), mToastLogger);
+ mToastUI = new ToastUI(
+ mContextSpy,
+ mCommandQueue,
+ mNotificationManager,
+ mAccessibilityManager,
+ new ToastFactory(
+ mLayoutInflater,
+ mPluginManager,
+ mDumpManager),
+ mToastLogger);
}
@Test
- public void testStart_addToastUIAsCallbackToCommandQueue() throws Exception {
+ public void testStart_addToastUIAsCallbackToCommandQueue() {
mToastUI.start();
verify(mCommandQueue).addCallback(mToastUI);
}
@Test
- public void testShowToast_addsCorrectViewToWindowManager() throws Exception {
+ public void testShowToast_addsCorrectViewToWindowManager() {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
null);
@@ -138,7 +151,7 @@
}
@Test
- public void testShowToast_addsViewWithCorrectLayoutParamsToWindowManager() throws Exception {
+ public void testShowToast_addsViewWithCorrectLayoutParamsToWindowManager() {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
null);
@@ -217,9 +230,14 @@
public void testHideToast_removesView() throws Exception {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
- View view = verifyWmAddViewAndAttachToParent();
+ final SystemUIToast toast = mToastUI.mToast;
+ View view = verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
+ if (toast.getOutAnimation() != null) {
+ assertThat(toast.getOutAnimation().isRunning()).isTrue();
+ toast.getOutAnimation().cancel(); // if applicable, try to finish anim early
+ }
verify(mWindowManager).removeViewImmediate(view);
}
@@ -228,51 +246,81 @@
public void testHideToast_finishesToken() throws Exception {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
+ final SystemUIToast toast = mToastUI.mToast;
+ verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
+ if (toast.getOutAnimation() != null) {
+ assertThat(toast.getOutAnimation().isRunning()).isTrue();
+ toast.getOutAnimation().cancel(); // if applicable, try to finish anim early
+ }
verify(mNotificationManager).finishToken(PACKAGE_NAME_1, TOKEN_1);
}
@Test
- public void testHideToast_callsCallback() throws Exception {
+ public void testHideToast_callsCallback() throws RemoteException {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
+ final SystemUIToast toast = mToastUI.mToast;
+ verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
+ if (toast.getOutAnimation() != null) {
+ assertThat(toast.getOutAnimation().isRunning()).isTrue();
+ toast.getOutAnimation().cancel();
+ }
verify(mCallback).onToastHidden();
}
@Test
- public void testHideToast_whenNotCurrentToastToken_doesNotHideToast() throws Exception {
+ public void testHideToast_whenNotCurrentToastToken_doesNotHideToast() throws RemoteException {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
+ final SystemUIToast toast = mToastUI.mToast;
+ verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_2);
+ if (toast.getOutAnimation() != null) {
+ assertThat(toast.getOutAnimation().isRunning()).isFalse();
+ }
+
verify(mCallback, never()).onToastHidden();
}
@Test
- public void testHideToast_whenNotCurrentToastPackage_doesNotHideToast() throws Exception {
+ public void testHideToast_whenNotCurrentToastPackage_doesNotHideToast() throws RemoteException {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
+ final SystemUIToast toast = mToastUI.mToast;
+ verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_2, TOKEN_1);
+ if (toast.getOutAnimation() != null) {
+ assertThat(toast.getOutAnimation().isRunning()).isFalse();
+ }
+
verify(mCallback, never()).onToastHidden();
}
@Test
- public void testShowToast_afterShowToast_hidesCurrentToast() throws Exception {
+ public void testShowToast_afterShowToast_hidesCurrentToast() throws RemoteException {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
- View view = verifyWmAddViewAndAttachToParent();
+ final SystemUIToast toast = mToastUI.mToast;
+ View view = verifyWmAddViewAndAttachToParent();
mToastUI.showToast(UID_2, PACKAGE_NAME_2, TOKEN_2, TEXT, WINDOW_TOKEN_2, Toast.LENGTH_LONG,
null);
+ if (toast.getOutAnimation() != null) {
+ assertThat(toast.getOutAnimation().isRunning()).isTrue();
+ toast.getOutAnimation().cancel(); // end early if applicable
+ }
+
verify(mWindowManager).removeViewImmediate(view);
verify(mNotificationManager).finishToken(PACKAGE_NAME_1, TOKEN_1);
verify(mCallback).onToastHidden();
@@ -287,9 +335,48 @@
}
@Test
+ public void testShowToast_targetsPreS_unlimitedLines_noAppIcon()
+ throws PackageManager.NameNotFoundException {
+ // GIVEN the application targets R
+ ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.targetSdkVersion = Build.VERSION_CODES.R;
+ when(mPackageManager.getApplicationInfoAsUser(PACKAGE_NAME_1, 0,
+ UserHandle.getUserHandleForUid(UID_1).getIdentifier())).thenReturn(applicationInfo);
+
+ // WHEN the package posts a toast
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ mCallback);
+
+ // THEN the view can have unlimited lines
+ assertThat(((TextView) mToastUI.mToast.getView()
+ .findViewById(com.android.systemui.R.id.text))
+ .getMaxLines()).isEqualTo(Integer.MAX_VALUE);
+ }
+
+ @Test
+ public void testShowToast_targetsS_twoLineLimit_noAppIcon()
+ throws PackageManager.NameNotFoundException {
+ // GIVEN the application targets S
+ ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.targetSdkVersion = Build.VERSION_CODES.S;
+ when(mPackageManager.getApplicationInfoAsUser(PACKAGE_NAME_1, 0,
+ UserHandle.getUserHandleForUid(UID_1).getIdentifier())).thenReturn(applicationInfo);
+
+ // WHEN the package posts a toast
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ mCallback);
+
+ // THEN the view is limited to 2 lines
+ assertThat(((TextView) mToastUI.mToast.getView()
+ .findViewById(com.android.systemui.R.id.text))
+ .getMaxLines()).isEqualTo(2);
+ }
+
+ @Test
public void testHideToast_logs() {
mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
+ verifyWmAddViewAndAttachToParent();
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
verify(mToastLogger).logOnHideToast(PACKAGE_NAME_1, TOKEN_1.toString());
}
@@ -298,6 +385,7 @@
public void testHideToast_error_noLog() {
// no toast was shown, so this hide is invalid
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
+ assertThat(mToastUI.mToast).isNull();
verify(mToastLogger, never()).logOnHideToast(PACKAGE_NAME_1, TOKEN_1.toString());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeThreadFactory.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeThreadFactory.java
index 570e1d8..301a157 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeThreadFactory.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeThreadFactory.java
@@ -27,6 +27,7 @@
public class FakeThreadFactory implements ThreadFactory {
private final FakeExecutor mFakeExecutor;
private Handler mHandler;
+ private Looper mLooper;
public FakeThreadFactory(FakeExecutor fakeExecutor) {
mFakeExecutor = fakeExecutor;
@@ -36,8 +37,17 @@
mHandler = handler;
}
+ public void setLooper(Looper looper) {
+ mLooper = looper;
+ }
+
@Override
- public Handler builderHandlerOnNewThread(String threadName) {
+ public Looper buildLooperOnNewThread(String threadName) {
+ return mLooper;
+ }
+
+ @Override
+ public Handler buildHandlerOnNewThread(String threadName) {
return mHandler;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
index 5fb779a..1aebf1c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardStateController.java
@@ -127,4 +127,9 @@
public void notifyPanelFlingEnd() {
}
+
+ @Override
+ public boolean canPerformSmartSpaceTransition() {
+ return false;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
index 6166cd7..5c0efd3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -23,29 +23,37 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.media.AudioManager;
+import android.media.IAudioService;
import android.media.session.MediaSession;
import android.os.Handler;
import android.os.Process;
+import android.os.Vibrator;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.accessibility.AccessibilityManager;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.RingerModeLiveData;
import com.android.systemui.util.RingerModeTracker;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.concurrency.FakeThreadFactory;
+import com.android.systemui.util.concurrency.ThreadFactory;
+import com.android.systemui.util.time.FakeSystemClock;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -58,7 +66,6 @@
TestableVolumeDialogControllerImpl mVolumeController;
VolumeDialogControllerImpl.C mCallback;
- StatusBar mStatusBar;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
@Mock
@@ -67,6 +74,23 @@
private RingerModeLiveData mRingerModeLiveData;
@Mock
private RingerModeLiveData mRingerModeInternalLiveData;
+ private final FakeThreadFactory mThreadFactory = new FakeThreadFactory(
+ new FakeExecutor(new FakeSystemClock()));
+ @Mock
+ private AudioManager mAudioManager;
+ @Mock
+ private NotificationManager mNotificationManager;
+ @Mock
+ private Vibrator mVibrator;
+ @Mock
+ private IAudioService mIAudioService;
+ @Mock
+ private AccessibilityManager mAccessibilityManager;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private WakefulnessLifecycle mWakefullnessLifcycle;
+
@Before
public void setup() throws Exception {
@@ -77,19 +101,15 @@
// Initial non-set value
when(mRingerModeLiveData.getValue()).thenReturn(-1);
when(mRingerModeInternalLiveData.getValue()).thenReturn(-1);
-
mCallback = mock(VolumeDialogControllerImpl.C.class);
- mStatusBar = mock(StatusBar.class);
- mVolumeController = new TestableVolumeDialogControllerImpl(mContext, mCallback, mStatusBar,
- mBroadcastDispatcher, mRingerModeTracker);
+ mThreadFactory.setLooper(TestableLooper.get(this).getLooper());
+ mVolumeController = new TestableVolumeDialogControllerImpl(mContext,
+ mBroadcastDispatcher, mRingerModeTracker, mThreadFactory, mAudioManager,
+ mNotificationManager, Optional.of(mVibrator), mIAudioService, mAccessibilityManager,
+ mPackageManager, mWakefullnessLifcycle, mCallback);
mVolumeController.setEnableDialogs(true, true);
}
- @After
- public void tearDown() {
- mVolumeController.destroy();
- }
-
@Test
public void testRegisteredWithDispatcher() {
verify(mBroadcastDispatcher).registerReceiverWithHandler(any(BroadcastReceiver.class),
@@ -99,45 +119,36 @@
@Test
public void testVolumeChangeW_deviceNotInteractiveAOD() {
- when(mStatusBar.isDeviceInteractive()).thenReturn(false);
- when(mStatusBar.getWakefulnessState()).thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
+ mVolumeController.setDeviceInteractive(false);
+ when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
+ WakefulnessLifecycle.WAKEFULNESS_AWAKE);
mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
verify(mCallback, never()).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
}
@Test
public void testVolumeChangeW_deviceInteractive() {
- when(mStatusBar.isDeviceInteractive()).thenReturn(true);
- when(mStatusBar.getWakefulnessState()).thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
+ mVolumeController.setDeviceInteractive(true);
+ when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
+ WakefulnessLifecycle.WAKEFULNESS_AWAKE);
mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
verify(mCallback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
}
@Test
public void testVolumeChangeW_deviceInteractive_StartedSleeping() {
- when(mStatusBar.isDeviceInteractive()).thenReturn(true);
- when(mStatusBar.getWakefulnessState()).thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
+ mVolumeController.setDeviceInteractive(true);
+ when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
+ WakefulnessLifecycle.WAKEFULNESS_AWAKE);
mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
- when(mStatusBar.isDeviceInteractive()).thenReturn(false);
- when(mStatusBar.getWakefulnessState()).thenReturn(
+ mVolumeController.setDeviceInteractive(false);
+ when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP);
mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
verify(mCallback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
}
@Test
- public void testVolumeChangeW_nullStatusBar() {
- VolumeDialogControllerImpl.C callback = mock(VolumeDialogControllerImpl.C.class);
- TestableVolumeDialogControllerImpl
- nullStatusBarTestableDialog =
- new TestableVolumeDialogControllerImpl(
- mContext, callback, null, mBroadcastDispatcher, mRingerModeTracker);
- nullStatusBarTestableDialog.setEnableDialogs(true, true);
- nullStatusBarTestableDialog.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
- verify(callback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
- }
-
- @Test
public void testOnRemoteVolumeChanged_newStream_noNullPointer() {
MediaSession.Token token = new MediaSession.Token(Process.myUid(), null);
mVolumeController.mMediaSessionsCallbacksW.onRemoteVolumeChanged(token, 0);
@@ -155,22 +166,51 @@
verify(mRingerModeInternalLiveData).observeForever(any());
}
- @Test
- public void testRingerModeOnDestroy_observersRemoved() {
- mVolumeController.destroy();
-
- verify(mRingerModeLiveData).removeObserver(any());
- verify(mRingerModeInternalLiveData).removeObserver(any());
- }
-
static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl {
- TestableVolumeDialogControllerImpl(Context context, C callback, StatusBar s,
- BroadcastDispatcher broadcastDispatcher, RingerModeTracker ringerModeTracker) {
- super(
- context, broadcastDispatcher,
- s == null ? Optional.empty() : Optional.of(() -> s), ringerModeTracker);
+ private final WakefulnessLifecycle.Observer mWakefullessLifecycleObserver;
+
+ TestableVolumeDialogControllerImpl(
+ Context context,
+ BroadcastDispatcher broadcastDispatcher,
+ RingerModeTracker ringerModeTracker,
+ ThreadFactory theadFactory,
+ AudioManager audioManager,
+ NotificationManager notificationManager,
+ Optional<Vibrator> optionalVibrator,
+ IAudioService iAudioService,
+ AccessibilityManager accessibilityManager,
+ PackageManager packageManager,
+ WakefulnessLifecycle wakefulnessLifecycle,
+ C callback) {
+ super(context, broadcastDispatcher, ringerModeTracker, theadFactory, audioManager,
+ notificationManager, optionalVibrator, iAudioService, accessibilityManager,
+ packageManager, wakefulnessLifecycle);
mCallbacks = callback;
+
+ ArgumentCaptor<WakefulnessLifecycle.Observer> observerCaptor =
+ ArgumentCaptor.forClass(WakefulnessLifecycle.Observer.class);
+ verify(wakefulnessLifecycle).addObserver(observerCaptor.capture());
+ mWakefullessLifecycleObserver = observerCaptor.getValue();
+ }
+
+ public void setDeviceInteractive(boolean interactive) {
+ if (interactive) {
+ mWakefullessLifecycleObserver.onStartedWakingUp();
+ } else {
+ mWakefullessLifecycleObserver.onFinishedGoingToSleep();
+ }
}
}
+// static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl {
+// TestableVolumeDialogControllerImpl(Context context, C callback,
+// BroadcastDispatcher broadcastDispatcher, RingerModeTracker ringerModeTracker,
+// ThreadFactory threadFactory) {
+// super(
+// context, broadcastDispatcher,
+// s == null ? Optional.empty() : Optional.of(() -> s), ringerModeTracker);
+// mCallbacks = callback;
+// }
+// }
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
new file mode 100644
index 0000000..33666bc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wallet.controller;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.service.quickaccesswallet.GetWalletCardsRequest;
+import android.service.quickaccesswallet.QuickAccessWalletClient;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.settings.SecureSettings;
+
+import com.google.common.util.concurrent.MoreExecutors;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class QuickAccessWalletControllerTest extends SysuiTestCase {
+
+ @Mock
+ private QuickAccessWalletClient mQuickAccessWalletClient;
+ @Mock
+ private SecureSettings mSecureSettings;
+ @Mock
+ private QuickAccessWalletClient.OnWalletCardsRetrievedCallback mCardsRetriever;
+ @Captor
+ private ArgumentCaptor<GetWalletCardsRequest> mRequestCaptor;
+
+ private QuickAccessWalletController mController;
+ private TestableLooper mTestableLooper;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mTestableLooper = TestableLooper.get(this);
+ when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(true);
+ when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(true);
+ when(mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked()).thenReturn(true);
+
+ mController = new QuickAccessWalletController(
+ mContext,
+ MoreExecutors.directExecutor(),
+ mSecureSettings,
+ mQuickAccessWalletClient);
+ }
+
+ @Test
+ public void walletEnabled() {
+ mController.updateWalletPreference();
+
+ assertTrue(mController.isWalletEnabled());
+ }
+
+ @Test
+ public void walletServiceUnavailable_walletNotEnabled() {
+ when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
+
+ mController.updateWalletPreference();
+
+ assertFalse(mController.isWalletEnabled());
+ }
+
+ @Test
+ public void walletFeatureUnavailable_walletNotEnabled() {
+ when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(false);
+
+ mController.updateWalletPreference();
+
+ assertFalse(mController.isWalletEnabled());
+ }
+
+ @Test
+ public void walletFeatureWhenLockedUnavailable_walletNotEnabled() {
+ when(mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked()).thenReturn(false);
+
+ mController.updateWalletPreference();
+
+ assertFalse(mController.isWalletEnabled());
+ }
+
+ @Test
+ public void getWalletClient_NoRecreation_sameClient() {
+ assertSame(mQuickAccessWalletClient, mController.getWalletClient());
+ }
+
+ @Test
+ public void getWalletClient_reCreateClient_notSameClient() {
+ mController.reCreateWalletClient();
+
+ assertNotSame(mQuickAccessWalletClient, mController.getWalletClient());
+ }
+
+ @Test
+ public void queryWalletCards_walletNotEnabled_notQuery() {
+ when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
+
+ mController.queryWalletCards(mCardsRetriever);
+
+ verify(mQuickAccessWalletClient, never()).getWalletCards(any(), any(), any());
+ }
+
+ @Test
+ public void queryWalletCards_walletEnabled_queryCards() {
+ mController.updateWalletPreference();
+ mController.queryWalletCards(mCardsRetriever);
+
+ verify(mQuickAccessWalletClient)
+ .getWalletCards(
+ eq(MoreExecutors.directExecutor()),
+ mRequestCaptor.capture(),
+ eq(mCardsRetriever));
+
+ GetWalletCardsRequest request = mRequestCaptor.getValue();
+ assertEquals(1, mRequestCaptor.getValue().getMaxCards());
+ assertEquals(
+ mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_width),
+ request.getCardWidthPx());
+ assertEquals(
+ mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_height),
+ request.getCardHeightPx());
+ }
+}
diff --git a/packages/VpnDialogs/res/values-as/strings.xml b/packages/VpnDialogs/res/values-as/strings.xml
index d469179..4669a69 100644
--- a/packages/VpnDialogs/res/values-as/strings.xml
+++ b/packages/VpnDialogs/res/values-as/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="3183836924226407828">"সংযোগৰ অনুৰোধ"</string>
<string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g>এ নেটৱৰ্ক ট্ৰেফিক নিৰীক্ষণ কৰিবলৈ এটা ভিপিএন সংযোগ ছেট আপ কৰিবলৈ বিচাৰিছে৷ আপুনি কেৱল উৎসটোক বিশ্বাস কৰিলেহে অনুৰোধ স্বীকাৰ কৰিব৷ ভিপিএন সক্ৰিয় থকাৰ সময়ত আপোনাৰ স্ক্ৰীণৰ ওপৰত <br /> <br /> <img src=vpn_icon /> দৃশ্যমান হয়৷"</string>
- <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g>এ এটা ভিপিএন সংযোগ ছেট আপ কৰিবলৈ বিচাৰে, যিটোৱে ইয়াক নেটৱৰ্ক ট্ৰেফিক নিৰীক্ষণ কৰিবলৈ দিয়ে। আপুনি উৎসটোক বিশ্বাস কৰিলেহে গ্ৰহণ কৰক। ভিপিএনটো সক্ৰিয় হৈ থকাৰ সময়ত আপোনাৰ স্ক্ৰীনত<br /> <br /> <img src=vpn_icon /> প্ৰদৰ্শিত হয়।"</string>
+ <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g>এ এটা ভিপিএন সংযোগ ছেট আপ কৰিব বিচাৰে, যিটোৱে ইয়াক নেটৱৰ্ক ট্ৰেফিক নিৰীক্ষণ কৰিবলৈ দিয়ে। আপুনি উৎসটোক বিশ্বাস কৰিলেহে গ্ৰহণ কৰক। ভিপিএনটো সক্ৰিয় হৈ থকাৰ সময়ত আপোনাৰ স্ক্ৰীনত<br /> <br /> <img src=vpn_icon /> প্ৰদৰ্শিত হয়।"</string>
<string name="legacy_title" msgid="192936250066580964">"ভিপিএন সংযোগ হৈ আছে"</string>
<string name="session" msgid="6470628549473641030">"ছেশ্বন:"</string>
<string name="duration" msgid="3584782459928719435">"সময়সীমা:"</string>
diff --git a/packages/VpnDialogs/res/values-bn/strings.xml b/packages/VpnDialogs/res/values-bn/strings.xml
index 041e46c..352b786 100644
--- a/packages/VpnDialogs/res/values-bn/strings.xml
+++ b/packages/VpnDialogs/res/values-bn/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="3183836924226407828">"সংযোগের অনুরোধ"</string>
<string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> এমন একটি VPN সংযোগ সেট-আপ করতে চাচ্ছে যেটি দিয়ে এটি নেটওয়ার্ক ট্রাফিক নিরীক্ষণ করতে পারবে। আপনি যদি উৎসটিকে বিশ্বাস করেন, তাহলেই কেবল এতে সম্মতি দিন। VPN সক্রিয় থাকলে আপনার স্ক্রীনের উপরে <br /> <br /> <img src=vpn_icon /> দেখা যাবে।"</string>
- <!-- no translation found for warning (5188957997628124947) -->
- <skip />
+ <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> এমন একটি VPN সংযোগ সেট আপ করতে চাইছে যেটি দিয়ে এটি নেটওয়ার্ক ট্রাফিক নিরীক্ষণ করতে পারবে। আপনি সোর্সটি বিশ্বাস করলে একমাত্র তখনই অ্যাক্সেপ্ট করুন। PN অ্যাক্টিভ থাকলে <br /> <br /> <img src=vpn_icon /> আপনার স্ক্রিনে দেখা যায়।"</string>
<string name="legacy_title" msgid="192936250066580964">"VPN সংযুক্ত হয়েছে"</string>
<string name="session" msgid="6470628549473641030">"অধিবেশন:"</string>
<string name="duration" msgid="3584782459928719435">"সময়কাল:"</string>
diff --git a/packages/VpnDialogs/res/values-gu/strings.xml b/packages/VpnDialogs/res/values-gu/strings.xml
index fd6e116..b5a8831 100644
--- a/packages/VpnDialogs/res/values-gu/strings.xml
+++ b/packages/VpnDialogs/res/values-gu/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="3183836924226407828">"કનેક્શન વિનંતી"</string>
<string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> VPN કનેક્શન સેટ કરવા માગે છે જે તેને નેટવર્ક ટ્રાફિક મૉનિટર કરવાની મંજૂરી આપે છે. જો તમને સ્રોત પર વિશ્વાસ હોય તો જ સ્વીકારો. <br /> <br /> <img src=vpn_icon /> તમારી સ્ક્રીનની ટોચ પર ત્યારે દેખાય છે જ્યારે VPN સક્રિય હોય છે."</string>
- <!-- no translation found for warning (5188957997628124947) -->
- <skip />
+ <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> એક એવું VPN કનેક્શન સેટ કરવા માગે છે કે જે તેને નેટવર્ક ટ્રાફિકનું નિરીક્ષણ કરવાની મંજૂરી આપતું હોય. જો તમને સૉર્સ પર વિશ્વાસ હોય તો જ સ્વીકારો. <br /> <br /> <img src=vpn_icon /> તમારી સ્ક્રીન પર ત્યારે દેખાય છે, જ્યારે VPN સક્રિય હોય છે."</string>
<string name="legacy_title" msgid="192936250066580964">"VPN કનેક્ટ કરેલું છે"</string>
<string name="session" msgid="6470628549473641030">"સત્ર:"</string>
<string name="duration" msgid="3584782459928719435">"અવધિ:"</string>
diff --git a/packages/VpnDialogs/res/values-hi/strings.xml b/packages/VpnDialogs/res/values-hi/strings.xml
index 6145949a..c9c65d5 100644
--- a/packages/VpnDialogs/res/values-hi/strings.xml
+++ b/packages/VpnDialogs/res/values-hi/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="3183836924226407828">"कनेक्शन अनुरोध"</string>
<string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> वीपीएन कनेक्शन सेट अप करना चाहता है, जिससे वह नेटवर्क ट्रैफ़िक पर नज़र रख पाएगा. इसकी मंज़ूरी तभी दें जब आपको इस पर भरोसा हो. वीपीएन चालू होने पर <br /> <br /> <img src=vpn_icon /> आपकी स्क्रीन के सबसे ऊपर दिखाई देता है."</string>
- <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> को वीपीएन कनेक्शन सेट अप करने की अनुमति चाहिए. इससे वह नेटवर्क ट्रैफ़िक पर नज़र रख पाएगा. अनुमति तब दें, जब आपको स्रोत पर भरोसा हो. वीपीएन चालू होने पर, आपकी स्क्रीन पर <br /> <br /> <img src=vpn_icon /> दिखेगा."</string>
+ <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> को वीपीएन कनेक्शन सेट अप करने की अनुमति चाहिए. इससे वह नेटवर्क ट्रैफ़िक पर नज़र रख पाएगा. अनुमति तब दें, जब आपको ऐप्लिकेशन पर भरोसा हो. वीपीएन चालू होने पर, आपकी स्क्रीन पर <br /> <br /> <img src=vpn_icon /> दिखेगा."</string>
<string name="legacy_title" msgid="192936250066580964">"VPN कनेक्ट है"</string>
<string name="session" msgid="6470628549473641030">"सत्र:"</string>
<string name="duration" msgid="3584782459928719435">"अवधि:"</string>
diff --git a/packages/VpnDialogs/res/values-hy/strings.xml b/packages/VpnDialogs/res/values-hy/strings.xml
index 62a2604..d2a6d42 100644
--- a/packages/VpnDialogs/res/values-hy/strings.xml
+++ b/packages/VpnDialogs/res/values-hy/strings.xml
@@ -18,7 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="3183836924226407828">"Միացման հայց"</string>
<string name="warning" msgid="809658604548412033">"«<xliff:g id="APP">%s</xliff:g>» հավելվածը ցանկանում է VPN կապ հաստատել՝ ցանցային երթևեկը հսկելու համար: Թույլատրեք, միայն եթե վստահում եք աղբյուրին։ Երբ VPN-ն ակտիվ լինի, ձեր էկրանի վերին հատվածում կհայտնվի <br /> <br /> <img src=vpn_icon /> պատկերը:"</string>
- <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> հավելվածն ուզում է միանալ VPN-ի ցանցին՝ թրաֆիկին հետևելու համար։ Թույլատրեք, միայն եթե վստահում եք աղբյուրին։ <br /> <br />Երբ VPN-ն ակտիվացված լինի, <img src=vpn_icon /> պատկերակը կհայտնվի ձեր էկրանին։"</string>
+ <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> հավելվածն ուզում է միանալ VPN-ի ցանցին՝ թրաֆիկին հետևելու համար։ Թույլատրեք, միայն եթե վստահում եք աղբյուրին։ Երբ VPN-ն ակտիվացված լինի, <br /> <br /> <img src=vpn_icon /> պատկերակը կհայտնվի ձեր էկրանին։"</string>
<string name="legacy_title" msgid="192936250066580964">"VPN-ը կապակցված է"</string>
<string name="session" msgid="6470628549473641030">"Աշխատաշրջան`"</string>
<string name="duration" msgid="3584782459928719435">"Տևողությունը՝"</string>
diff --git a/packages/VpnDialogs/res/values-mr/strings.xml b/packages/VpnDialogs/res/values-mr/strings.xml
index 6caccf7..22fb502 100644
--- a/packages/VpnDialogs/res/values-mr/strings.xml
+++ b/packages/VpnDialogs/res/values-mr/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="3183836924226407828">"कनेक्शन विनंती"</string>
<string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> नेटवर्क रहदारीचे परीक्षण करण्यासाठी त्यास अनुमती देणारे VPN कनेक्शन सेट करू इच्छितो. तुम्हाला स्रोत विश्वसनीय वाटत असेल तरच स्वीकार करा. <br /> <br /> <img src=vpn_icon /> VPN सक्रिय असताना आपल्या स्क्रीनच्या शीर्षावर दिसते."</string>
- <!-- no translation found for warning (5188957997628124947) -->
- <skip />
+ <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> ला नेटवर्क ट्रॅफिकवर लक्ष ठेवण्याची अनुमती देणारे VPN कनेक्शन सेट करायचे आहे. तुमचा स्रोतावर विश्वास असेल तरच स्वीकारा. VPN अॅक्टिव्ह असल्यास, तुमच्या स्क्रीनवर <br /> <br /> <img src=vpn_icon /> दिसते."</string>
<string name="legacy_title" msgid="192936250066580964">"VPN कनेक्ट केले"</string>
<string name="session" msgid="6470628549473641030">"सत्र:"</string>
<string name="duration" msgid="3584782459928719435">"कालावधी:"</string>
diff --git a/packages/VpnDialogs/res/values-ne/strings.xml b/packages/VpnDialogs/res/values-ne/strings.xml
index a248d6d8..2a5648d 100644
--- a/packages/VpnDialogs/res/values-ne/strings.xml
+++ b/packages/VpnDialogs/res/values-ne/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="3183836924226407828">"जडान अनुरोध"</string>
<string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ले नेटवर्क यातायात अनुगमन गर्न अनुमति दिने VPN जडान स्थापना गर्न चाहन्छ। तपाईँले स्रोत भरोसा छ भने मात्र स्वीकार गर्नुहोस्। <br /> <br /> <img src=vpn_icon /> जब VPN सक्रिय हुन्छ आफ्नो स्क्रिनको माथि देखा पर्छन्।"</string>
- <!-- no translation found for warning (5188957997628124947) -->
- <skip />
+ <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> ले कुनै VPN कनेक्सन सेटअप गर्न चाहन्छ। यसको सहायताले यो एप नेटवर्क ट्राफिकको निगरानी राख्न सक्छ। तपाईं यो एपमाथि विश्वास गर्नुहुन्छ भने मात्र स्वीकार गर्नुहोस्। VPN सक्रिय हुँदा तपाईंको स्क्रिनमा <br /> <br /> <img src=vpn_icon /> देखा पर्छ।"</string>
<string name="legacy_title" msgid="192936250066580964">"VPN जोडिएको छ"</string>
<string name="session" msgid="6470628549473641030">"सत्र:"</string>
<string name="duration" msgid="3584782459928719435">"अवधि:"</string>
diff --git a/packages/VpnDialogs/res/values-te/strings.xml b/packages/VpnDialogs/res/values-te/strings.xml
index f6d19ff..2316c62 100644
--- a/packages/VpnDialogs/res/values-te/strings.xml
+++ b/packages/VpnDialogs/res/values-te/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="3183836924226407828">"కనెక్షన్ అభ్యర్థన"</string>
<string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> నెట్వర్క్ ట్రాఫిక్ని పర్యవేక్షించగలగడానికి VPN కనెక్షన్ను సెటప్ చేయాలనుకుంటోంది. మీరు మూలాన్ని విశ్వసిస్తే మాత్రమే ఆమోదించండి. VPN సక్రియంగా ఉన్నప్పుడు మీ స్క్రీన్ ఎగువన <br /> <br /> <img src=vpn_icon /> కనిపిస్తుంది."</string>
- <!-- no translation found for warning (5188957997628124947) -->
- <skip />
+ <string name="warning" product="tv" msgid="5188957997628124947">"నెట్వర్క్ ట్రాఫిక్ను పర్యవేక్షించగలగడానికి, <xliff:g id="APP">%s</xliff:g> VPN కనెక్షన్ను సెటప్ చేయాలనుకుంటోంది. మీరు సోర్స్ను విశ్వసిస్తే మాత్రమే ఆమోదించండి. <br /> <br /> <img src=vpn_icon /> VPN యాక్టివ్గా ఉన్నప్పుడు మీ స్క్రీన్ పై కనిపిస్తుంది."</string>
<string name="legacy_title" msgid="192936250066580964">"VPN కనెక్ట్ చేయబడింది"</string>
<string name="session" msgid="6470628549473641030">"సెషన్:"</string>
<string name="duration" msgid="3584782459928719435">"వ్యవధి:"</string>
diff --git a/packages/VpnDialogs/res/values-ur/strings.xml b/packages/VpnDialogs/res/values-ur/strings.xml
index 10dc56c..3a23e94 100644
--- a/packages/VpnDialogs/res/values-ur/strings.xml
+++ b/packages/VpnDialogs/res/values-ur/strings.xml
@@ -18,8 +18,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="3183836924226407828">"کنکشن کی درخواست"</string>
<string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> ایک ایسا VPN کنکشن ترتیب دینا چاہتی ہے جو اسے نیٹ ورک ٹریفک کو مانیٹر کرنے کی اجازت دیتا ہے۔ اگر آپ کو ماخذ پر بھروسہ ہے تبھی قبول کریں۔ <br /> <br /> <img src=vpn_icon /> آپ کی اسکرین کے اوپر اس وقت ظاہر ہوتا ہے جب VPN فعال ہوتا ہے۔"</string>
- <!-- no translation found for warning (5188957997628124947) -->
- <skip />
+ <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> ایک ایسا VPN کنکشن سیٹ اپ کرنا چاہتی ہے جو اسے نیٹ ورک ٹریفک کو مانیٹر کرنے کی اجازت دیتا ہو۔ آپ کو ماخذ پر اعتماد ہونے پر ہی قبول کریں۔ <br /> <br /> <img src=vpn_icon /> VPN کے فعال ہونے پر آپ کی اسکرین پر ظاہر ہوتا ہے۔"</string>
<string name="legacy_title" msgid="192936250066580964">"VPN مربوط ہے"</string>
<string name="session" msgid="6470628549473641030">"سیشن:"</string>
<string name="duration" msgid="3584782459928719435">"دورانیہ:"</string>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bn/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bn/strings.xml
new file mode 100644
index 0000000..15b1fdc
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"লুকান (কাটআউট অঞ্চলে অ্যাপটি দেখাবেন না)"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-gu/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-gu/strings.xml
new file mode 100644
index 0000000..557c791
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-gu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"છુપાવો (કટ આઉટ પ્રદેશમાં ઍપ બાકાત રાખો)"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mr/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mr/strings.xml
new file mode 100644
index 0000000..ecd0c0b
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-mr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"लपवा (कटआउट भागामध्ये ॲप्स दाखवू नका)"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ne/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ne/strings.xml
new file mode 100644
index 0000000..98d7512
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ne/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"लुकाइयोस् (कटआउट क्षेत्रमा एपहरू नदेखाइयोस्)"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ro/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ro/strings.xml
index 9227ceb..9aefb31 100644
--- a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ro/strings.xml
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ro/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Ascundeți (evitați aplicațiile din regiunea decupată)"</string>
+ <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"Ascundeți (se evită aplicațiile în regiunea decupată)"</string>
</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-te/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-te/strings.xml
new file mode 100644
index 0000000..db2a797
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"దాచండి (కట్అవుట్ ప్రాంతంలో యాప్లను నివారించండి)"</string>
+</resources>
diff --git a/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ur/strings.xml b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ur/strings.xml
new file mode 100644
index 0000000..48c5d14
--- /dev/null
+++ b/packages/overlays/AvoidAppsInCutoutOverlay/res/values-ur/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="1946296620328354129">"چھپائیں (کٹ آؤٹ والے علاقے میں ایپس سے اجتناب کریں)"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-bn/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-bn/strings.xml
new file mode 100644
index 0000000..1e62725
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"লুকান"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-gu/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-gu/strings.xml
new file mode 100644
index 0000000..7e4b33a
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-gu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"છુપાવો"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-mr/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-mr/strings.xml
new file mode 100644
index 0000000..46f0ab8
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-mr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"लपवा"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-ne/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-ne/strings.xml
new file mode 100644
index 0000000..ff920b2
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-ne/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"लुकाइयोस्"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-te/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-te/strings.xml
new file mode 100644
index 0000000..de04152
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"దాచండి"</string>
+</resources>
diff --git a/packages/overlays/NoCutoutOverlay/res/values-ur/strings.xml b/packages/overlays/NoCutoutOverlay/res/values-ur/strings.xml
new file mode 100644
index 0000000..0f08170
--- /dev/null
+++ b/packages/overlays/NoCutoutOverlay/res/values-ur/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="display_cutout_emulation_overlay" msgid="9031691255599853162">"چھپائیں"</string>
+</resources>
diff --git a/services/Android.bp b/services/Android.bp
index 1dd2192..c83a697 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -72,17 +72,6 @@
visibility: ["//visibility:private"],
}
-filegroup {
- name: "services-all-sources",
- srcs: [
- ":services-non-updatable-sources",
- ":service-media-s-sources",
- ":service-permission-sources",
- ":service-statsd-sources",
- ],
- visibility: ["//visibility:private"],
-}
-
java_library {
name: "Slogf",
srcs: ["core/java/com/android/server/utils/Slogf.java"],
@@ -141,7 +130,6 @@
libs: [
"android.hidl.manager-V1.0-java",
"framework-tethering.stubs.module_lib",
- "service-art.stubs.system_server",
],
// Uncomment to enable output of certain warnings (deprecated, unchecked)
diff --git a/services/OWNERS b/services/OWNERS
index 03e0807..3b972e9 100644
--- a/services/OWNERS
+++ b/services/OWNERS
@@ -3,4 +3,4 @@
# art-team@ manages the system server profile
per-file art-profile* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
-per-file java/com/android/server/* = toddke@google.com
+per-file java/com/android/server/* = toddke@google.com,patb@google.com
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index ab85b5e..83dfe8e 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -20,6 +20,7 @@
import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
import static android.bluetooth.le.ScanSettings.SCAN_MODE_BALANCED;
import static android.content.Context.BIND_IMPORTANT;
+import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -657,7 +658,14 @@
}
@Override
- public void createAssociation(String packageName, String macAddress, int userId) {
+ public void createAssociation(String packageName, String macAddress, int userId,
+ byte[] certificate) {
+ if (!getContext().getPackageManager().hasSigningCertificate(
+ packageName, certificate, CERT_INPUT_SHA256)) {
+ Slog.e(LOG_TAG, "Given certificate doesn't match the package certificate.");
+ return;
+ }
+
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES, "createAssociation");
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index 0bd331b..b87184a 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -25,6 +25,7 @@
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_IGNORE_BATTERY_STATUS_KEY;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_MAX_CALL_STATS_KEY;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_SAMPLING_INTERVAL_KEY;
+import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_SHARDING_MODULO_KEY;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_TRACK_DIRECT_CALLING_UID_KEY;
import static com.android.internal.os.BinderCallsStats.SettingsObserver.SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY;
@@ -188,6 +189,10 @@
mBinderCallsStats.setIgnoreBatteryStatus(
mParser.getBoolean(SETTINGS_IGNORE_BATTERY_STATUS_KEY,
BinderCallsStats.DEFAULT_IGNORE_BATTERY_STATUS));
+ mBinderCallsStats.setShardingModulo(mParser.getInt(
+ SETTINGS_SHARDING_MODULO_KEY,
+ BinderCallsStats.SHARDING_MODULO_DEFAULT));
+
mBinderCallsStats.setCollectLatencyData(
mParser.getBoolean(SETTINGS_COLLECT_LATENCY_DATA_KEY,
BinderCallsStats.DEFAULT_COLLECT_LATENCY_DATA));
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index 6e7771d..e336b6b 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -39,11 +39,9 @@
import libcore.io.IoUtils;
import java.io.DataInputStream;
-import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
@@ -377,11 +375,16 @@
try {
FileChannel channel = getBlockOutputChannel();
- ByteBuffer buf = ByteBuffer.allocate(DIGEST_SIZE_BYTES + HEADER_SIZE);
+ int header_size = DIGEST_SIZE_BYTES + HEADER_SIZE;
+ ByteBuffer buf = ByteBuffer.allocate(header_size);
buf.put(new byte[DIGEST_SIZE_BYTES]);
buf.putInt(PARTITION_TYPE_MARKER);
buf.putInt(0);
channel.write(buf);
+ // corrupt the payload explicitly
+ int payload_size = (int) getBlockDeviceSize() - header_size;
+ buf = ByteBuffer.allocate(payload_size);
+ channel.write(buf);
channel.force(true);
} catch (IOException e) {
Slog.e(TAG, "failed to format block", e);
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index b0d6d65..71609d2 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -966,6 +966,19 @@
mHandler.removeListener(listener);
}
+ /**
+ * Unregisters a listener from sensor privacy state change notifications.
+ */
+ @Override
+ public void removeIndividualSensorPrivacyListener(int sensor,
+ ISensorPrivacyListener listener) {
+ enforceObserveSensorPrivacyPermission();
+ if (listener == null) {
+ throw new NullPointerException("listener cannot be null");
+ }
+ mHandler.removeListener(sensor, listener);
+ }
+
@Override
public void suppressIndividualSensorPrivacyReminders(int userId, String packageName,
IBinder token, boolean suppress) {
@@ -1300,10 +1313,21 @@
deathRecipient.destroy();
}
mListeners.unregister(listener);
+ }
+ }
+
+ public void removeListener(int sensor, ISensorPrivacyListener listener) {
+ synchronized (mListenerLock) {
+ DeathRecipient deathRecipient = mDeathRecipients.remove(listener);
+ if (deathRecipient != null) {
+ deathRecipient.destroy();
+ }
+
for (int i = 0, numUsers = mIndividualSensorListeners.size(); i < numUsers; i++) {
- for (int j = 0, numListeners = mIndividualSensorListeners.valueAt(i).size();
- j < numListeners; j++) {
- mIndividualSensorListeners.valueAt(i).valueAt(j).unregister(listener);
+ RemoteCallbackList callbacks =
+ mIndividualSensorListeners.valueAt(i).get(sensor);
+ if (callbacks != null) {
+ callbacks.unregister(listener);
}
}
}
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index dc8f84a..85eadf5 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -754,8 +754,7 @@
}
@Override
- public void setApplicationNightMode(@UiModeManager.NightMode int mode)
- throws RemoteException {
+ public void setApplicationNightMode(@UiModeManager.NightMode int mode) {
switch (mode) {
case UiModeManager.MODE_NIGHT_NO:
case UiModeManager.MODE_NIGHT_YES:
@@ -776,14 +775,10 @@
default:
configNightMode = Configuration.UI_MODE_NIGHT_UNDEFINED;
}
- try {
- final ActivityTaskManagerInternal.PackageConfigurationUpdater updater =
- mActivityTaskManager.createPackageConfigurationUpdater();
- updater.setNightMode(configNightMode);
- updater.commit();
- } catch (RemoteException e) {
- throw e;
- }
+ final ActivityTaskManagerInternal.PackageConfigurationUpdater updater =
+ mActivityTaskManager.createPackageConfigurationUpdater();
+ updater.setNightMode(configNightMode);
+ updater.commit();
}
@Override
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index e7e3ce9..7e2274b 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -64,6 +64,7 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
+import android.util.LocalLog;
import android.util.Log;
import android.util.Slog;
@@ -148,6 +149,11 @@
// TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity
public class VcnManagementService extends IVcnManagementService.Stub {
@NonNull private static final String TAG = VcnManagementService.class.getSimpleName();
+ private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5);
+ private static final int LOCAL_LOG_LINE_COUNT = 128;
+
+ // Public for use in all other VCN classes
+ @NonNull public static final LocalLog LOCAL_LOG = new LocalLog(LOCAL_LOG_LINE_COUNT);
public static final boolean VDBG = false; // STOPSHIP: if true
@@ -241,13 +247,13 @@
try {
configBundle = mConfigDiskRwHelper.readFromDisk();
} catch (IOException e1) {
- Slog.e(TAG, "Failed to read configs from disk; retrying", e1);
+ logErr("Failed to read configs from disk; retrying", e1);
// Retry immediately. The IOException may have been transient.
try {
configBundle = mConfigDiskRwHelper.readFromDisk();
} catch (IOException e2) {
- Slog.wtf(TAG, "Failed to read configs from disk", e2);
+ logWtf("Failed to read configs from disk", e2);
return;
}
}
@@ -439,7 +445,7 @@
synchronized (mLock) {
final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot;
mLastSnapshot = snapshot;
- Slog.d(TAG, "new snapshot: " + mLastSnapshot);
+ logDbg("new snapshot: " + mLastSnapshot);
// Start any VCN instances as necessary
for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) {
@@ -542,7 +548,7 @@
@GuardedBy("mLock")
private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
- Slog.d(TAG, "Starting VCN config for subGrp: " + subscriptionGroup);
+ logDbg("Starting VCN config for subGrp: " + subscriptionGroup);
// TODO(b/176939047): Support multiple VCNs active at the same time, or limit to one active
// VCN.
@@ -567,7 +573,7 @@
@GuardedBy("mLock")
private void startOrUpdateVcnLocked(
@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
- Slog.d(TAG, "Starting or updating VCN config for subGrp: " + subscriptionGroup);
+ logDbg("Starting or updating VCN config for subGrp: " + subscriptionGroup);
if (mVcns.containsKey(subscriptionGroup)) {
final Vcn vcn = mVcns.get(subscriptionGroup);
@@ -593,7 +599,7 @@
if (!config.getProvisioningPackageName().equals(opPkgName)) {
throw new IllegalArgumentException("Mismatched caller and VcnConfig creator");
}
- Slog.d(TAG, "VCN config updated for subGrp: " + subscriptionGroup);
+ logDbg("VCN config updated for subGrp: " + subscriptionGroup);
mContext.getSystemService(AppOpsManager.class)
.checkPackage(mDeps.getBinderCallingUid(), config.getProvisioningPackageName());
@@ -619,7 +625,7 @@
public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull String opPkgName) {
requireNonNull(subscriptionGroup, "subscriptionGroup was null");
requireNonNull(opPkgName, "opPkgName was null");
- Slog.d(TAG, "VCN config cleared for subGrp: " + subscriptionGroup);
+ logDbg("VCN config cleared for subGrp: " + subscriptionGroup);
mContext.getSystemService(AppOpsManager.class)
.checkPackage(mDeps.getBinderCallingUid(), opPkgName);
@@ -682,7 +688,7 @@
VcnConfig::toPersistableBundle);
mConfigDiskRwHelper.writeToDisk(bundle);
} catch (IOException e) {
- Slog.e(TAG, "Failed to save configs to disk", e);
+ logErr("Failed to save configs to disk", e);
throw new ServiceSpecificException(0, "Failed to save configs");
}
}
@@ -792,7 +798,7 @@
for (int subId : networkCapabilities.getSubscriptionIds()) {
// Verify that all subscriptions point to the same group
if (subGrp != null && !subGrp.equals(snapshot.getGroupForSubId(subId))) {
- Slog.wtf(TAG, "Got multiple subscription groups for a single network");
+ logWtf("Got multiple subscription groups for a single network");
}
subGrp = snapshot.getGroupForSubId(subId);
@@ -858,10 +864,8 @@
final VcnUnderlyingNetworkPolicy policy = new VcnUnderlyingNetworkPolicy(
mTrackingNetworkCallback.requiresRestartForCarrierWifi(result), result);
- if (VDBG) {
- Slog.d(TAG, "getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities
+ logVdbg("getUnderlyingNetworkPolicy() called for caps: " + networkCapabilities
+ "; and lp: " + linkProperties + "; result = " + policy);
- }
return policy;
});
}
@@ -953,14 +957,14 @@
|| vcnStatus == VCN_STATUS_CODE_SAFE_MODE) {
resultStatus = vcnStatus;
} else {
- Slog.wtf(TAG, "Unknown VCN status: " + vcnStatus);
+ logWtf("Unknown VCN status: " + vcnStatus);
resultStatus = VCN_STATUS_CODE_NOT_CONFIGURED;
}
try {
cbInfo.mCallback.onVcnStatusChanged(resultStatus);
} catch (RemoteException e) {
- Slog.d(TAG, "VcnStatusCallback threw on VCN status change", e);
+ logDbg("VcnStatusCallback threw on VCN status change", e);
}
}
} finally {
@@ -988,6 +992,43 @@
}
}
+ private void logVdbg(String msg) {
+ if (VDBG) {
+ Slog.v(TAG, msg);
+ LOCAL_LOG.log(TAG + " VDBG: " + msg);
+ }
+ }
+
+ private void logDbg(String msg) {
+ Slog.d(TAG, msg);
+ LOCAL_LOG.log(TAG + " DBG: " + msg);
+ }
+
+ private void logDbg(String msg, Throwable tr) {
+ Slog.d(TAG, msg, tr);
+ LOCAL_LOG.log(TAG + " DBG: " + msg + tr);
+ }
+
+ private void logErr(String msg) {
+ Slog.e(TAG, msg);
+ LOCAL_LOG.log(TAG + " ERR: " + msg);
+ }
+
+ private void logErr(String msg, Throwable tr) {
+ Slog.e(TAG, msg, tr);
+ LOCAL_LOG.log(TAG + " ERR: " + msg + tr);
+ }
+
+ private void logWtf(String msg) {
+ Slog.wtf(TAG, msg);
+ LOCAL_LOG.log(TAG + " WTF: " + msg);
+ }
+
+ private void logWtf(String msg, Throwable tr) {
+ Slog.wtf(TAG, msg, tr);
+ LOCAL_LOG.log(TAG + " WTF: " + msg + tr);
+ }
+
/**
* Dumps the state of the VcnManagementService for logging and debugging purposes.
*
@@ -997,48 +1038,44 @@
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
mContext.enforceCallingOrSelfPermission(DUMP, TAG);
- final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+ final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "| ");
- pw.println("VcnManagementService dump:");
- pw.increaseIndent();
-
- pw.println("mNetworkProvider:");
- pw.increaseIndent();
- mNetworkProvider.dump(pw);
- pw.decreaseIndent();
- pw.println();
-
- pw.println("mTrackingNetworkCallback:");
- pw.increaseIndent();
- mTrackingNetworkCallback.dump(pw);
- pw.decreaseIndent();
- pw.println();
-
- synchronized (mLock) {
- pw.println("mLastSnapshot:");
- pw.increaseIndent();
- mLastSnapshot.dump(pw);
- pw.decreaseIndent();
+ // Post to handler thread to prevent ConcurrentModificationExceptions, and avoid lock-hell.
+ mHandler.runWithScissors(() -> {
+ mNetworkProvider.dump(pw);
pw.println();
- pw.println("mConfigs:");
- pw.increaseIndent();
- for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) {
- pw.println(entry.getKey() + ": " + entry.getValue().getProvisioningPackageName());
+ mTrackingNetworkCallback.dump(pw);
+ pw.println();
+
+ synchronized (mLock) {
+ mLastSnapshot.dump(pw);
+ pw.println();
+
+ pw.println("mConfigs:");
+ pw.increaseIndent();
+ for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) {
+ pw.println(entry.getKey() + ": "
+ + entry.getValue().getProvisioningPackageName());
+ }
+ pw.decreaseIndent();
+ pw.println();
+
+ pw.println("mVcns:");
+ pw.increaseIndent();
+ for (Vcn vcn : mVcns.values()) {
+ vcn.dump(pw);
+ }
+ pw.decreaseIndent();
+ pw.println();
}
- pw.decreaseIndent();
- pw.println();
- pw.println("mVcns:");
+ pw.println("Local log:");
pw.increaseIndent();
- for (Vcn vcn : mVcns.values()) {
- vcn.dump(pw);
- }
+ LOCAL_LOG.dump(pw);
pw.decreaseIndent();
pw.println();
- }
-
- pw.decreaseIndent();
+ }, DUMP_TIMEOUT_MILLIS);
}
// TODO(b/180452282): Make name more generic and implement directly with VcnManagementService
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 0f3aa65..71d6a48 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -21,38 +21,40 @@
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
+import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
+import static android.os.PowerExemptionManager.REASON_ACTIVITY_STARTER;
import static android.os.PowerExemptionManager.REASON_ACTIVITY_VISIBILITY_GRACE_PERIOD;
+import static android.os.PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE;
+import static android.os.PowerExemptionManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
+import static android.os.PowerExemptionManager.REASON_BACKGROUND_FGS_PERMISSION;
+import static android.os.PowerExemptionManager.REASON_COMPANION_DEVICE_MANAGER;
+import static android.os.PowerExemptionManager.REASON_DENIED;
+import static android.os.PowerExemptionManager.REASON_DEVICE_DEMO_MODE;
+import static android.os.PowerExemptionManager.REASON_DEVICE_OWNER;
+import static android.os.PowerExemptionManager.REASON_FGS_BINDING;
+import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
+import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_FGS_PERMISSION;
import static android.os.PowerExemptionManager.REASON_OPT_OUT_REQUESTED;
import static android.os.PowerExemptionManager.REASON_OP_ACTIVATE_PLATFORM_VPN;
import static android.os.PowerExemptionManager.REASON_OP_ACTIVATE_VPN;
+import static android.os.PowerExemptionManager.REASON_PROC_STATE_PERSISTENT;
+import static android.os.PowerExemptionManager.REASON_PROC_STATE_PERSISTENT_UI;
+import static android.os.PowerExemptionManager.REASON_PROC_STATE_TOP;
+import static android.os.PowerExemptionManager.REASON_PROFILE_OWNER;
+import static android.os.PowerExemptionManager.REASON_SERVICE_LAUNCH;
+import static android.os.PowerExemptionManager.REASON_START_ACTIVITY_FLAG;
+import static android.os.PowerExemptionManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
+import static android.os.PowerExemptionManager.REASON_SYSTEM_ALLOW_LISTED;
+import static android.os.PowerExemptionManager.REASON_SYSTEM_UID;
import static android.os.PowerExemptionManager.REASON_TEMP_ALLOWED_WHILE_IN_USE;
-import static android.os.PowerWhitelistManager.REASON_ACTIVITY_STARTER;
-import static android.os.PowerWhitelistManager.REASON_ALLOWLISTED_PACKAGE;
-import static android.os.PowerWhitelistManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_BACKGROUND_FGS_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_COMPANION_DEVICE_MANAGER;
-import static android.os.PowerWhitelistManager.REASON_DENIED;
-import static android.os.PowerWhitelistManager.REASON_DEVICE_DEMO_MODE;
-import static android.os.PowerWhitelistManager.REASON_DEVICE_OWNER;
-import static android.os.PowerWhitelistManager.REASON_FGS_BINDING;
-import static android.os.PowerWhitelistManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_INSTR_BACKGROUND_FGS_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_PROC_STATE_PERSISTENT;
-import static android.os.PowerWhitelistManager.REASON_PROC_STATE_PERSISTENT_UI;
-import static android.os.PowerWhitelistManager.REASON_PROC_STATE_TOP;
-import static android.os.PowerWhitelistManager.REASON_PROFILE_OWNER;
-import static android.os.PowerWhitelistManager.REASON_START_ACTIVITY_FLAG;
-import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
-import static android.os.PowerWhitelistManager.REASON_SYSTEM_UID;
-import static android.os.PowerWhitelistManager.REASON_UID_VISIBLE;
-import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
-import static android.os.PowerWhitelistManager.getReasonCodeFromProcState;
-import static android.os.PowerWhitelistManager.reasonCodeToString;
+import static android.os.PowerExemptionManager.REASON_UID_VISIBLE;
+import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+import static android.os.PowerExemptionManager.getReasonCodeFromProcState;
+import static android.os.PowerExemptionManager.reasonCodeToString;
import static android.os.Process.INVALID_UID;
import static android.os.Process.NFC_UID;
import static android.os.Process.ROOT_UID;
@@ -118,8 +120,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
-import android.os.PowerWhitelistManager;
-import android.os.PowerWhitelistManager.ReasonCode;
+import android.os.PowerExemptionManager.ReasonCode;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
@@ -135,6 +136,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
+import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
@@ -1704,14 +1706,6 @@
+ String.format("0x%08X", manifestType)
+ " in service element of manifest file");
}
- // If the foreground service is not started from TOP process, do not allow it to
- // have while-in-use location/camera/microphone access.
- if (!r.mAllowWhileInUsePermissionInFgs) {
- Slog.w(TAG,
- "Foreground service started from background can not have "
- + "location/camera/microphone access: service "
- + r.shortInstanceName);
- }
}
boolean alreadyStartedOp = false;
@@ -1800,6 +1794,14 @@
r.appInfo.uid, r.intent.getIntent(), r, r.userId,false);
}
}
+ // If the foreground service is not started from TOP process, do not allow it to
+ // have while-in-use location/camera/microphone access.
+ if (!r.mAllowWhileInUsePermissionInFgs) {
+ Slog.w(TAG,
+ "Foreground service started from background can not have "
+ + "location/camera/microphone access: service "
+ + r.shortInstanceName);
+ }
logFgsBackgroundStart(r);
if (r.mAllowStartForeground == REASON_DENIED && isBgFgsRestrictionEnabled(r)) {
final String msg = "Service.startForeground() not allowed due to "
@@ -2567,10 +2569,6 @@
s.setAllowedBgActivityStartsByBinding(true);
}
- if ((flags & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
- s.setAllowedBgFgsStartsByBinding(true);
- }
-
if ((flags & Context.BIND_NOT_APP_COMPONENT_USAGE) != 0) {
s.isNotAppComponentUsage = true;
}
@@ -3614,8 +3612,9 @@
+ " for fg-service launch");
}
mAm.tempAllowlistUidLocked(r.appInfo.uid,
- SERVICE_START_FOREGROUND_TIMEOUT, PowerWhitelistManager.REASON_SERVICE_LAUNCH,
- "fg-service-launch", TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ SERVICE_START_FOREGROUND_TIMEOUT, REASON_SERVICE_LAUNCH,
+ "fg-service-launch",
+ TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
r.mRecentCallingUid);
}
@@ -4126,9 +4125,6 @@
if ((c.flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
s.updateIsAllowedBgActivityStartsByBinding();
}
- if ((c.flags & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
- s.updateIsAllowedBgFgsStartsByBinding();
- }
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app.mServices, c, true);
}
@@ -5740,6 +5736,66 @@
int ret = shouldAllowFgsStartForegroundLocked(allowWhileInUse, callingPid, callingUid,
callingPackage, r);
+ String bindFromPackage = null;
+ if (ret == REASON_DENIED) {
+ // If the callingUid is not allowed to start FGS, check if the callingUid has any
+ // service that is bound by a clientUid, the clientUid can propagate its BG-FGS-start
+ // capability down to the callingUid.
+ final ArraySet<Integer> checkedClientUids = new ArraySet<>();
+ final Pair<Integer, String> isAllowed = mAm.mProcessList.searchEachLruProcessesLOSP(
+ false, pr -> {
+ if (pr.uid == callingUid) {
+ final ProcessServiceRecord psr = pr.mServices;
+ final int serviceCount = psr.mServices.size();
+ for (int svc = 0; svc < serviceCount; svc++) {
+ final ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns =
+ psr.mServices.valueAt(svc).getConnections();
+ final int size = conns.size();
+ for (int conni = 0; conni < size; conni++) {
+ final ArrayList<ConnectionRecord> crs = conns.valueAt(conni);
+ for (int con = 0; con < crs.size(); con++) {
+ final ConnectionRecord cr = crs.get(con);
+ final ProcessRecord clientPr = cr.binding.client;
+ // Persistent process does not propagate BG-FGS-start capability
+ // down to service over binding.
+ if (clientPr.mState.getCurProcState()
+ <= PROCESS_STATE_PERSISTENT_UI) {
+ continue;
+ }
+ final int clientPid = clientPr.mPid;
+ final int clientUid = clientPr.uid;
+ // An UID can bind to itself, do not check on itself again.
+ // Also skip already checked clientUid.
+ if (clientUid == callingUid
+ || checkedClientUids.contains(clientUid)) {
+ continue;
+ }
+ final String clientPackageName = cr.clientPackageName;
+ final @ReasonCode int allowWhileInUse2 =
+ shouldAllowFgsWhileInUsePermissionLocked(clientPackageName,
+ clientPid, clientUid, null /* serviceRecord */,
+ false /* allowBackgroundActivityStarts */);
+ final @ReasonCode int allowStartFgs =
+ shouldAllowFgsStartForegroundLocked(allowWhileInUse2,
+ clientPid, clientUid, clientPackageName, null /* targetService */);
+ if (allowStartFgs != REASON_DENIED) {
+ return new Pair<>(allowStartFgs, clientPackageName);
+ } else {
+ checkedClientUids.add(clientUid);
+ }
+
+ }
+ }
+ }
+ }
+ return null;
+ });
+ if (isAllowed != null) {
+ ret = REASON_FGS_BINDING;
+ bindFromPackage = isAllowed.second;
+ }
+ }
+
final int uidState = mAm.getUidStateLocked(callingUid);
int callerTargetSdkVersion = INVALID_UID;
try {
@@ -5765,6 +5821,7 @@
+ "; targetSdkVersion:" + r.appInfo.targetSdkVersion
+ "; callerTargetSdkVersion:" + callerTargetSdkVersion
+ "; startForegroundCount:" + r.mStartForegroundCount
+ + "; bindFromPackage:" + bindFromPackage
+ "]";
if (!debugInfo.equals(r.mInfoAllowStartForeground)) {
r.mLoggedInfoAllowStartForeground = false;
@@ -5790,12 +5847,8 @@
final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, app -> {
if (app.uid == callingUid) {
final ProcessStateRecord state = app.mState;
- if (state.getAllowedStartFgs() != REASON_DENIED) {
- return state.getAllowedStartFgs();
- } else if (state.isAllowedStartFgsState()) {
+ if (state.isAllowedStartFgsState()) {
return getReasonCodeFromProcState(state.getAllowStartFgsState());
- } else if (state.areBackgroundFgsStartsAllowedByToken()) {
- return REASON_FGS_BINDING;
} else {
final ActiveInstrumentation instr = app.getActiveInstrumentation();
if (instr != null
@@ -5891,6 +5944,7 @@
}
if (ret == REASON_DENIED) {
if (mAm.mConstants.mFgsAllowOptOut
+ && targetService != null
&& targetService.appInfo.hasRequestForegroundServiceExemption()) {
ret = REASON_OPT_OUT_REQUESTED;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5f95761..3e6a0a8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1236,7 +1236,7 @@
* The temp-allowlist that is allowed to start FGS from background.
*/
@CompositeRWLock({"this", "mProcLock"})
- final FgsTempAllowList<Integer, FgsTempAllowListItem> mFgsStartTempAllowList =
+ final FgsTempAllowList<FgsTempAllowListItem> mFgsStartTempAllowList =
new FgsTempAllowList();
static final FgsTempAllowListItem FAKE_TEMP_ALLOW_LIST_ITEM = new FgsTempAllowListItem(
@@ -1246,7 +1246,7 @@
* List of uids that are allowed to have while-in-use permission when FGS is started from
* background.
*/
- private final FgsTempAllowList<Integer, String> mFgsWhileInUseTempAllowList =
+ private final FgsTempAllowList<String> mFgsWhileInUseTempAllowList =
new FgsTempAllowList();
/**
@@ -2589,6 +2589,7 @@
addServiceToMap(mAppBindArgs, Context.POWER_SERVICE);
addServiceToMap(mAppBindArgs, Context.USER_SERVICE);
addServiceToMap(mAppBindArgs, "mount");
+ addServiceToMap(mAppBindArgs, Context.PLATFORM_COMPAT_SERVICE);
}
return mAppBindArgs;
}
@@ -4324,8 +4325,8 @@
if (pid > 0 && pid != MY_PID) {
killProcessQuiet(pid);
//TODO: killProcessGroup(app.info.uid, pid);
- mProcessList.noteAppKill(app, ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
- ApplicationExitInfo.SUBREASON_UNKNOWN, "attach failed");
+ // We can't log the app kill info for this process since we don't
+ // know who it is, so just skip the logging.
} else {
try {
thread.scheduleExit();
@@ -9371,22 +9372,17 @@
pw.println(" mFgsStartTempAllowList:");
final long currentTimeNow = System.currentTimeMillis();
final long elapsedRealtimeNow = SystemClock.elapsedRealtime();
- final Set<Integer> uids = new ArraySet<>(mFgsStartTempAllowList.keySet());
- for (Integer uid : uids) {
- final Pair<Long, FgsTempAllowListItem> entry = mFgsStartTempAllowList.get(uid);
- if (entry == null) {
- continue;
- }
+ mFgsStartTempAllowList.forEach((uid, entry) -> {
pw.print(" " + UserHandle.formatUid(uid) + ": ");
- entry.second.dump(pw); pw.println();
- pw.print("ms expiration=");
+ entry.second.dump(pw);
+ pw.print(" expiration=");
// Convert entry.mExpirationTime, which is an elapsed time since boot,
// to a time since epoch (i.e. System.currentTimeMillis()-based time.)
final long expirationInCurrentTime =
currentTimeNow - elapsedRealtimeNow + entry.first;
TimeUtils.dumpTimeWithDelta(pw, expirationInCurrentTime, currentTimeNow);
pw.println();
- }
+ });
}
if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
|| mOrigWaitForDebugger) {
@@ -15344,10 +15340,19 @@
mDeviceIdleTempAllowlist = appids;
if (adding) {
if (type == TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
+ // Note, the device idle temp-allowlist are by app-ids, but here
+ // mFgsStartTempAllowList contains UIDs.
mFgsStartTempAllowList.add(changingUid, durationMs,
new FgsTempAllowListItem(durationMs, reasonCode, reason,
callingUid));
}
+ } else {
+ // Note in the removing case, we need to remove all the UIDs matching
+ // the appId, because DeviceIdle's temp-allowlist are based on AppIds,
+ // not UIDs.
+ // For eacmple, "cmd deviceidle tempallowlist -r PACKAGE" will
+ // not only remove this app for user 0, but for all users.
+ mFgsStartTempAllowList.removeAppId(UserHandle.getAppId(changingUid));
}
setAppIdTempAllowlistStateLSP(changingUid, adding);
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 85e8315..4e6e91a 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -139,7 +139,7 @@
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE)
.replaceWith("?");
- private static final int MAX_LOW_POWER_STATS_SIZE = 8192;
+ private static final int MAX_LOW_POWER_STATS_SIZE = 16384;
private static final int POWER_STATS_QUERY_TIMEOUT_MILLIS = 2000;
private static final String EMPTY = "Empty";
@@ -771,9 +771,7 @@
default:
throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
}
- // TODO(b/187223764): busTime won't be needed once end_session is a field in BUS.
- final long busTime = System.currentTimeMillis();
- final byte[] statsProto = bus.getStatsProto(busTime);
+ final byte[] statsProto = bus.getStatsProto();
data.add(FrameworkStatsLog.buildStatsEvent(atomTag, statsProto));
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 1ddd899..966e746 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -927,7 +927,7 @@
+ " received sync transactions while frozen, killing");
app.killLocked("Sync transaction while in frozen state",
ApplicationExitInfo.REASON_OTHER,
- ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
+ ApplicationExitInfo.SUBREASON_FREEZER_BINDER_TRANSACTION, true);
processKilled = true;
}
@@ -940,7 +940,7 @@
+ app.processName + ". Killing it. Exception: " + e);
app.killLocked("Unable to query binder frozen stats",
ApplicationExitInfo.REASON_OTHER,
- ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
+ ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true);
processKilled = true;
}
@@ -957,7 +957,7 @@
+ ". Killing it");
app.killLocked("Unable to unfreeze",
ApplicationExitInfo.REASON_OTHER,
- ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
+ ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true);
return;
}
@@ -1342,7 +1342,7 @@
synchronized (mAm) {
proc.killLocked("Unable to freeze binder interface",
ApplicationExitInfo.REASON_OTHER,
- ApplicationExitInfo.SUBREASON_INVALID_STATE, true);
+ ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true);
}
});
}
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index f32423f..b325ea3 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -159,6 +159,10 @@
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.MAGNIFIER_ASPECT_RATIO,
WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, float.class,
WidgetFlags.MAGNIFIER_ASPECT_RATIO_DEFAULT));
+ sDeviceConfigEntries.add(new DeviceConfigEntry<>(
+ DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ANALOG_CLOCK_SECONDS_HAND_FPS,
+ WidgetFlags.KEY_ANALOG_CLOCK_SECONDS_HAND_FPS, int.class,
+ WidgetFlags.ANALOG_CLOCK_SECONDS_HAND_FPS_DEFAULT));
// add other device configs here...
}
diff --git a/services/core/java/com/android/server/am/FgsTempAllowList.java b/services/core/java/com/android/server/am/FgsTempAllowList.java
index 847e82f..c286556 100644
--- a/services/core/java/com/android/server/am/FgsTempAllowList.java
+++ b/services/core/java/com/android/server/am/FgsTempAllowList.java
@@ -20,11 +20,12 @@
import android.annotation.Nullable;
import android.os.SystemClock;
-import android.util.ArrayMap;
+import android.os.UserHandle;
import android.util.Pair;
import android.util.Slog;
+import android.util.SparseArray;
-import java.util.Set;
+import java.util.function.BiConsumer;
/**
* List of keys that have expiration time.
@@ -33,19 +34,18 @@
*
* <p>This is used for both FGS-BG-start restriction, and FGS-while-in-use permissions check.</p>
*
- * <p>Note: the underlying data structure is an {@link ArrayMap}, for performance reason, it is only
- * suitable to hold up to hundreds of entries.</p>
- * @param <K> type of the key.
+ * <p>Note: the underlying data structure is an {@link SparseArray}, for performance reason,
+ * it is only suitable to hold up to hundreds of entries.</p>
* @param <E> type of the additional optional info.
*/
-public class FgsTempAllowList<K, E> {
+public class FgsTempAllowList<E> {
private static final int DEFAULT_MAX_SIZE = 100;
/**
* The value is Pair type, Pair.first is the expirationTime(an elapsedRealtime),
* Pair.second is the optional information entry about this key.
*/
- private final ArrayMap<K, Pair<Long, E>> mTempAllowList = new ArrayMap<>();
+ private final SparseArray<Pair<Long, E>> mTempAllowList = new SparseArray<>();
private int mMaxSize = DEFAULT_MAX_SIZE;
private final Object mLock = new Object();
@@ -70,15 +70,14 @@
/**
* Add a key and its duration with optional info into the temp allowlist.
- * @param key
* @param durationMs temp-allowlisted duration in milliseconds.
* @param entry additional optional information of this key, could be null.
*/
- public void add(K key, long durationMs, @Nullable E entry) {
+ public void add(int uid, long durationMs, @Nullable E entry) {
synchronized (mLock) {
if (durationMs <= 0) {
Slog.e(TAG_AM, "FgsTempAllowList bad duration:" + durationMs + " key: "
- + key);
+ + uid);
return;
}
// The temp allowlist should be a short list with only a few entries in it.
@@ -94,10 +93,10 @@
}
}
}
- final Pair<Long, E> existing = mTempAllowList.get(key);
+ final Pair<Long, E> existing = mTempAllowList.get(uid);
final long expirationTime = now + durationMs;
if (existing == null || existing.first < expirationTime) {
- mTempAllowList.put(key, new Pair(expirationTime, entry));
+ mTempAllowList.put(uid, new Pair(expirationTime, entry));
}
}
}
@@ -105,13 +104,12 @@
/**
* If the key has not expired (AKA allowed), return its non-null value.
* If the key has expired, return null.
- * @param key
* @return
*/
@Nullable
- public Pair<Long, E> get(K key) {
+ public Pair<Long, E> get(int uid) {
synchronized (mLock) {
- final int index = mTempAllowList.indexOfKey(key);
+ final int index = mTempAllowList.indexOfKey(uid);
if (index < 0) {
return null;
} else if (mTempAllowList.valueAt(index).first < SystemClock.elapsedRealtime()) {
@@ -126,23 +124,48 @@
/**
* If the key has not expired (AKA allowed), return true.
* If the key has expired, return false.
- * @param key
- * @return
*/
- public boolean isAllowed(K key) {
- Pair<Long, E> entry = get(key);
+ public boolean isAllowed(int uid) {
+ Pair<Long, E> entry = get(uid);
return entry != null;
}
- public void remove(K key) {
+ /**
+ * Remove a given UID.
+ */
+ public void removeUid(int uid) {
synchronized (mLock) {
- mTempAllowList.remove(key);
+ mTempAllowList.remove(uid);
}
}
- public Set<K> keySet() {
+ /**
+ * Remove by appId.
+ */
+ public void removeAppId(int appId) {
synchronized (mLock) {
- return mTempAllowList.keySet();
+ // Find all UIDs matching the appId.
+ for (int i = mTempAllowList.size() - 1; i >= 0; i--) {
+ final int uid = mTempAllowList.keyAt(i);
+ if (UserHandle.getAppId(uid) == appId) {
+ mTempAllowList.removeAt(i);
+ }
+ }
+ }
+ }
+
+ /**
+ * Iterate over the entries.
+ */
+ public void forEach(BiConsumer<Integer, Pair<Long, E>> callback) {
+ synchronized (mLock) {
+ for (int i = 0; i < mTempAllowList.size(); i++) {
+ final int uid = mTempAllowList.keyAt(i);
+ final Pair<Long, E> entry = mTempAllowList.valueAt(i);
+ if (entry != null) {
+ callback.accept(uid, entry);
+ }
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index 273b9c3..c4efbd7 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -20,6 +20,7 @@
# Permissions & Packages
svetoslavganov@google.com
toddke@google.com
+patb@google.com
# Battery Stats
joeo@google.com
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 2e2a297..661e0b8 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -42,7 +42,6 @@
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
-import static android.os.PowerWhitelistManager.REASON_DENIED;
import static android.os.Process.SCHED_OTHER;
import static android.os.Process.THREAD_GROUP_BACKGROUND;
import static android.os.Process.THREAD_GROUP_DEFAULT;
@@ -1574,8 +1573,7 @@
state.setAdjTarget(null);
state.setEmpty(false);
state.setCached(false);
- state.setAllowStartFgsState(PROCESS_STATE_NONEXISTENT);
- state.resetAllowStartFgs();
+ state.resetAllowStartFgsState();
app.mOptRecord.setShouldNotFreeze(false);
final int appUid = app.info.uid;
@@ -1630,7 +1628,6 @@
state.setCurAdj(state.getMaxAdj());
state.setCompletedAdjSeq(state.getAdjSeq());
state.bumpAllowStartFgsState(state.getCurProcState());
- state.setAllowStartFgs();
// if curAdj is less than prevAppAdj, then this process was promoted
return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState;
}
@@ -2028,12 +2025,6 @@
final boolean clientIsSystem = clientProcState < PROCESS_STATE_TOP;
- // pass client's mAllowStartFgs to the app if client is not persistent process.
- if (cstate.getAllowedStartFgs() != REASON_DENIED
- && cstate.getMaxAdj() >= ProcessList.FOREGROUND_APP_ADJ) {
- state.setAllowStartFgs(cstate.getAllowedStartFgs());
- }
-
if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) {
if (shouldSkipDueToCycle(state, cstate, procState, adj, cycleReEval)) {
continue;
@@ -2524,7 +2515,6 @@
state.updateLastInvisibleTime(hasVisibleActivities);
state.setHasForegroundActivities(foregroundActivities);
state.setCompletedAdjSeq(mAdjSeq);
- state.setAllowStartFgs();
// if curAdj or curProcState improved, then this process was promoted
return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 0ffaccf..457fe0f 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -3074,7 +3074,7 @@
UidRecord.CHANGE_GONE);
EventLogTags.writeAmUidStopped(uid);
mActiveUids.remove(uid);
- mService.mFgsStartTempAllowList.remove(record.info.uid);
+ mService.mFgsStartTempAllowList.removeUid(record.info.uid);
mService.noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT,
ActivityManager.PROCESS_CAPABILITY_NONE);
}
diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java
index 5c3bf60..8f77b87 100644
--- a/services/core/java/com/android/server/am/ProcessServiceRecord.java
+++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java
@@ -89,7 +89,7 @@
/**
* All ServiceRecord running in this process.
*/
- private final ArraySet<ServiceRecord> mServices = new ArraySet<>();
+ final ArraySet<ServiceRecord> mServices = new ArraySet<>();
/**
* Services that are currently executing code (need to remain foreground).
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index 801e382..1fb5572 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -16,28 +16,9 @@
package com.android.server.am;
-import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
-import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
-import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.os.PowerWhitelistManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_BACKGROUND_FGS_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_DENIED;
-import static android.os.PowerWhitelistManager.REASON_DEVICE_OWNER;
-import static android.os.PowerWhitelistManager.REASON_PROFILE_OWNER;
-import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
-import static android.os.PowerWhitelistManager.REASON_SYSTEM_UID;
-import static android.os.PowerWhitelistManager.ReasonCode;
-import static android.os.PowerWhitelistManager.getReasonCodeFromProcState;
-import static android.os.PowerWhitelistManager.reasonCodeToString;
-import static android.os.Process.NFC_UID;
-import static android.os.Process.ROOT_UID;
-import static android.os.Process.SHELL_UID;
-import static android.os.Process.SYSTEM_UID;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
import static com.android.server.am.ProcessRecord.TAG;
@@ -45,9 +26,7 @@
import android.annotation.ElapsedRealtimeLong;
import android.app.ActivityManager;
import android.content.ComponentName;
-import android.os.Binder;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Slog;
import android.util.TimeUtils;
@@ -56,7 +35,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.FrameworkStatsLog;
-
import java.io.PrintWriter;
/**
@@ -323,23 +301,6 @@
@GuardedBy("mService")
private int mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
- @GuardedBy("mService")
- private final ArraySet<Binder> mBackgroundFgsStartTokens = new ArraySet<>();
-
- /**
- * Does the process has permission to start FGS from background.
- */
- @GuardedBy("mService")
- private @ReasonCode int mAllowStartFgsByPermission = REASON_DENIED;
-
- /**
- * Can this process start FGS from background?
- * If this process has the ability to start FGS from background, this ability can be passed to
- * another process through service binding.
- */
- @GuardedBy("mService")
- private @ReasonCode int mAllowStartFgs = REASON_DENIED;
-
/**
* Whether or not this process has been in forced-app-standby state.
*/
@@ -435,7 +396,6 @@
mApp = app;
mService = app.mService;
mProcLock = mService.mProcLock;
- setAllowStartFgsByPermission();
}
void init(long now) {
@@ -1137,24 +1097,8 @@
}
@GuardedBy("mService")
- void addAllowBackgroundFgsStartsToken(Binder entity) {
- mBackgroundFgsStartTokens.add(entity);
- }
-
- @GuardedBy("mService")
- void removeAllowBackgroundFgsStartsToken(Binder entity) {
- mBackgroundFgsStartTokens.remove(entity);
- }
-
- @GuardedBy("mService")
- boolean areBackgroundFgsStartsAllowedByToken() {
- return !mBackgroundFgsStartTokens.isEmpty();
- }
-
- @GuardedBy("mService")
- void resetAllowStartFgs() {
+ void resetAllowStartFgsState() {
mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
- mAllowStartFgs = mAllowStartFgsByPermission;
}
@GuardedBy("mService")
@@ -1165,11 +1109,6 @@
}
@GuardedBy("mService")
- void setAllowStartFgsState(int allowStartFgsState) {
- mAllowStartFgsState = allowStartFgsState;
- }
-
- @GuardedBy("mService")
int getAllowStartFgsState() {
return mAllowStartFgsState;
}
@@ -1180,98 +1119,6 @@
}
@GuardedBy("mService")
- void setAllowStartFgsByPermission() {
- int ret = REASON_DENIED;
- boolean isSystem = false;
- final int uid = UserHandle.getAppId(mApp.info.uid);
- switch (uid) {
- case ROOT_UID:
- case SYSTEM_UID:
- case NFC_UID:
- case SHELL_UID:
- isSystem = true;
- break;
- default:
- isSystem = false;
- break;
- }
-
- if (isSystem) {
- ret = REASON_SYSTEM_UID;
- }
-
- if (ret == REASON_DENIED) {
- if (ActivityManager.checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND,
- mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
- ret = REASON_BACKGROUND_ACTIVITY_PERMISSION;
- } else if (ActivityManager.checkComponentPermission(
- START_FOREGROUND_SERVICES_FROM_BACKGROUND,
- mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
- ret = REASON_BACKGROUND_FGS_PERMISSION;
- } else if (ActivityManager.checkComponentPermission(SYSTEM_ALERT_WINDOW,
- mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
- ret = REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
- }
- }
- mAllowStartFgs = mAllowStartFgsByPermission = ret;
- }
-
- // TODO(b/188063200) Clean up this method. Why do we need to duplicate only some of the checks?
- @GuardedBy("mService")
- void setAllowStartFgs() {
- if (mAllowStartFgs != REASON_DENIED) {
- return;
- }
- if (mAllowStartFgs == REASON_DENIED) {
- if (isAllowedStartFgsState()) {
- mAllowStartFgs = getReasonCodeFromProcState(mAllowStartFgsState);
- }
- }
-
- if (mAllowStartFgs == REASON_DENIED) {
- // Is the calling UID a device owner app?
- if (mService.mInternal != null) {
- if (mService.mInternal.isDeviceOwner(mApp.info.uid)) {
- mAllowStartFgs = REASON_DEVICE_OWNER;
- }
- }
- }
-
- if (mAllowStartFgs == REASON_DENIED) {
- // Is the calling UID a profile owner app?
- if (mService.mInternal != null) {
- if (mService.mInternal.isProfileOwner(mApp.info.uid)) {
- mAllowStartFgs = REASON_PROFILE_OWNER;
- }
- }
- }
-
- if (mAllowStartFgs == REASON_DENIED) {
- // uid is on DeviceIdleController's user/system allowlist
- // or AMS's FgsStartTempAllowList.
- ActivityManagerService.FgsTempAllowListItem item =
- mService.isAllowlistedForFgsStartLOSP(mApp.info.uid);
- if (item != null) {
- if (item == ActivityManagerService.FAKE_TEMP_ALLOW_LIST_ITEM) {
- mAllowStartFgs = REASON_SYSTEM_ALLOW_LISTED;
- } else {
- mAllowStartFgs = item.mReasonCode;
- }
- }
- }
- }
-
- @GuardedBy("mService")
- void setAllowStartFgs(@ReasonCode int allowStartFgs) {
- mAllowStartFgs = allowStartFgs;
- }
-
- @GuardedBy("mService")
- @ReasonCode int getAllowedStartFgs() {
- return mAllowStartFgs;
- }
-
- @GuardedBy("mService")
void setForcedAppStandby(boolean standby) {
mForcedAppStandby = standby;
}
@@ -1334,10 +1181,6 @@
pw.println();
pw.print(prefix); pw.print("allowStartFgsState=");
pw.println(mAllowStartFgsState);
- if (mAllowStartFgs != REASON_DENIED) {
- pw.print(prefix); pw.print("allowStartFgs=");
- pw.println(reasonCodeToString(mAllowStartFgs));
- }
if (mHasShownUi || mApp.mProfile.hasPendingUiClean()) {
pw.print(prefix); pw.print("hasShownUi="); pw.print(mHasShownUi);
pw.print(" pendingUiClean="); pw.println(mApp.mProfile.hasPendingUiClean());
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index fd59e85..dbb2f65 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -149,10 +149,6 @@
@GuardedBy("ams")
private List<IBinder> mBgActivityStartsByStartOriginatingTokens = new ArrayList<>();
- // any current binding to this service has BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND
- // flag? if true, the process can start FGS from background.
- boolean mIsAllowedBgFgsStartsByBinding;
-
// allow while-in-use permissions in foreground service or not.
// while-in-use permissions in FGS started from background might be restricted.
boolean mAllowWhileInUsePermissionInFgs;
@@ -445,10 +441,6 @@
pw.print(prefix); pw.print("mIsAllowedBgActivityStartsByStart=");
pw.println(mIsAllowedBgActivityStartsByStart);
}
- if (mIsAllowedBgFgsStartsByBinding) {
- pw.print(prefix); pw.print("mIsAllowedBgFgsStartsByBinding=");
- pw.println(mIsAllowedBgFgsStartsByBinding);
- }
pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs=");
pw.println(mAllowWhileInUsePermissionInFgs);
pw.print(prefix); pw.print("recentCallingPackage=");
@@ -634,11 +626,6 @@
} else {
proc.removeAllowBackgroundActivityStartsToken(this);
}
- if (mIsAllowedBgFgsStartsByBinding) {
- proc.mState.addAllowBackgroundFgsStartsToken(this);
- } else {
- proc.mState.removeAllowBackgroundFgsStartsToken(this);
- }
}
if (app != null && app != proc) {
// If the old app is allowed to start bg activities because of a service start, leave it
@@ -726,34 +713,11 @@
setAllowedBgActivityStartsByBinding(isAllowedByBinding);
}
- void updateIsAllowedBgFgsStartsByBinding() {
- boolean isAllowedByBinding = false;
- for (int conni = connections.size() - 1; conni >= 0; conni--) {
- ArrayList<ConnectionRecord> cr = connections.valueAt(conni);
- for (int i = 0; i < cr.size(); i++) {
- if ((cr.get(i).flags
- & Context.BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND) != 0) {
- isAllowedByBinding = true;
- break;
- }
- }
- if (isAllowedByBinding) {
- break;
- }
- }
- setAllowedBgFgsStartsByBinding(isAllowedByBinding);
- }
-
void setAllowedBgActivityStartsByBinding(boolean newValue) {
mIsAllowedBgActivityStartsByBinding = newValue;
updateParentProcessBgActivityStartsToken();
}
- void setAllowedBgFgsStartsByBinding(boolean newValue) {
- mIsAllowedBgFgsStartsByBinding = newValue;
- updateParentProcessBgFgsStartsToken();
- }
-
/**
* Called when the service is started with allowBackgroundActivityStarts set. We allow
* it for background activity starts, setting up a callback to remove this ability after a
@@ -846,17 +810,6 @@
}
}
- private void updateParentProcessBgFgsStartsToken() {
- if (app == null) {
- return;
- }
- if (mIsAllowedBgFgsStartsByBinding) {
- app.mState.addAllowBackgroundFgsStartsToken(this);
- } else {
- app.mState.removeAllowBackgroundFgsStartsToken(this);
- }
- }
-
/**
* Returns the originating token if that's the only reason background activity starts are
* allowed. In order for that to happen the service has to be allowed only due to starts, since
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 1aeeda0..f70b0fb 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -387,12 +387,12 @@
* Get an array of a package's available game modes.
*/
public @GameMode int[] getAvailableGameModes() {
-
- int modesBitfield = getAvailableGameModesBitfield();
- int sigBits = Integer.bitCount(modesBitfield);
- int[] modes = new int[sigBits];
+ final int modesBitfield = getAvailableGameModesBitfield();
+ int[] modes = new int[Integer.bitCount(modesBitfield)];
int i = 0;
- for (int mode = 0; mode < sigBits; ++mode) {
+ final int gameModeInHighestBit =
+ Integer.numberOfTrailingZeros(Integer.highestOneBit(modesBitfield));
+ for (int mode = 0; mode <= gameModeInHighestBit; ++mode) {
if (((modesBitfield >> mode) & 1) != 0) {
modes[i++] = mode;
}
diff --git a/services/core/java/com/android/server/app/GameManagerShellCommand.java b/services/core/java/com/android/server/app/GameManagerShellCommand.java
index e4c0002..c5f1a0b 100644
--- a/services/core/java/com/android/server/app/GameManagerShellCommand.java
+++ b/services/core/java/com/android/server/app/GameManagerShellCommand.java
@@ -16,6 +16,8 @@
package com.android.server.app;
+import android.app.GameManager;
+import android.app.IGameManagerService;
import android.compat.Compatibility;
import android.content.Context;
import android.os.ServiceManager;
@@ -55,7 +57,7 @@
final PrintWriter pw = getOutPrintWriter();
try {
switch (cmd) {
- case "downscale":
+ case "downscale": {
final String ratio = getNextArgRequired();
final String packageName = getNextArgRequired();
@@ -114,6 +116,71 @@
}
break;
+ }
+ case "mode": {
+ /** The "mode" command allows setting a package's current game mode outside of
+ * the game dashboard UI. This command requires that a mode already be supported
+ * by the package. Devs can forcibly support game modes via the manifest
+ * metadata flags: com.android.app.gamemode.performance.enabled,
+ * com.android.app.gamemode.battery.enabled
+ * OR by `adb shell device_config put game_overlay \
+ * <PACKAGE_NAME> <CONFIG_STRING>`
+ * see: {@link GameManagerServiceTests#mockDeviceConfigAll()}
+ */
+ final String gameMode = getNextArgRequired();
+ final String packageName = getNextArgRequired();
+ final String userIdStr = getNextArgRequired();
+ final IGameManagerService service = IGameManagerService.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.GAME_SERVICE));
+ boolean batteryModeSupported = false;
+ boolean perfModeSupported = false;
+ int[] modes = service.getAvailableGameModes(packageName);
+ for (int mode : modes) {
+ if (mode == GameManager.GAME_MODE_PERFORMANCE) {
+ perfModeSupported = true;
+ } else if (mode == GameManager.GAME_MODE_BATTERY) {
+ batteryModeSupported = true;
+ }
+ }
+ int userId = Integer.parseInt(userIdStr);
+ switch (gameMode.toLowerCase()) {
+ case "1":
+ case "standard":
+ // Standard should only be available if other game modes are.
+ if (batteryModeSupported || perfModeSupported) {
+ service.setGameMode(packageName, GameManager.GAME_MODE_STANDARD,
+ userId);
+ } else {
+ pw.println("Game mode: " + gameMode + " not supported by "
+ + packageName);
+ }
+ break;
+ case "2":
+ case "performance":
+ if (perfModeSupported) {
+ service.setGameMode(packageName, GameManager.GAME_MODE_PERFORMANCE,
+ userId);
+ } else {
+ pw.println("Game mode: " + gameMode + " not supported by "
+ + packageName);
+ }
+ break;
+ case "3":
+ case "battery":
+ if (batteryModeSupported) {
+ service.setGameMode(packageName, GameManager.GAME_MODE_BATTERY,
+ userId);
+ } else {
+ pw.println("Game mode: " + gameMode + " not supported by "
+ + packageName);
+ }
+ break;
+ default:
+ pw.println("Invalid game mode: " + gameMode);
+ break;
+ }
+ break;
+ }
default:
return handleDefaultCommands(cmd);
}
@@ -132,5 +199,7 @@
pw.println(" Print this help text.");
pw.println(" downscale [0.5|0.6|0.7|0.8|0.9|disable] <PACKAGE_NAME>");
pw.println(" Force app to run at the specified scaling ratio.");
+ pw.println(" mode [1|2|3|standard|performance|battery] <PACKAGE_NAME> <USER_ID>");
+ pw.println(" Force app to run in the specified game mode, if supported.");
}
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index c5582a0..541dcdc 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -116,6 +116,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.PackageTagsList;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteCallbackList;
@@ -132,6 +133,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.IndentingPrintWriter;
import android.util.KeyValueListParser;
import android.util.LongSparseArray;
import android.util.Pair;
@@ -6194,17 +6196,19 @@
final int excludedPackageCount = restrictionState.perUserExcludedPackageTags != null
? restrictionState.perUserExcludedPackageTags.size() : 0;
if (excludedPackageCount > 0 && dumpOp < 0) {
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
+ ipw.increaseIndent();
boolean printedPackagesHeader = false;
for (int j = 0; j < excludedPackageCount; j++) {
int userId = restrictionState.perUserExcludedPackageTags.keyAt(j);
- Map<String, String[]> packageNames =
+ PackageTagsList packageNames =
restrictionState.perUserExcludedPackageTags.valueAt(j);
if (packageNames == null) {
continue;
}
boolean hasPackage;
if (dumpPackage != null) {
- hasPackage = packageNames.containsKey(dumpPackage);
+ hasPackage = packageNames.includes(dumpPackage);
} else {
hasPackage = true;
}
@@ -6212,32 +6216,29 @@
continue;
}
if (!printedTokenHeader) {
- pw.println(" User restrictions for token " + token + ":");
+ ipw.println("User restrictions for token " + token + ":");
printedTokenHeader = true;
}
+
+ ipw.increaseIndent();
if (!printedPackagesHeader) {
- pw.println(" Excluded packages:");
+ ipw.println("Excluded packages:");
printedPackagesHeader = true;
}
- pw.print(" ");
- pw.print("user: ");
- pw.print(userId);
- pw.println(" packages: ");
- for (Map.Entry<String, String[]> entry : packageNames.entrySet()) {
- if (entry.getValue() == null) {
- continue;
- }
- pw.print(" ");
- pw.print(entry.getKey());
- pw.print(": ");
- if (entry.getValue().length == 0) {
- pw.print("*");
- } else {
- pw.print(Arrays.toString(entry.getValue()));
- }
- pw.println();
- }
+
+ ipw.increaseIndent();
+ ipw.print("user: ");
+ ipw.print(userId);
+ ipw.println(" packages: ");
+
+ ipw.increaseIndent();
+ packageNames.dump(ipw);
+
+ ipw.decreaseIndent();
+ ipw.decreaseIndent();
+ ipw.decreaseIndent();
}
+ ipw.decreaseIndent();
}
}
}
@@ -6270,7 +6271,7 @@
@Override
public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
- Map<String, String[]> excludedPackageTags) {
+ PackageTagsList excludedPackageTags) {
if (Binder.getCallingPid() != Process.myPid()) {
mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
Binder.getCallingPid(), Binder.getCallingUid(), null);
@@ -6290,7 +6291,7 @@
}
private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
- int userHandle, Map<String, String[]> excludedPackageTags) {
+ int userHandle, PackageTagsList excludedPackageTags) {
synchronized (AppOpsService.this) {
ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
@@ -6835,7 +6836,7 @@
private final class ClientRestrictionState implements DeathRecipient {
private final IBinder token;
SparseArray<boolean[]> perUserRestrictions;
- SparseArray<Map<String, String[]>> perUserExcludedPackageTags;
+ SparseArray<PackageTagsList> perUserExcludedPackageTags;
public ClientRestrictionState(IBinder token)
throws RemoteException {
@@ -6844,7 +6845,7 @@
}
public boolean setRestriction(int code, boolean restricted,
- Map<String, String[]> excludedPackageTags, int userId) {
+ PackageTagsList excludedPackageTags, int userId) {
boolean changed = false;
if (perUserRestrictions == null && restricted) {
@@ -6886,7 +6887,8 @@
}
if (userRestrictions != null) {
- final boolean noExcludedPackages = ArrayUtils.isEmpty(excludedPackageTags);
+ final boolean noExcludedPackages =
+ excludedPackageTags == null || excludedPackageTags.isEmpty();
if (perUserExcludedPackageTags == null && !noExcludedPackages) {
perUserExcludedPackageTags = new SparseArray<>();
}
@@ -6897,16 +6899,7 @@
perUserExcludedPackageTags = null;
}
} else {
- Map<String, String[]> userExcludedPackageTags =
- perUserExcludedPackageTags.get(thisUserId);
- if (userExcludedPackageTags == null) {
- userExcludedPackageTags = new ArrayMap<>(
- excludedPackageTags.size());
- perUserExcludedPackageTags.put(thisUserId,
- userExcludedPackageTags);
- }
- userExcludedPackageTags.clear();
- userExcludedPackageTags.putAll(excludedPackageTags);
+ perUserExcludedPackageTags.put(thisUserId, excludedPackageTags);
}
changed = true;
}
@@ -6932,19 +6925,11 @@
if (perUserExcludedPackageTags == null) {
return true;
}
- Map<String, String[]> perUserExclusions = perUserExcludedPackageTags.get(userId);
+ PackageTagsList perUserExclusions = perUserExcludedPackageTags.get(userId);
if (perUserExclusions == null) {
return true;
}
- String[] excludedTags = perUserExclusions.get(packageName);
- if (excludedTags == null) {
- return true;
- }
- if (excludedTags.length == 0) {
- // all attribution tags within the package are excluded
- return false;
- }
- return !ArrayUtils.contains(excludedTags, attributionTag);
+ return !perUserExclusions.contains(packageName, attributionTag);
}
public void removeUser(int userId) {
diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java
index 99daa24..10cfddf 100644
--- a/services/core/java/com/android/server/appop/DiscreteRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java
@@ -43,7 +43,6 @@
import android.os.Build;
import android.os.Environment;
import android.os.FileUtils;
-import android.os.Process;
import android.provider.DeviceConfig;
import android.util.ArrayMap;
import android.util.AtomicFile;
@@ -229,7 +228,7 @@
void recordDiscreteAccess(int uid, String packageName, int op, @Nullable String attributionTag,
@AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState, long accessTime,
long accessDuration) {
- if (!isDiscreteOp(op, uid, flags)) {
+ if (!isDiscreteOp(op, flags)) {
return;
}
synchronized (mInMemoryLock) {
@@ -1046,26 +1045,16 @@
return result;
}
- private static boolean isDiscreteOp(int op, int uid, @AppOpsManager.OpFlags int flags) {
+ private static boolean isDiscreteOp(int op, @AppOpsManager.OpFlags int flags) {
if (!ArrayUtils.contains(sDiscreteOps, op)) {
return false;
}
- if (!isDiscreteUid(uid)) {
- return false;
- }
if ((flags & (sDiscreteFlags)) == 0) {
return false;
}
return true;
}
- private static boolean isDiscreteUid(int uid) {
- if (uid < Process.FIRST_APPLICATION_UID) {
- return false;
- }
- return true;
- }
-
void setDebugMode(boolean debugMode) {
this.mDebugMode = debugMode;
}
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index e118781..1e3eec8 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -19,8 +19,25 @@
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
+import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT;
+import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT;
+import static android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
-import static com.android.server.biometrics.BiometricServiceStateProto.*;
+import static com.android.server.biometrics.BiometricServiceStateProto.MULTI_SENSOR_STATE_FACE_SCANNING;
+import static com.android.server.biometrics.BiometricServiceStateProto.MULTI_SENSOR_STATE_FP_SCANNING;
+import static com.android.server.biometrics.BiometricServiceStateProto.MULTI_SENSOR_STATE_SWITCHING;
+import static com.android.server.biometrics.BiometricServiceStateProto.MULTI_SENSOR_STATE_UNKNOWN;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTHENTICATED_PENDING_SYSUI;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_CALLED;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_IDLE;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_PAUSED;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_PAUSED_RESUMING;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_PENDING_CONFIRM;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_STARTED;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_STARTED_UI_SHOWING;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_CLIENT_DIED_CANCELLING;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_ERROR_PENDING_SYSUI;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_SHOWING_DEVICE_CREDENTIAL;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -49,8 +66,10 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
import java.util.List;
import java.util.Random;
+import java.util.function.Function;
/**
* Class that defines the states of an authentication session invoked via
@@ -78,6 +97,14 @@
@Retention(RetentionPolicy.SOURCE)
@interface SessionState {}
+ /** Defined in biometrics.proto */
+ @IntDef({
+ MULTI_SENSOR_STATE_UNKNOWN,
+ MULTI_SENSOR_STATE_FACE_SCANNING,
+ MULTI_SENSOR_STATE_FP_SCANNING})
+ @Retention(RetentionPolicy.SOURCE)
+ @interface MultiSensorState {}
+
/**
* Notify the holder of the AuthSession that the caller/client's binder has died. The
* holder (BiometricService) should schedule {@link AuthSession#onClientDied()} to be run
@@ -111,6 +138,9 @@
// The current state, which can be either idle, called, or started
private @SessionState int mState = STATE_AUTH_IDLE;
+ private @BiometricMultiSensorMode int mMultiSensorMode;
+ private @MultiSensorState int mMultiSensorState;
+ private int[] mSensors;
// For explicit confirmation, do not send to keystore until the user has confirmed
// the authentication.
private byte[] mTokenEscrow;
@@ -186,6 +216,9 @@
// with the cookie. Once all cookies are received, we can show the prompt
// and let the services start authenticating. The cookie should be non-zero.
for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
+ if (DEBUG) {
+ Slog.v(TAG, "set to unknown state sensor: " + sensor.id);
+ }
sensor.goToStateUnknown();
}
}
@@ -194,6 +227,10 @@
for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
final int cookie = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
final boolean requireConfirmation = isConfirmationRequired(sensor);
+
+ if (DEBUG) {
+ Slog.v(TAG, "waiting for cooking for sensor: " + sensor.id);
+ }
sensor.goToStateWaitingForCookie(requireConfirmation, mToken, mOperationId,
mUserId, mSensorReceiver, mOpPackageName, cookie,
mPromptInfo.isAllowBackgroundAuthentication());
@@ -206,16 +243,20 @@
// since LockSettingsService/Gatekeeper is always ready to check for credential.
// SystemUI invokes that path.
mState = STATE_SHOWING_DEVICE_CREDENTIAL;
+ mSensors = new int[0];
+ mMultiSensorMode = BIOMETRIC_MULTI_SENSOR_DEFAULT;
+ mMultiSensorState = MULTI_SENSOR_STATE_UNKNOWN;
mStatusBarService.showAuthenticationDialog(
mPromptInfo,
mSysuiReceiver,
- new int[0] /* sensorIds */,
+ mSensors /* sensorIds */,
true /* credentialAllowed */,
false /* requireConfirmation */,
mUserId,
mOpPackageName,
- mOperationId);
+ mOperationId,
+ mMultiSensorMode);
} else if (!mPreAuthInfo.eligibleSensors.isEmpty()) {
// Some combination of biometric or biometric|credential is requested
setSensorsToStateWaitingForCookie();
@@ -235,9 +276,9 @@
if (allCookiesReceived()) {
mStartTimeMs = System.currentTimeMillis();
- // For UDFPS, do not start until BiometricPrompt UI is shown. Otherwise, the UDFPS
- // affordance will be shown before the BP UI is finished animating in.
- startAllPreparedSensorsExceptUdfps();
+ // Do not start fingerprint sensors until BiometricPrompt UI is shown. Otherwise,
+ // the affordance may be shown before the BP UI is finished animating in.
+ startAllPreparedSensorsExceptFingerprint();
// No need to request the UI if we're coming from the paused state.
if (mState != STATE_AUTH_PAUSED_RESUMING) {
@@ -245,19 +286,23 @@
// If any sensor requires confirmation, request it to be shown.
final boolean requireConfirmation = isConfirmationRequiredByAnyEligibleSensor();
- final int[] sensorIds = new int[mPreAuthInfo.eligibleSensors.size()];
+ mSensors = new int[mPreAuthInfo.eligibleSensors.size()];
for (int i = 0; i < mPreAuthInfo.eligibleSensors.size(); i++) {
- sensorIds[i] = mPreAuthInfo.eligibleSensors.get(i).id;
+ mSensors[i] = mPreAuthInfo.eligibleSensors.get(i).id;
}
+ mMultiSensorMode = getMultiSensorModeForNewSession(
+ mPreAuthInfo.eligibleSensors);
+ mMultiSensorState = MULTI_SENSOR_STATE_UNKNOWN;
mStatusBarService.showAuthenticationDialog(mPromptInfo,
mSysuiReceiver,
- sensorIds,
+ mSensors,
mPreAuthInfo.shouldShowCredential(),
requireConfirmation,
mUserId,
mOpPackageName,
- mOperationId);
+ mOperationId,
+ mMultiSensorMode);
mState = STATE_AUTH_STARTED;
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
@@ -266,7 +311,8 @@
// The UI was already showing :)
mState = STATE_AUTH_STARTED_UI_SHOWING;
}
-
+ } else {
+ Slog.v(TAG, "onCookieReceived: still waiting");
}
}
@@ -285,53 +331,50 @@
return false;
}
- private boolean isUdfpsSensor(@NonNull BiometricSensor sensor) {
- if (sensor.modality != TYPE_FINGERPRINT) {
- return false;
- }
-
- for (FingerprintSensorPropertiesInternal prop : mFingerprintSensorProperties) {
- if (sensor.id == prop.sensorId && prop.isAnyUdfpsType()) {
- return true;
- }
- }
- return false;
+ private void startAllPreparedSensorsExceptFingerprint() {
+ startAllPreparedSensors(sensor -> sensor.modality != TYPE_FINGERPRINT);
}
- private void startAllPreparedSensorsExceptUdfps() {
- for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
- if (isUdfpsSensor(sensor)) {
- Slog.d(TAG, "Skipping UDFPS, sensorId: " + sensor.id);
- continue;
- }
- try {
- sensor.startSensor();
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to start prepared client, sensor: " + sensor, e);
- }
- }
+ private void startAllPreparedFingerprintSensors() {
+ startAllPreparedSensors(sensor -> sensor.modality == TYPE_FINGERPRINT);
}
- private void startPreparedUdfpsSensors() {
+ private void startAllPreparedSensors(Function<BiometricSensor, Boolean> filter) {
for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
- if (isUdfpsSensor(sensor)) {
+ if (filter.apply(sensor)) {
try {
+ if (DEBUG) {
+ Slog.v(TAG, "Starting sensor: " + sensor.id);
+ }
sensor.startSensor();
} catch (RemoteException e) {
- Slog.e(TAG, "Unable to start UDFPS sensor: " + sensor, e);
+ Slog.e(TAG, "Unable to start prepared client, sensor: " + sensor, e);
}
}
}
}
+ private void cancelAllFingerprintSensors() {
+ cancelAllSensors(sensor -> sensor.modality == TYPE_FINGERPRINT);
+ }
+
private void cancelAllSensors() {
+ cancelAllSensors(sensor -> true);
+ }
+
+ private void cancelAllSensors(Function<BiometricSensor, Boolean> filter) {
// TODO: For multiple modalities, send a single ERROR_CANCELED only when all
// drivers have canceled authentication. We'd probably have to add a state for
// STATE_CANCELING for when we're waiting for final ERROR_CANCELED before
// sending the final error callback to the application.
for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
try {
- sensor.goToStateCancelling(mToken, mOpPackageName);
+ if (filter.apply(sensor)) {
+ if (DEBUG) {
+ Slog.v(TAG, "Canceling sensor: " + sensor.id);
+ }
+ sensor.goToStateCancelling(mToken, mOpPackageName);
+ }
} catch (RemoteException e) {
Slog.e(TAG, "Unable to cancel authentication");
}
@@ -374,16 +417,20 @@
mPromptInfo.setAuthenticators(authenticators);
mState = STATE_SHOWING_DEVICE_CREDENTIAL;
+ mMultiSensorMode = BIOMETRIC_MULTI_SENSOR_DEFAULT;
+ mMultiSensorState = MULTI_SENSOR_STATE_UNKNOWN;
+ mSensors = new int[0];
mStatusBarService.showAuthenticationDialog(
mPromptInfo,
mSysuiReceiver,
- new int[0] /* sensorIds */,
+ mSensors /* sensorIds */,
true /* credentialAllowed */,
false /* requireConfirmation */,
mUserId,
mOpPackageName,
- mOperationId);
+ mOperationId,
+ mMultiSensorMode);
} else {
mClientReceiver.onError(modality, error, vendorCode);
return true;
@@ -406,6 +453,10 @@
// a round trip to SystemUI.
mClientReceiver.onError(modality, error, vendorCode);
return true;
+ } else if (shouldErrorTriggerMultiSensorTransition()) {
+ // wait for the UI to signal when modality should switch
+ mMultiSensorState = MULTI_SENSOR_STATE_SWITCHING;
+ Slog.d(TAG, "onErrorReceived: waiting for modality switch callback");
} else {
mState = STATE_ERROR_PENDING_SYSUI;
mStatusBarService.onBiometricError(modality, error, vendorCode);
@@ -472,8 +523,36 @@
mState = STATE_AUTH_STARTED_UI_SHOWING;
- // For UDFPS devices, we can now start the sensor.
- startPreparedUdfpsSensors();
+ if (mMultiSensorMode == BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT) {
+ mMultiSensorState = MULTI_SENSOR_STATE_FACE_SCANNING;
+ } else {
+ startFingerprintSensorsNow();
+ }
+ }
+
+ // call anytime after onDialogAnimatedIn() to indicate it's appropriate to start the
+ // fingerprint sensor (i.e. face auth has failed or is not available)
+ void onStartFingerprint() {
+ if (mMultiSensorMode != BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT) {
+ Slog.e(TAG, "onStartFingerprint, unexpected mode: " + mMultiSensorMode);
+ return;
+ }
+
+ if (mState != STATE_AUTH_STARTED
+ && mState != STATE_AUTH_STARTED_UI_SHOWING
+ && mState != STATE_AUTH_PAUSED) {
+ Slog.e(TAG, "onStartFingerprint, unexpected state: " + mState);
+ return;
+ }
+
+ mMultiSensorState = MULTI_SENSOR_STATE_FP_SCANNING;
+ startFingerprintSensorsNow();
+ }
+
+ // unguarded helper for the above methods only
+ private void startFingerprintSensorsNow() {
+ startAllPreparedFingerprintSensors();
+ mState = STATE_AUTH_STARTED_UI_SHOWING;
}
void onTryAgainPressed() {
@@ -613,6 +692,7 @@
+ ", IsCrypto: " + isCrypto()
+ ", Action: " + BiometricsProtoEnums.ACTION_AUTHENTICATE
+ ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT
+ + ", Reason: " + reason
+ ", Error: " + error
+ ", Latency: " + latency);
}
@@ -652,6 +732,7 @@
}
mClientReceiver.onAuthenticationSucceeded(
Utils.getAuthenticationTypeForResult(reason));
+ cancelBiometricOnly();
break;
case BiometricPrompt.DISMISSED_REASON_NEGATIVE:
@@ -729,6 +810,12 @@
private void cancelBiometricOnly() {
if (mState == STATE_AUTH_STARTED || mState == STATE_AUTH_STARTED_UI_SHOWING) {
cancelAllSensors();
+ } else if (mMultiSensorMode == BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT) {
+ cancelAllFingerprintSensors();
+ } else {
+ if (DEBUG) {
+ Slog.v(TAG, "nothing to cancel - wrong state: " + mState);
+ }
}
}
@@ -808,6 +895,32 @@
}
}
+ private boolean shouldErrorTriggerMultiSensorTransition() {
+ if (mMultiSensorMode == BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT) {
+ return mMultiSensorState == MULTI_SENSOR_STATE_FACE_SCANNING;
+ }
+ return false;
+ }
+
+ @BiometricMultiSensorMode
+ private static int getMultiSensorModeForNewSession(Collection<BiometricSensor> sensors) {
+ boolean hasFace = false;
+ boolean hasFingerprint = false;
+
+ for (BiometricSensor sensor: sensors) {
+ if (sensor.modality == TYPE_FACE) {
+ hasFace = true;
+ } else if (sensor.modality == TYPE_FINGERPRINT) {
+ hasFingerprint = true;
+ }
+ }
+
+ if (hasFace && hasFingerprint) {
+ return BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT;
+ }
+ return BIOMETRIC_MULTI_SENSOR_DEFAULT;
+ }
+
@Override
public String toString() {
return "State: " + mState
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index a546a60..e8e25f1 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -104,6 +104,7 @@
private static final int MSG_ON_SYSTEM_EVENT = 13;
private static final int MSG_CLIENT_DIED = 14;
private static final int MSG_ON_DIALOG_ANIMATED_IN = 15;
+ private static final int MSG_ON_START_FINGERPRINT_NOW = 16;
private final Injector mInjector;
private final DevicePolicyManager mDevicePolicyManager;
@@ -237,6 +238,11 @@
break;
}
+ case MSG_ON_START_FINGERPRINT_NOW: {
+ handleOnStartFingerprintNow();
+ break;
+ }
+
default:
Slog.e(TAG, "Unknown message: " + msg);
break;
@@ -618,6 +624,11 @@
public void onDialogAnimatedIn() {
mHandler.obtainMessage(MSG_ON_DIALOG_ANIMATED_IN).sendToTarget();
}
+
+ @Override
+ public void onStartFingerprintNow() {
+ mHandler.obtainMessage(MSG_ON_START_FINGERPRINT_NOW).sendToTarget();
+ }
};
private final AuthSession.ClientDeathReceiver mClientDeathReceiver = () -> {
@@ -1284,6 +1295,7 @@
}
private void handleOnDialogAnimatedIn() {
+ Slog.d(TAG, "handleOnDialogAnimatedIn");
if (mCurrentAuthSession == null) {
Slog.e(TAG, "handleOnDialogAnimatedIn: AuthSession is null");
return;
@@ -1292,6 +1304,16 @@
mCurrentAuthSession.onDialogAnimatedIn();
}
+ private void handleOnStartFingerprintNow() {
+ Slog.d(TAG, "handleOnStartFingerprintNow");
+ if (mCurrentAuthSession == null) {
+ Slog.e(TAG, "handleOnStartFingerprintNow: AuthSession is null");
+ return;
+ }
+
+ mCurrentAuthSession.onStartFingerprint();
+ }
+
/**
* Invoked when each service has notified that its client is ready to be started. When
* all biometrics are ready, this invokes the SystemUI dialog through StatusBar.
@@ -1310,7 +1332,6 @@
private void handleAuthenticate(IBinder token, long operationId, int userId,
IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) {
-
mHandler.post(() -> {
try {
final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager,
diff --git a/services/core/java/com/android/server/biometrics/BiometricStrengthController.java b/services/core/java/com/android/server/biometrics/BiometricStrengthController.java
index 270621c..768dc36 100644
--- a/services/core/java/com/android/server/biometrics/BiometricStrengthController.java
+++ b/services/core/java/com/android/server/biometrics/BiometricStrengthController.java
@@ -48,16 +48,9 @@
*/
private static final String KEY_BIOMETRIC_STRENGTHS = "biometric_strengths";
- /**
- * Default (no-op) value of the flag KEY_BIOMETRIC_STRENGTHS
- */
- public static final String DEFAULT_BIOMETRIC_STRENGTHS = null;
-
private DeviceConfig.OnPropertiesChangedListener mDeviceConfigListener = properties -> {
- for (String name : properties.getKeyset()) {
- if (KEY_BIOMETRIC_STRENGTHS.equals(name)) {
- updateStrengths();
- }
+ if (properties.getKeyset().contains(KEY_BIOMETRIC_STRENGTHS)) {
+ updateStrengths();
}
};
@@ -75,7 +68,17 @@
* has been changed.
*/
public void updateStrengths() {
- final Map<Integer, Integer> idToStrength = getIdToStrengthMap();
+ final String newValue = DeviceConfig.getString(DeviceConfig.NAMESPACE_BIOMETRICS,
+ KEY_BIOMETRIC_STRENGTHS, "null");
+ if ("null".equals(newValue) || newValue.isEmpty()) {
+ revertStrengths();
+ } else {
+ updateStrengths(newValue);
+ }
+ }
+
+ private void updateStrengths(String flags) {
+ final Map<Integer, Integer> idToStrength = getIdToStrengthMap(flags);
if (idToStrength == null) {
return;
}
@@ -91,12 +94,18 @@
}
}
+ private void revertStrengths() {
+ for (BiometricSensor sensor : mService.mSensors) {
+ Slog.d(TAG, "updateStrengths: revert sensorId=" + sensor.id + " to oemStrength="
+ + sensor.oemStrength);
+ sensor.updateStrength(sensor.oemStrength);
+ }
+ }
+
/**
* @return a map of <ID, Strength>
*/
- private Map<Integer, Integer> getIdToStrengthMap() {
- final String flags = DeviceConfig.getString(DeviceConfig.NAMESPACE_BIOMETRICS,
- KEY_BIOMETRIC_STRENGTHS, DEFAULT_BIOMETRIC_STRENGTHS);
+ private static Map<Integer, Integer> getIdToStrengthMap(String flags) {
if (flags == null || flags.isEmpty()) {
Slog.d(TAG, "Flags are null or empty");
return null;
diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
index 6482a2e..99f4e2c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
@@ -82,7 +82,20 @@
private final int mCookie;
boolean mAlreadyDone;
- @NonNull protected Callback mCallback;
+ // Use an empty callback by default since delayed operations can receive events
+ // before they are started and cause NPE in subclasses that access this field directly.
+ @NonNull protected Callback mCallback = new Callback() {
+ @Override
+ public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
+ Slog.e(TAG, "mCallback onClientStarted: called before set (should not happen)");
+ }
+
+ @Override
+ public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
+ boolean success) {
+ Slog.e(TAG, "mCallback onClientFinished: called before set (should not happen)");
+ }
+ };
/**
* @return A ClientMonitorEnum constant defined in biometrics.proto
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlConversionUtils.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlConversionUtils.java
index 6ad4308..573c20f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlConversionUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlConversionUtils.java
@@ -120,10 +120,13 @@
return BiometricFaceConstants.FACE_ACQUIRED_SENSOR_DIRTY;
case AcquiredInfo.VENDOR:
return BiometricFaceConstants.FACE_ACQUIRED_VENDOR;
- case AcquiredInfo.UNKNOWN:
case AcquiredInfo.FIRST_FRAME_RECEIVED:
+ return BiometricFaceConstants.FACE_ACQUIRED_FIRST_FRAME_RECEIVED;
case AcquiredInfo.DARK_GLASSES_DETECTED:
+ return BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED;
case AcquiredInfo.MOUTH_COVERING_DETECTED:
+ return BiometricFaceConstants.FACE_ACQUIRED_MOUTH_COVERING_DETECTED;
+ case AcquiredInfo.UNKNOWN:
default:
return BiometricFaceConstants.FACE_ACQUIRED_UNKNOWN;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index 0e6a0f7..2f71f44 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -148,6 +148,16 @@
}
@Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
+
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
+
+ @Override
public void onChallengeGenerated(long challenge) {
mHandler.post(() -> {
final BaseClientMonitor client = mScheduler.getCurrentClient();
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java
index bf3f7b4..525e508 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java
@@ -35,6 +35,16 @@
private static final String TAG = "face.aidl.TestHal";
@Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
+
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
+
+ @Override
public SensorProps[] getSensorProps() {
Slog.w(TAG, "getSensorProps");
return new SensorProps[0];
@@ -46,6 +56,16 @@
return new ISession.Stub() {
@Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
+
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
+
+ @Override
public void generateChallenge() throws RemoteException {
Slog.w(TAG, "generateChallenge");
cb.onChallengeGenerated(0L);
@@ -71,6 +91,14 @@
public void cancel() throws RemoteException {
cb.onError(Error.CANCELED, 0 /* vendorCode */);
}
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
};
}
@@ -82,6 +110,14 @@
public void cancel() throws RemoteException {
cb.onError(Error.CANCELED, 0 /* vendorCode */);
}
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
};
}
@@ -93,6 +129,14 @@
public void cancel() throws RemoteException {
cb.onError(Error.CANCELED, 0 /* vendorCode */);
}
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
};
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index 10137b5..b3b818f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -151,6 +151,16 @@
}
@Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
+
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
+
+ @Override
public void onChallengeGenerated(long challenge) {
mHandler.post(() -> {
final BaseClientMonitor client = mScheduler.getCurrentClient();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java
index abc3597..e771923 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java
@@ -33,6 +33,16 @@
private static final String TAG = "fingerprint.aidl.TestHal";
@Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
+
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
+
+ @Override
public SensorProps[] getSensorProps() {
Slog.w(TAG, "getSensorProps");
return new SensorProps[0];
@@ -44,6 +54,16 @@
return new ISession.Stub() {
@Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
+
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
+
+ @Override
public void generateChallenge() throws RemoteException {
Slog.w(TAG, "generateChallenge");
cb.onChallengeGenerated(0L);
@@ -63,6 +83,14 @@
public void cancel() throws RemoteException {
cb.onError(Error.CANCELED, 0 /* vendorCode */);
}
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
};
}
@@ -74,6 +102,14 @@
public void cancel() throws RemoteException {
cb.onError(Error.CANCELED, 0 /* vendorCode */);
}
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
};
}
@@ -85,6 +121,14 @@
public void cancel() throws RemoteException {
cb.onError(Error.CANCELED, 0 /* vendorCode */);
}
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
};
}
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index d29a0c7..0f97b90 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -26,9 +26,7 @@
import android.compat.annotation.Disabled;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.Overridable;
-import android.content.Context;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
import com.android.internal.compat.AndroidBuildClassifier;
import com.android.internal.compat.CompatibilityChangeInfo;
@@ -161,15 +159,17 @@
*
* @param packageName Package name to tentatively enable the change for.
* @param override The package override to be set
+ * @param allowedState Whether the override is allowed.
+ * @param versionCode The version code of the package.
*/
void addPackageOverride(String packageName, PackageOverride override,
- OverrideAllowedState allowedState, Context context) {
+ OverrideAllowedState allowedState, @Nullable Long versionCode) {
if (getLoggingOnly()) {
throw new IllegalArgumentException(
"Can't add overrides for a logging only change " + toString());
}
mRawOverrides.put(packageName, override);
- recheckOverride(packageName, allowedState, context);
+ recheckOverride(packageName, allowedState, versionCode);
}
/**
@@ -179,32 +179,24 @@
* overrides, check if they need to be demoted to deferred.</p>
*
* @param packageName Package name to apply deferred overrides for.
- * @param allowed Whether the override is allowed.
+ * @param allowedState Whether the override is allowed.
+ * @param versionCode The version code of the package.
*
* @return {@code true} if the recheck yielded a result that requires invalidating caches
* (a deferred override was consolidated or a regular override was removed).
*/
boolean recheckOverride(String packageName, OverrideAllowedState allowedState,
- Context context) {
+ @Nullable Long versionCode) {
boolean allowed = (allowedState.state == OverrideAllowedState.ALLOWED);
- Long version = null;
- try {
- ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(
- packageName, 0);
- version = applicationInfo.longVersionCode;
- } catch (PackageManager.NameNotFoundException e) {
- // Do nothing
- }
-
// If the app is not installed or no longer has raw overrides, evaluate to false
- if (version == null || !hasRawOverride(packageName) || !allowed) {
+ if (versionCode == null || !hasRawOverride(packageName) || !allowed) {
removePackageOverrideInternal(packageName);
return false;
}
// Evaluate the override based on its version
- int overrideValue = mRawOverrides.get(packageName).evaluate(version);
+ int overrideValue = mRawOverrides.get(packageName).evaluate(versionCode);
switch (overrideValue) {
case VALUE_UNDEFINED:
removePackageOverrideInternal(packageName);
@@ -229,11 +221,13 @@
* <p>Note, this method is not thread safe so callers must ensure thread safety.
*
* @param pname Package name to reset to defaults for.
+ * @param allowedState Whether the override is allowed.
+ * @param versionCode The version code of the package.
*/
boolean removePackageOverride(String pname, OverrideAllowedState allowedState,
- Context context) {
+ @Nullable Long versionCode) {
if (mRawOverrides.remove(pname) != null) {
- recheckOverride(pname, allowedState, context);
+ recheckOverride(pname, allowedState, versionCode);
return true;
}
return false;
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 9247568..909ed11 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -16,11 +16,13 @@
package com.android.server.compat;
+import android.annotation.Nullable;
import android.app.compat.ChangeIdStateCache;
import android.app.compat.PackageOverride;
import android.compat.Compatibility.ChangeConfig;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.os.Environment;
import android.text.TextUtils;
import android.util.LongArray;
@@ -51,7 +53,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -249,6 +250,7 @@
OverrideAllowedState allowedState =
mOverrideValidator.getOverrideAllowedState(changeId, packageName);
allowedState.enforce(changeId, packageName);
+ Long versionCode = getVersionCodeOrNull(packageName);
synchronized (mChanges) {
CompatChange c = mChanges.get(changeId);
if (c == null) {
@@ -256,7 +258,7 @@
c = new CompatChange(changeId);
addChange(c);
}
- c.addPackageOverride(packageName, overrides, allowedState, mContext);
+ c.addPackageOverride(packageName, overrides, allowedState, versionCode);
invalidateCache();
}
return alreadyKnown;
@@ -336,6 +338,7 @@
* It does not invalidate the cache nor save the overrides.
*/
private boolean removeOverrideUnsafe(long changeId, String packageName) {
+ Long versionCode = getVersionCodeOrNull(packageName);
synchronized (mChanges) {
CompatChange c = mChanges.get(changeId);
if (c != null) {
@@ -343,7 +346,7 @@
mOverrideValidator.getOverrideAllowedState(changeId, packageName);
if (c.hasPackageOverride(packageName)) {
allowedState.enforce(changeId, packageName);
- c.removePackageOverride(packageName, allowedState, mContext);
+ c.removePackageOverride(packageName, allowedState, versionCode);
invalidateCache();
return true;
}
@@ -653,26 +656,33 @@
* Rechecks all the existing overrides for a package.
*/
void recheckOverrides(String packageName) {
- // Local cache of compat changes. Holding a lock on mChanges for the whole duration of the
- // method will cause a deadlock.
- List<CompatChange> changes;
+ Long versionCode = getVersionCodeOrNull(packageName);
synchronized (mChanges) {
- changes = new ArrayList<>(mChanges.size());
+ boolean shouldInvalidateCache = false;
for (int idx = 0; idx < mChanges.size(); ++idx) {
- changes.add(mChanges.valueAt(idx));
+ CompatChange c = mChanges.valueAt(idx);
+ if (!c.hasPackageOverride(packageName)) {
+ continue;
+ }
+ OverrideAllowedState allowedState =
+ mOverrideValidator.getOverrideAllowedStateForRecheck(c.getId(),
+ packageName);
+ shouldInvalidateCache |= c.recheckOverride(packageName, allowedState, versionCode);
+ }
+ if (shouldInvalidateCache) {
+ invalidateCache();
}
}
- boolean shouldInvalidateCache = false;
- for (CompatChange c: changes) {
- if (!c.hasPackageOverride(packageName)) {
- continue;
- }
- OverrideAllowedState allowedState =
- mOverrideValidator.getOverrideAllowedStateForRecheck(c.getId(), packageName);
- shouldInvalidateCache |= c.recheckOverride(packageName, allowedState, mContext);
- }
- if (shouldInvalidateCache) {
- invalidateCache();
+ }
+
+ @Nullable
+ private Long getVersionCodeOrNull(String packageName) {
+ try {
+ ApplicationInfo applicationInfo = mContext.getPackageManager().getApplicationInfo(
+ packageName, 0);
+ return applicationInfo.longVersionCode;
+ } catch (PackageManager.NameNotFoundException e) {
+ return null;
}
}
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index 47eb3eb..a0a596d 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -18,10 +18,16 @@
import static android.net.ConnectivityManager.NetworkCallback;
import static android.net.ipsec.ike.SaProposal.DH_GROUP_2048_BIT_MODP;
+import static android.net.ipsec.ike.SaProposal.DH_GROUP_3072_BIT_MODP;
+import static android.net.ipsec.ike.SaProposal.DH_GROUP_4096_BIT_MODP;
+import static android.net.ipsec.ike.SaProposal.DH_GROUP_CURVE_25519;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CBC;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_CTR;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16;
import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8;
+import static android.net.ipsec.ike.SaProposal.ENCRYPTION_ALGORITHM_CHACHA20_POLY1305;
+import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_CMAC_96;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_AES_XCBC_96;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128;
import static android.net.ipsec.ike.SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_384_192;
@@ -29,8 +35,13 @@
import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_128;
import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_192;
import static android.net.ipsec.ike.SaProposal.KEY_LEN_AES_256;
+import static android.net.ipsec.ike.SaProposal.KEY_LEN_UNUSED;
+import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_CMAC;
import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC;
import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_HMAC_SHA1;
+import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256;
+import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_384;
+import static android.net.ipsec.ike.SaProposal.PSEUDORANDOM_FUNCTION_SHA2_512;
import android.annotation.NonNull;
import android.content.Context;
@@ -84,12 +95,6 @@
public class VpnIkev2Utils {
private static final String TAG = VpnIkev2Utils.class.getSimpleName();
- // TODO: Use IKE library exposed constants when @SystemApi is updated.
- /** IANA-defined 3072 group for use in IKEv2 */
- private static final int DH_GROUP_3072_BIT_MODP = 15;
- /** IANA-defined 4096 group for use in IKEv2 */
- private static final int DH_GROUP_4096_BIT_MODP = 16;
-
static IkeSessionParams buildIkeSessionParams(
@NonNull Context context, @NonNull Ikev2VpnProfile profile, @NonNull Network network) {
final IkeIdentification localId = parseIkeIdentification(profile.getUserIdentity());
@@ -154,12 +159,14 @@
// TODO: Add ability to filter this when IKEv2 API is made Public API
final List<IkeSaProposal> proposals = new ArrayList<>();
- // Encryption Algorithms: Currently only AES_CBC is supported.
final IkeSaProposal.Builder normalModeBuilder = new IkeSaProposal.Builder();
- // Currently only AES_CBC is supported.
+ // Add normal mode encryption algorithms
+ normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CTR, KEY_LEN_AES_256);
normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256);
+ normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CTR, KEY_LEN_AES_192);
normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_192);
+ normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CTR, KEY_LEN_AES_128);
normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128);
// Authentication/Integrity Algorithms
@@ -167,9 +174,11 @@
normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_384_192);
normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128);
normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_AES_XCBC_96);
+ normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_AES_CMAC_96);
// Add AEAD options
final IkeSaProposal.Builder aeadBuilder = new IkeSaProposal.Builder();
+ aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_CHACHA20_POLY1305, KEY_LEN_UNUSED);
aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256);
aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_256);
aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_256);
@@ -183,9 +192,17 @@
// Add dh, prf for both builders
for (final IkeSaProposal.Builder builder : Arrays.asList(normalModeBuilder, aeadBuilder)) {
builder.addDhGroup(DH_GROUP_4096_BIT_MODP);
+
+ // Curve25519 has the same security strength as MODP 3072 and cost less bytes
+ builder.addDhGroup(DH_GROUP_CURVE_25519);
+
builder.addDhGroup(DH_GROUP_3072_BIT_MODP);
builder.addDhGroup(DH_GROUP_2048_BIT_MODP);
+ builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_SHA2_512);
+ builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_SHA2_384);
+ builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_SHA2_256);
builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_XCBC);
+ builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_AES128_CMAC);
builder.addPseudorandomFunction(PSEUDORANDOM_FUNCTION_HMAC_SHA1);
}
@@ -198,15 +215,23 @@
private static List<ChildSaProposal> getChildSaProposals(List<String> allowedAlgorithms) {
final List<ChildSaProposal> proposals = new ArrayList<>();
+ final List<Integer> aesKeyLenOptions =
+ Arrays.asList(KEY_LEN_AES_256, KEY_LEN_AES_192, KEY_LEN_AES_128);
+
// Add non-AEAD options
if (Ikev2VpnProfile.hasNormalModeAlgorithms(allowedAlgorithms)) {
final ChildSaProposal.Builder normalModeBuilder = new ChildSaProposal.Builder();
// Encryption Algorithms:
- // AES-CBC is currently the only supported encryption algorithm.
- normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_256);
- normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_192);
- normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, KEY_LEN_AES_128);
+ // AES-CBC and AES_CTR are currently the only supported encryption algorithms.
+ for (int len : aesKeyLenOptions) {
+ if (allowedAlgorithms.contains(IpSecAlgorithm.CRYPT_AES_CTR)) {
+ normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CTR, len);
+ }
+ if (allowedAlgorithms.contains(IpSecAlgorithm.CRYPT_AES_CBC)) {
+ normalModeBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_CBC, len);
+ }
+ }
// Authentication/Integrity Algorithms:
// Guaranteed by Ikev2VpnProfile constructor to contain at least one of these.
@@ -219,6 +244,12 @@
if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_HMAC_SHA256)) {
normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_HMAC_SHA2_256_128);
}
+ if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_AES_XCBC)) {
+ normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_AES_XCBC_96);
+ }
+ if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_AES_CMAC)) {
+ normalModeBuilder.addIntegrityAlgorithm(INTEGRITY_ALGORITHM_AES_CMAC_96);
+ }
ChildSaProposal proposal = normalModeBuilder.build();
if (proposal.getIntegrityAlgorithms().isEmpty()) {
@@ -233,16 +264,27 @@
if (Ikev2VpnProfile.hasAeadAlgorithms(allowedAlgorithms)) {
final ChildSaProposal.Builder aeadBuilder = new ChildSaProposal.Builder();
- // AES-GCM is currently the only supported AEAD algorithm
- aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256);
- aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_256);
- aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_256);
- aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_192);
- aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_192);
- aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_192);
- aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_128);
- aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_128);
- aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_128);
+ if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305)) {
+ aeadBuilder.addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_CHACHA20_POLY1305, KEY_LEN_UNUSED);
+ }
+ if (allowedAlgorithms.contains(IpSecAlgorithm.AUTH_CRYPT_AES_GCM)) {
+ aeadBuilder.addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_256);
+ aeadBuilder.addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_256);
+ aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_256);
+ aeadBuilder.addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_192);
+ aeadBuilder.addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_192);
+ aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_192);
+ aeadBuilder.addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_AES_GCM_16, KEY_LEN_AES_128);
+ aeadBuilder.addEncryptionAlgorithm(
+ ENCRYPTION_ALGORITHM_AES_GCM_12, KEY_LEN_AES_128);
+ aeadBuilder.addEncryptionAlgorithm(ENCRYPTION_ALGORITHM_AES_GCM_8, KEY_LEN_AES_128);
+ }
proposals.add(aeadBuilder.build());
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 61107b2..9fcc9a1 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -2479,15 +2479,12 @@
Slog.d(TAG, "setLightStateInternal device " + deviceId + " light " + light
+ "lightState " + lightState);
}
- if (light.getType() == Light.LIGHT_TYPE_INPUT_PLAYER_ID) {
+ if (light.getType() == Light.LIGHT_TYPE_PLAYER_ID) {
nativeSetLightPlayerId(mPtr, deviceId, light.getId(), lightState.getPlayerId());
- } else if (light.getType() == Light.LIGHT_TYPE_INPUT_SINGLE
- || light.getType() == Light.LIGHT_TYPE_INPUT_RGB) {
+ } else {
// Set ARGB format color to input device light
// Refer to https://developer.android.com/reference/kotlin/android/graphics/Color
nativeSetLightColor(mPtr, deviceId, light.getId(), lightState.getColor());
- } else {
- Slog.e(TAG, "setLightStates for unsupported light type " + light.getType());
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 94e669a..a0004a0 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -89,8 +89,6 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
-import android.graphics.Matrix;
-import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.InputManagerInternal;
import android.inputmethodservice.InputMethodService;
import android.media.AudioManagerInternal;
@@ -126,10 +124,8 @@
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
-import android.util.SparseArray;
import android.util.imetracing.ImeTracing;
import android.util.proto.ProtoOutputStream;
-import android.view.DisplayInfo;
import android.view.IWindowManager;
import android.view.InputChannel;
import android.view.View;
@@ -313,7 +309,6 @@
final WindowManagerInternal mWindowManagerInternal;
final PackageManagerInternal mPackageManagerInternal;
final InputManagerInternal mInputManagerInternal;
- private final DisplayManagerInternal mDisplayManagerInternal;
final HandlerCaller mCaller;
final boolean mHasFeature;
private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
@@ -453,32 +448,6 @@
@GuardedBy("mMethodMap")
final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
- private static final class ActivityViewInfo {
- /**
- * {@link ClientState} where {@link android.app.ActivityView} is running.
- */
- private final ClientState mParentClient;
- /**
- * {@link Matrix} to convert screen coordinates in the embedded virtual display to
- * screen coordinates where {@link #mParentClient} exists.
- */
- private final Matrix mMatrix;
-
- ActivityViewInfo(ClientState parentClient, Matrix matrix) {
- mParentClient = parentClient;
- mMatrix = matrix;
- }
- }
-
- /**
- * A mapping table from virtual display IDs created for {@link android.app.ActivityView}
- * to its parent IME client where {@link android.app.ActivityView} is running.
- *
- * <p>Note: this can be used only for virtual display IDs created by
- * {@link android.app.ActivityView}.</p>
- */
- private SparseArray<ActivityViewInfo> mActivityViewDisplayIdToParentMap = new SparseArray<>();
-
/**
* Set once the system is ready to run third party code.
*/
@@ -564,16 +533,6 @@
EditorInfo mCurAttribute;
/**
- * A special {@link Matrix} to convert virtual screen coordinates to the IME target display
- * coordinates.
- *
- * <p>Used only while the IME client is running in a virtual display inside
- * {@link android.app.ActivityView}. {@code null} otherwise.</p>
- */
- @Nullable
- private Matrix mCurActivityViewToScreenMatrix = null;
-
- /**
* Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
* connected to or in the process of connecting to.
*
@@ -1648,7 +1607,6 @@
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
- mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mImeDisplayValidator = displayId -> mWindowManagerInternal.getDisplayImePolicy(displayId);
mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
@Override
@@ -2262,15 +2220,6 @@
if (cs != null) {
client.asBinder().unlinkToDeath(cs.clientDeathRecipient, 0);
clearClientSessionLocked(cs);
-
- final int numItems = mActivityViewDisplayIdToParentMap.size();
- for (int i = numItems - 1; i >= 0; --i) {
- final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.valueAt(i);
- if (info.mParentClient == cs) {
- mActivityViewDisplayIdToParentMap.removeAt(i);
- }
- }
-
if (mCurClient == cs) {
hideCurrentInputLocked(
mCurFocusedWindow, 0, null, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
@@ -2282,7 +2231,6 @@
}
}
mCurClient = null;
- mCurActivityViewToScreenMatrix = null;
}
if (mCurFocusedWindowClient == cs) {
mCurFocusedWindowClient = null;
@@ -2318,7 +2266,6 @@
MSG_UNBIND_CLIENT, mCurSeq, unbindClientReason, mCurClient.client));
mCurClient.sessionRequested = false;
mCurClient = null;
- mCurActivityViewToScreenMatrix = null;
mMenuController.hideInputMethodMenuLocked();
}
@@ -2386,31 +2333,7 @@
curInputMethodInfo != null && curInputMethodInfo.suppressesSpellChecker();
return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION,
session.session, (session.channel != null ? session.channel.dup() : null),
- mCurId, mCurSeq, mCurActivityViewToScreenMatrix, suppressesSpellChecker);
- }
-
- @Nullable
- private Matrix getActivityViewToScreenMatrixLocked(int clientDisplayId, int imeDisplayId) {
- if (clientDisplayId == imeDisplayId) {
- return null;
- }
- int displayId = clientDisplayId;
- Matrix matrix = null;
- while (true) {
- final ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(displayId);
- if (info == null) {
- return null;
- }
- if (matrix == null) {
- matrix = new Matrix(info.mMatrix);
- } else {
- matrix.postConcat(info.mMatrix);
- }
- if (info.mParentClient.selfReportedDisplayId == imeDisplayId) {
- return matrix;
- }
- displayId = info.mParentClient.selfReportedDisplayId;
- }
+ mCurId, mCurSeq, suppressesSpellChecker);
}
@GuardedBy("mMethodMap")
@@ -2428,7 +2351,7 @@
// party code.
return new InputBindResult(
InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY,
- null, null, mCurMethodId, mCurSeq, null, false);
+ null, null, mCurMethodId, mCurSeq, false);
}
if (!InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
@@ -2474,10 +2397,7 @@
if (mCurSeq <= 0) mCurSeq = 1;
mCurClient = cs;
mCurInputContext = inputContext;
- mCurActivityViewToScreenMatrix =
- getActivityViewToScreenMatrixLocked(cs.selfReportedDisplayId, displayIdToShowIme);
- if (cs.selfReportedDisplayId != displayIdToShowIme
- && mCurActivityViewToScreenMatrix == null) {
+ if (cs.selfReportedDisplayId != displayIdToShowIme) {
// CursorAnchorInfo API does not work as-is for cross-display scenario. Pretend that
// InputConnection#requestCursorUpdates() is not implemented in the application so that
// IMEs will always receive false from this API.
@@ -2504,7 +2424,7 @@
requestClientSessionLocked(cs);
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
- null, null, mCurId, mCurSeq, null, false);
+ null, null, mCurId, mCurSeq, false);
} else if (SystemClock.uptimeMillis()
< (mLastBindTime+TIME_TO_RECONNECT)) {
// In this case we have connected to the service, but
@@ -2516,7 +2436,7 @@
// to see if we can get back in touch with the service.
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
- null, null, mCurId, mCurSeq, null, false);
+ null, null, mCurId, mCurSeq, false);
} else {
EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME,
mCurMethodId, SystemClock.uptimeMillis()-mLastBindTime, 0);
@@ -2556,7 +2476,7 @@
}
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
- null, null, mCurId, mCurSeq, null, false);
+ null, null, mCurId, mCurSeq, false);
}
mCurIntent = null;
Slog.w(TAG, "Failure connecting to input method service: " + mCurIntent);
@@ -3550,7 +3470,7 @@
}
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
- null, null, null, -1, null, false);
+ null, null, null, -1, false);
}
mCurFocusedWindow = windowToken;
@@ -4046,98 +3966,6 @@
}
@Override
- public void reportActivityViewAsync(IInputMethodClient parentClient, int childDisplayId,
- float[] matrixValues) {
- try {
- final DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(childDisplayId);
- if (displayInfo == null) {
- throw new IllegalArgumentException(
- "Cannot find display for non-existent displayId: " + childDisplayId);
- }
- final int callingUid = Binder.getCallingUid();
- if (callingUid != displayInfo.ownerUid) {
- throw new SecurityException("The caller doesn't own the display.");
- }
-
- synchronized (mMethodMap) {
- final ClientState cs = mClients.get(parentClient.asBinder());
- if (cs == null) {
- return;
- }
-
- // null matrixValues means that the entry needs to be removed.
- if (matrixValues == null) {
- final ActivityViewInfo info =
- mActivityViewDisplayIdToParentMap.get(childDisplayId);
- if (info == null) {
- return;
- }
- if (info.mParentClient != cs) {
- throw new SecurityException("Only the owner client can clear"
- + " ActivityViewGeometry for display #" + childDisplayId);
- }
- mActivityViewDisplayIdToParentMap.remove(childDisplayId);
- return;
- }
-
- ActivityViewInfo info = mActivityViewDisplayIdToParentMap.get(childDisplayId);
- if (info != null && info.mParentClient != cs) {
- throw new InvalidParameterException("Display #" + childDisplayId
- + " is already registered by " + info.mParentClient);
- }
- if (info == null) {
- if (!mWindowManagerInternal.isUidAllowedOnDisplay(childDisplayId, cs.uid)) {
- throw new SecurityException(cs + " cannot access to display #"
- + childDisplayId);
- }
- info = new ActivityViewInfo(cs, new Matrix());
- mActivityViewDisplayIdToParentMap.put(childDisplayId, info);
- }
- info.mMatrix.setValues(matrixValues);
-
- if (mCurClient == null || mCurClient.curSession == null) {
- return;
- }
-
- Matrix matrix = null;
- int displayId = mCurClient.selfReportedDisplayId;
- boolean needToNotify = false;
- while (true) {
- needToNotify |= (displayId == childDisplayId);
- final ActivityViewInfo next = mActivityViewDisplayIdToParentMap.get(displayId);
- if (next == null) {
- break;
- }
- if (matrix == null) {
- matrix = new Matrix(next.mMatrix);
- } else {
- matrix.postConcat(next.mMatrix);
- }
- if (next.mParentClient.selfReportedDisplayId == mCurTokenDisplayId) {
- if (needToNotify) {
- final float[] values = new float[9];
- matrix.getValues(values);
- try {
- mCurClient.client.updateActivityViewToScreenMatrix(mCurSeq, values);
- } catch (RemoteException e) {
- }
- }
- break;
- }
- displayId = info.mParentClient.selfReportedDisplayId;
- }
- }
- } catch (Throwable t) {
- if (parentClient != null) {
- try {
- parentClient.throwExceptionFromSystem(t.toString());
- } catch (RemoteException e) {
- }
- }
- }
- }
-
- @Override
public void removeImeSurface(IVoidResultCallback resultCallback) {
CallbackUtils.onResult(resultCallback, () -> {
mContext.enforceCallingPermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW, null);
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index bbf4b71..9275c56 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1778,7 +1778,7 @@
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION,
null, null, data.mCurrentInputMethodInfo.getId(),
- clientInfo.mBindingSequence, null, false);
+ clientInfo.mBindingSequence, false);
case InputMethodClientState.READY_TO_SEND_FIRST_BIND_RESULT:
case InputMethodClientState.ALREADY_SENT_BIND_RESULT:
clientInfo.mBindingSequence++;
@@ -1800,7 +1800,7 @@
clientInfo.mInputMethodSession,
clientInfo.mWriteChannel.dup(),
data.mCurrentInputMethodInfo.getId(),
- clientInfo.mBindingSequence, null, false);
+ clientInfo.mBindingSequence, false);
case InputMethodClientState.UNREGISTERED:
Slog.e(TAG, "The client is already unregistered.");
return InputBindResult.INVALID_CLIENT;
@@ -1864,13 +1864,6 @@
@BinderThread
@Override
- public void reportActivityViewAsync(IInputMethodClient parentClient, int childDisplayId,
- float[] matrixValues) {
- reportNotSupported();
- }
-
- @BinderThread
- @Override
public void reportPerceptibleAsync(IBinder windowClient, boolean perceptible) {
reportNotSupported();
}
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 634b6aa..b9e97e8 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -76,6 +76,7 @@
import android.os.Build;
import android.os.Bundle;
import android.os.ICancellationSignal;
+import android.os.PackageTagsList;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
@@ -139,7 +140,6 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -271,7 +271,7 @@
mInjector.getSettingsHelper().addOnLocationEnabledChangedListener(
this::onLocationModeChanged);
- mInjector.getSettingsHelper().addOnIgnoreSettingsPackageWhitelistChangedListener(
+ mInjector.getSettingsHelper().addIgnoreSettingsAllowlistChangedListener(
() -> refreshAppOpsRestrictions(UserHandle.USER_ALL));
mInjector.getUserInfoHelper().addListener((userId, change) -> {
if (change == UserInfoHelper.UserListener.USER_STARTED) {
@@ -641,9 +641,8 @@
}
@Override
- public String[] getIgnoreSettingsWhitelist() {
- return mInjector.getSettingsHelper().getIgnoreSettingsPackageWhitelist().toArray(
- new String[0]);
+ public PackageTagsList getIgnoreSettingsAllowlist() {
+ return mInjector.getSettingsHelper().getIgnoreSettingsAllowlist();
}
@Nullable
@@ -1408,26 +1407,17 @@
boolean enabled = mInjector.getSettingsHelper().isLocationEnabled(userId);
- ArrayMap<String, String[]> allowedPackages = null;
+ PackageTagsList allowedPackages = null;
if (!enabled) {
- ArrayMap<String, ArraySet<String>> packages = new ArrayMap<>();
+ PackageTagsList.Builder builder = new PackageTagsList.Builder();
for (LocationProviderManager manager : mProviderManagers) {
CallerIdentity identity = manager.getIdentity();
if (identity != null) {
- packages.computeIfAbsent(identity.getPackageName(), k -> new ArraySet<>()).add(
- identity.getAttributionTag());
+ builder.add(identity.getPackageName(), identity.getAttributionTag());
}
}
- for (String packageName :
- mInjector.getSettingsHelper().getIgnoreSettingsPackageWhitelist()) {
- packages.computeIfAbsent(packageName, k -> new ArraySet<>()).clear();
- }
- packages.computeIfAbsent(mContext.getPackageName(), k -> new ArraySet<>()).clear();
-
- allowedPackages = new ArrayMap<>();
- for (Map.Entry<String, ArraySet<String>> entry : packages.entrySet()) {
- allowedPackages.put(entry.getKey(), entry.getValue().toArray(new String[0]));
- }
+ builder.add(mInjector.getSettingsHelper().getIgnoreSettingsAllowlist());
+ allowedPackages = builder.build();
}
AppOpsManager appOpsManager = Objects.requireNonNull(
diff --git a/services/core/java/com/android/server/location/injector/SettingsHelper.java b/services/core/java/com/android/server/location/injector/SettingsHelper.java
index 387ab77..148afa7 100644
--- a/services/core/java/com/android/server/location/injector/SettingsHelper.java
+++ b/services/core/java/com/android/server/location/injector/SettingsHelper.java
@@ -16,6 +16,7 @@
package com.android.server.location.injector;
+import android.os.PackageTagsList;
import android.util.IndentingPrintWriter;
import java.io.FileDescriptor;
@@ -146,21 +147,21 @@
GlobalSettingChangedListener listener);
/**
- * Retrieve the ignore settings package whitelist.
+ * Retrieve the ignore location settings package+tags allowlist setting.
*/
- public abstract Set<String> getIgnoreSettingsPackageWhitelist();
+ public abstract PackageTagsList getIgnoreSettingsAllowlist();
/**
* Add a listener for changes to the ignore settings package whitelist. Callbacks occur on an
* unspecified thread.
*/
- public abstract void addOnIgnoreSettingsPackageWhitelistChangedListener(
+ public abstract void addIgnoreSettingsAllowlistChangedListener(
GlobalSettingChangedListener listener);
/**
* Remove a listener for changes to the ignore settings package whitelist.
*/
- public abstract void removeOnIgnoreSettingsPackageWhitelistChangedListener(
+ public abstract void removeIgnoreSettingsAllowlistChangedListener(
GlobalSettingChangedListener listener);
/**
diff --git a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
index aa3e579..a34d722 100644
--- a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
+++ b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java
@@ -72,8 +72,11 @@
@Override
public boolean isInEmergency(long extensionTimeMs) {
+ boolean isInExtensionTime = mEmergencyCallEndRealtimeMs != Long.MIN_VALUE
+ && (SystemClock.elapsedRealtime() - mEmergencyCallEndRealtimeMs) < extensionTimeMs;
+
return mIsInEmergencyCall
- || ((SystemClock.elapsedRealtime() - mEmergencyCallEndRealtimeMs) < extensionTimeMs)
+ || isInExtensionTime
|| mTelephonyManager.getEmergencyCallbackMode()
|| mTelephonyManager.isInEmergencySmsMode();
}
diff --git a/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java b/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
index 632ed6e..c315da4 100644
--- a/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
+++ b/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
@@ -16,11 +16,11 @@
package com.android.server.location.injector;
+import static android.location.LocationDeviceConfig.IGNORE_SETTINGS_ALLOWLIST;
import static android.provider.Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING;
import static android.provider.Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS;
import static android.provider.Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST;
import static android.provider.Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS;
-import static android.provider.Settings.Global.LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST;
import static android.provider.Settings.Secure.LOCATION_COARSE_ACCURACY_M;
import static android.provider.Settings.Secure.LOCATION_MODE;
import static android.provider.Settings.Secure.LOCATION_MODE_OFF;
@@ -35,10 +35,13 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Handler;
+import android.os.PackageTagsList;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Log;
@@ -77,7 +80,7 @@
private final StringListCachedSecureSetting mLocationPackageBlacklist;
private final StringListCachedSecureSetting mLocationPackageWhitelist;
private final StringSetCachedGlobalSetting mBackgroundThrottlePackageWhitelist;
- private final StringSetCachedGlobalSetting mIgnoreSettingsPackageWhitelist;
+ private final PackageTagsListSetting mIgnoreSettingsPackageAllowlist;
public SystemSettingsHelper(Context context) {
mContext = context;
@@ -95,10 +98,9 @@
LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
() -> SystemConfig.getInstance().getAllowUnthrottledLocation(),
FgThread.getHandler());
- mIgnoreSettingsPackageWhitelist = new StringSetCachedGlobalSetting(context,
- LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST,
- () -> SystemConfig.getInstance().getAllowIgnoreLocationSettings(),
- FgThread.getHandler());
+ mIgnoreSettingsPackageAllowlist = new PackageTagsListSetting(
+ IGNORE_SETTINGS_ALLOWLIST,
+ () -> SystemConfig.getInstance().getAllowIgnoreLocationSettings());
}
/** Called when system is ready. */
@@ -108,20 +110,14 @@
mLocationPackageBlacklist.register();
mLocationPackageWhitelist.register();
mBackgroundThrottlePackageWhitelist.register();
- mIgnoreSettingsPackageWhitelist.register();
+ mIgnoreSettingsPackageAllowlist.register();
}
- /**
- * Retrieve if location is enabled or not.
- */
@Override
public boolean isLocationEnabled(int userId) {
return mLocationMode.getValueForUser(LOCATION_MODE_OFF, userId) != LOCATION_MODE_OFF;
}
- /**
- * Set location enabled for a user.
- */
@Override
public void setLocationEnabled(boolean enabled, int userId) {
final long identity = Binder.clearCallingIdentity();
@@ -138,53 +134,33 @@
}
}
- /**
- * Add a listener for changes to the location enabled setting. Callbacks occur on an unspecified
- * thread.
- */
@Override
public void addOnLocationEnabledChangedListener(UserSettingChangedListener listener) {
mLocationMode.addListener(listener);
}
- /**
- * Remove a listener for changes to the location enabled setting.
- */
@Override
public void removeOnLocationEnabledChangedListener(UserSettingChangedListener listener) {
mLocationMode.removeListener(listener);
}
- /**
- * Retrieve the background throttle interval.
- */
@Override
public long getBackgroundThrottleIntervalMs() {
return mBackgroundThrottleIntervalMs.getValue(DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS);
}
- /**
- * Add a listener for changes to the background throttle interval. Callbacks occur on an
- * unspecified thread.
- */
@Override
public void addOnBackgroundThrottleIntervalChangedListener(
GlobalSettingChangedListener listener) {
mBackgroundThrottleIntervalMs.addListener(listener);
}
- /**
- * Remove a listener for changes to the background throttle interval.
- */
@Override
public void removeOnBackgroundThrottleIntervalChangedListener(
GlobalSettingChangedListener listener) {
mBackgroundThrottleIntervalMs.removeListener(listener);
}
- /**
- * Check if the given package is blacklisted for location access.
- */
@Override
public boolean isLocationPackageBlacklisted(int userId, String packageName) {
List<String> locationPackageBlacklist = mLocationPackageBlacklist.getValueForUser(userId);
@@ -208,10 +184,6 @@
return false;
}
- /**
- * Add a listener for changes to the location package blacklist. Callbacks occur on an
- * unspecified thread.
- */
@Override
public void addOnLocationPackageBlacklistChangedListener(
UserSettingChangedListener listener) {
@@ -219,9 +191,6 @@
mLocationPackageWhitelist.addListener(listener);
}
- /**
- * Remove a listener for changes to the location package blacklist.
- */
@Override
public void removeOnLocationPackageBlacklistChangedListener(
UserSettingChangedListener listener) {
@@ -229,90 +198,57 @@
mLocationPackageWhitelist.removeListener(listener);
}
- /**
- * Retrieve the background throttle package whitelist.
- */
@Override
public Set<String> getBackgroundThrottlePackageWhitelist() {
return mBackgroundThrottlePackageWhitelist.getValue();
}
- /**
- * Add a listener for changes to the background throttle package whitelist. Callbacks occur on
- * an unspecified thread.
- */
@Override
public void addOnBackgroundThrottlePackageWhitelistChangedListener(
GlobalSettingChangedListener listener) {
mBackgroundThrottlePackageWhitelist.addListener(listener);
}
- /**
- * Remove a listener for changes to the background throttle package whitelist.
- */
@Override
public void removeOnBackgroundThrottlePackageWhitelistChangedListener(
GlobalSettingChangedListener listener) {
mBackgroundThrottlePackageWhitelist.removeListener(listener);
}
- /**
- * Retrieve the gnss measurements full tracking enabled setting.
- */
@Override
public boolean isGnssMeasurementsFullTrackingEnabled() {
return mGnssMeasurementFullTracking.getValue(false);
}
- /**
- * Add a listener for changes to the background throttle package whitelist. Callbacks occur on
- * an unspecified thread.
- */
@Override
public void addOnGnssMeasurementsFullTrackingEnabledChangedListener(
GlobalSettingChangedListener listener) {
mGnssMeasurementFullTracking.addListener(listener);
}
- /**
- * Remove a listener for changes to the background throttle package whitelist.
- */
@Override
public void removeOnGnssMeasurementsFullTrackingEnabledChangedListener(
GlobalSettingChangedListener listener) {
mGnssMeasurementFullTracking.removeListener(listener);
}
- /**
- * Retrieve the ignore settings package whitelist.
- */
@Override
- public Set<String> getIgnoreSettingsPackageWhitelist() {
- return mIgnoreSettingsPackageWhitelist.getValue();
+ public PackageTagsList getIgnoreSettingsAllowlist() {
+ return mIgnoreSettingsPackageAllowlist.getValue();
}
- /**
- * Add a listener for changes to the ignore settings package whitelist. Callbacks occur on an
- * unspecified thread.
- */
@Override
- public void addOnIgnoreSettingsPackageWhitelistChangedListener(
+ public void addIgnoreSettingsAllowlistChangedListener(
GlobalSettingChangedListener listener) {
- mIgnoreSettingsPackageWhitelist.addListener(listener);
+ mIgnoreSettingsPackageAllowlist.addListener(listener);
}
- /**
- * Remove a listener for changes to the ignore settings package whitelist.
- */
@Override
- public void removeOnIgnoreSettingsPackageWhitelistChangedListener(
+ public void removeIgnoreSettingsAllowlistChangedListener(
GlobalSettingChangedListener listener) {
- mIgnoreSettingsPackageWhitelist.removeListener(listener);
+ mIgnoreSettingsPackageAllowlist.removeListener(listener);
}
- /**
- * Retrieve the background throttling proximity alert interval.
- */
@Override
public long getBackgroundThrottleProximityAlertIntervalMs() {
final long identity = Binder.clearCallingIdentity();
@@ -325,10 +261,6 @@
}
}
- /**
- * Retrieve the accuracy for coarsening location, ie, the grid size used for snap-to-grid
- * coarsening.
- */
@Override
public float getCoarseLocationAccuracyM() {
final long identity = Binder.clearCallingIdentity();
@@ -344,9 +276,6 @@
}
}
- /**
- * Dump info for debugging.
- */
@Override
public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
int[] userIds;
@@ -428,13 +357,11 @@
ipw.decreaseIndent();
}
- Set<String> ignoreSettingsPackageWhitelist = mIgnoreSettingsPackageWhitelist.getValue();
- if (!ignoreSettingsPackageWhitelist.isEmpty()) {
+ PackageTagsList ignoreSettingsAllowlist = mIgnoreSettingsPackageAllowlist.getValue();
+ if (!ignoreSettingsAllowlist.isEmpty()) {
ipw.println("Bypass Allow Packages:");
ipw.increaseIndent();
- for (String packageName : ignoreSettingsPackageWhitelist) {
- ipw.println(packageName);
- }
+ ignoreSettingsAllowlist.dump(ipw);
ipw.decreaseIndent();
}
}
@@ -687,4 +614,139 @@
super.onChange(selfChange, uri, userId);
}
}
+
+ private static class DeviceConfigSetting implements DeviceConfig.OnPropertiesChangedListener {
+
+ protected final String mName;
+ private final CopyOnWriteArrayList<GlobalSettingChangedListener> mListeners;
+
+ @GuardedBy("this")
+ private boolean mRegistered;
+
+ DeviceConfigSetting(String name) {
+ mName = name;
+ mListeners = new CopyOnWriteArrayList<>();
+ }
+
+ protected synchronized boolean isRegistered() {
+ return mRegistered;
+ }
+
+ protected synchronized void register() {
+ if (mRegistered) {
+ return;
+ }
+
+ DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_LOCATION,
+ FgThread.getExecutor(), this);
+ mRegistered = true;
+ }
+
+ public void addListener(GlobalSettingChangedListener listener) {
+ mListeners.add(listener);
+ }
+
+ public void removeListener(GlobalSettingChangedListener listener) {
+ mListeners.remove(listener);
+ }
+
+ @Override
+ public final void onPropertiesChanged(DeviceConfig.Properties properties) {
+ if (!properties.getKeyset().contains(mName)) {
+ return;
+ }
+
+ onPropertiesChanged();
+ }
+
+ public void onPropertiesChanged() {
+ if (D) {
+ Log.d(TAG, "location device config setting changed: " + mName);
+ }
+
+ for (UserSettingChangedListener listener : mListeners) {
+ listener.onSettingChanged(UserHandle.USER_ALL);
+ }
+ }
+ }
+
+
+
+ private static class PackageTagsListSetting extends DeviceConfigSetting {
+
+ private final Supplier<ArrayMap<String, ArraySet<String>>> mBaseValuesSupplier;
+
+ @GuardedBy("this")
+ private boolean mValid;
+ @GuardedBy("this")
+ private PackageTagsList mCachedValue;
+
+ PackageTagsListSetting(String name,
+ Supplier<ArrayMap<String, ArraySet<String>>> baseValuesSupplier) {
+ super(name);
+ mBaseValuesSupplier = baseValuesSupplier;
+ }
+
+ public synchronized PackageTagsList getValue() {
+ PackageTagsList value = mCachedValue;
+ if (!mValid) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ PackageTagsList.Builder builder = new PackageTagsList.Builder().add(
+ mBaseValuesSupplier.get());
+
+ String setting = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_LOCATION,
+ mName);
+ if (!TextUtils.isEmpty(setting)) {
+ for (String packageAndTags : setting.split(",")) {
+ if (TextUtils.isEmpty(packageAndTags)) {
+ continue;
+ }
+
+ String[] packageThenTags = packageAndTags.split(";");
+ String packageName = packageThenTags[0];
+ if (packageThenTags.length == 1) {
+ builder.add(packageName);
+ } else {
+ for (int i = 1; i < packageThenTags.length; i++) {
+ String attributionTag = packageThenTags[i];
+ if ("null".equals(attributionTag)) {
+ attributionTag = null;
+ }
+
+ if ("*".equals(attributionTag)) {
+ builder.add(packageName);
+ } else {
+ builder.add(packageName, attributionTag);
+ }
+ }
+ }
+ }
+ }
+
+ value = builder.build();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
+ if (isRegistered()) {
+ mValid = true;
+ mCachedValue = value;
+ }
+ }
+
+ return value;
+ }
+
+ public synchronized void invalidate() {
+ mValid = false;
+ mCachedValue = null;
+ }
+
+ @Override
+ public void onPropertiesChanged() {
+ invalidate();
+ super.onPropertiesChanged();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index a4a5956..6d7f792 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -613,9 +613,9 @@
boolean locationSettingsIgnored = baseRequest.isLocationSettingsIgnored();
if (locationSettingsIgnored) {
// if we are not currently allowed use location settings ignored, disable it
- if (!mSettingsHelper.getIgnoreSettingsPackageWhitelist().contains(
- getIdentity().getPackageName()) && !mLocationManagerInternal.isProvider(
- null, getIdentity())) {
+ if (!mSettingsHelper.getIgnoreSettingsAllowlist().contains(
+ getIdentity().getPackageName(), getIdentity().getAttributionTag())
+ && !mLocationManagerInternal.isProvider(null, getIdentity())) {
builder.setLocationSettingsIgnored(false);
locationSettingsIgnored = false;
}
@@ -1820,7 +1820,7 @@
mBackgroundThrottlePackageWhitelistChangedListener);
mSettingsHelper.addOnLocationPackageBlacklistChangedListener(
mLocationPackageBlacklistChangedListener);
- mSettingsHelper.addOnIgnoreSettingsPackageWhitelistChangedListener(
+ mSettingsHelper.addIgnoreSettingsAllowlistChangedListener(
mIgnoreSettingsPackageWhitelistChangedListener);
mLocationPermissionsHelper.addListener(mLocationPermissionsListener);
mAppForegroundHelper.addListener(mAppForegroundChangedListener);
@@ -1841,7 +1841,7 @@
mBackgroundThrottlePackageWhitelistChangedListener);
mSettingsHelper.removeOnLocationPackageBlacklistChangedListener(
mLocationPackageBlacklistChangedListener);
- mSettingsHelper.removeOnIgnoreSettingsPackageWhitelistChangedListener(
+ mSettingsHelper.removeIgnoreSettingsAllowlistChangedListener(
mIgnoreSettingsPackageWhitelistChangedListener);
mLocationPermissionsHelper.removeListener(mLocationPermissionsListener);
mAppForegroundHelper.removeListener(mAppForegroundChangedListener);
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 3f2b8ff..b714c6d 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -33,6 +33,9 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
import android.os.Handler;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -126,6 +129,7 @@
ERROR_UNLOCK_ALL_USERS,
ERROR_PROVIDER_MISMATCH,
ERROR_KEYSTORE_FAILURE,
+ ERROR_NO_NETWORK,
})
@Retention(RetentionPolicy.SOURCE)
@interface RebootEscrowErrorCode {
@@ -139,6 +143,7 @@
static final int ERROR_UNLOCK_ALL_USERS = 5;
static final int ERROR_PROVIDER_MISMATCH = 6;
static final int ERROR_KEYSTORE_FAILURE = 7;
+ static final int ERROR_NO_NETWORK = 8;
private @RebootEscrowErrorCode int mLoadEscrowDataErrorCode = ERROR_NONE;
@@ -235,6 +240,23 @@
"server_based_ror_enabled", false);
}
+ public boolean isNetworkConnected() {
+ final ConnectivityManager connectivityManager =
+ mContext.getSystemService(ConnectivityManager.class);
+ if (connectivityManager == null) {
+ return false;
+ }
+
+ Network activeNetwork = connectivityManager.getActiveNetwork();
+ NetworkCapabilities networkCapabilities =
+ connectivityManager.getNetworkCapabilities(activeNetwork);
+ return networkCapabilities != null
+ && networkCapabilities.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ && networkCapabilities.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_VALIDATED);
+ }
+
public Context getContext() {
return mContext;
}
@@ -363,7 +385,11 @@
}
Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts");
- mLoadEscrowDataErrorCode = ERROR_RETRY_COUNT_EXHAUSTED;
+ if (mInjector.serverBasedResumeOnReboot() && !mInjector.isNetworkConnected()) {
+ mLoadEscrowDataErrorCode = ERROR_NO_NETWORK;
+ } else {
+ mLoadEscrowDataErrorCode = ERROR_RETRY_COUNT_EXHAUSTED;
+ }
onGetRebootEscrowKeyFailed(users, attemptNumber);
}
@@ -471,6 +497,8 @@
mLoadEscrowDataErrorCode = ERROR_UNKNOWN;
}
+ Slog.i(TAG, "Reporting RoR recovery metrics, success: " + success + ", service type: "
+ + serviceType + ", error code: " + mLoadEscrowDataErrorCode);
// TODO(179105110) report the duration since boot complete.
mInjector.reportMetric(success, mLoadEscrowDataErrorCode, serviceType, attemptCount,
escrowDurationInSeconds, vbmetaDigestStatus, -1);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0bc2840..0dd9b29 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4221,6 +4221,7 @@
}
}
+ /** Notifications returned here will have allowlistToken stripped from them. */
private StatusBarNotification sanitizeSbn(String pkg, int userId,
StatusBarNotification sbn) {
if (sbn.getUserId() == userId) {
@@ -4228,11 +4229,16 @@
// We could pass back a cloneLight() but clients might get confused and
// try to send this thing back to notify() again, which would not work
// very well.
+ Notification notification = sbn.getNotification().clone();
+ // Remove background token before returning notification to untrusted app, this
+ // ensures the app isn't able to perform background operations that are
+ // associated with notification interactions.
+ notification.setAllowlistToken(null);
return new StatusBarNotification(
sbn.getPackageName(),
sbn.getOpPkg(),
sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
- sbn.getNotification().clone(),
+ notification,
sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
}
}
@@ -8469,7 +8475,9 @@
for (int i = 0; i < newUris.size(); i++) {
final Uri uri = newUris.valueAt(i);
if (oldUris == null || !oldUris.contains(uri)) {
- Slog.d(TAG, key + ": granting " + uri);
+ if (DBG) {
+ Slog.d(TAG, key + ": granting " + uri);
+ }
grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg,
targetUserId);
}
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 0f6e384..c97095d 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -390,6 +390,11 @@
throws RemoteException;
/**
+ * Performs a non-staged install of an APEX package with given {@code packagePath}.
+ */
+ abstract void installPackage(String packagePath) throws PackageManagerException;
+
+ /**
* Dumps various state information to the provided {@link PrintWriter} object.
*
* @param pw the {@link PrintWriter} object to send information to.
@@ -974,6 +979,22 @@
waitForApexService().reserveSpaceForCompressedApex(infoList);
}
+ @Override
+ void installPackage(String packagePath) throws PackageManagerException {
+ try {
+ // TODO(b/187864524): do pre-install verification.
+ waitForApexService().installAndActivatePackage(packagePath);
+ // TODO(b/187864524): update mAllPackagesCache.
+ } catch (RemoteException e) {
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+ "apexservice not available");
+ } catch (Exception e) {
+ // TODO(b/187864524): is INSTALL_FAILED_INTERNAL_ERROR is the right error code here?
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+ e.getMessage());
+ }
+ }
+
/**
* Dump information about the packages contained in a particular cache
* @param packagesCache the cache to print information about.
@@ -1241,6 +1262,11 @@
}
@Override
+ void installPackage(String packagePath) {
+ throw new UnsupportedOperationException("APEX updates are not supported");
+ }
+
+ @Override
void dump(PrintWriter pw, String packageName) {
// No-op
}
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 7b1fa14..06ff691 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -58,10 +58,12 @@
import com.android.server.om.OverlayReferenceMapper;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.utils.Snappable;
+import com.android.server.utils.SnapshotCache;
import com.android.server.utils.Snapshots;
import com.android.server.utils.Watchable;
import com.android.server.utils.WatchableImpl;
import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.WatchedSparseBooleanMatrix;
import com.android.server.utils.Watcher;
import java.io.PrintWriter;
@@ -158,12 +160,21 @@
* initial scam and is null until {@link #onSystemReady()} is called.
*/
@GuardedBy("mCacheLock")
- private volatile SparseArray<SparseBooleanArray> mShouldFilterCache;
+ private volatile WatchedSparseBooleanMatrix mShouldFilterCache;
/**
* A cached snapshot.
*/
- private volatile AppsFilter mSnapshot = null;
+ private final SnapshotCache<AppsFilter> mSnapshot;
+
+ private SnapshotCache<AppsFilter> makeCache() {
+ return new SnapshotCache<AppsFilter>(this, this) {
+ @Override
+ public AppsFilter createSnapshot() {
+ AppsFilter s = new AppsFilter(mSource);
+ return s;
+ }};
+ }
/**
* Watchable machinery
@@ -211,7 +222,6 @@
*/
@Override
public void dispatchChange(@Nullable Watchable what) {
- mSnapshot = null;
mWatchable.dispatchChange(what);
}
@@ -236,6 +246,7 @@
overlayProvider);
mStateProvider = stateProvider;
mBackgroundExecutor = backgroundExecutor;
+ mSnapshot = makeCache();
}
/**
@@ -258,8 +269,14 @@
mSystemSigningDetails = orig.mSystemSigningDetails;
mProtectedBroadcasts = orig.mProtectedBroadcasts;
mShouldFilterCache = orig.mShouldFilterCache;
+ if (mShouldFilterCache != null) {
+ synchronized (orig.mCacheLock) {
+ mShouldFilterCache = mShouldFilterCache.snapshot();
+ }
+ }
mBackgroundExecutor = null;
+ mSnapshot = new SnapshotCache.Sealed<>();
}
/**
@@ -268,13 +285,7 @@
* condition causes the cached snapshot to be cleared asynchronously to this method.
*/
public AppsFilter snapshot() {
- AppsFilter s = mSnapshot;
- if (s == null) {
- s = new AppsFilter(this);
- s.mWatchable.seal();
- mSnapshot = s;
- }
- return s;
+ return mSnapshot.snapshot();
}
/**
@@ -636,12 +647,7 @@
if (mShouldFilterCache != null) {
// update the cache in a one-off manner since we've got all the information we
// need.
- SparseBooleanArray visibleUids = mShouldFilterCache.get(recipientUid);
- if (visibleUids == null) {
- visibleUids = new SparseBooleanArray();
- mShouldFilterCache.put(recipientUid, visibleUids);
- }
- visibleUids.put(visibleUid, false);
+ mShouldFilterCache.put(recipientUid, visibleUid, false);
}
}
if (changed) {
@@ -813,23 +819,21 @@
if (mShouldFilterCache == null) {
return;
}
- for (int i = mShouldFilterCache.size() - 1; i >= 0; i--) {
+ for (int i = 0; i < mShouldFilterCache.size(); i++) {
if (UserHandle.getAppId(mShouldFilterCache.keyAt(i)) == appId) {
mShouldFilterCache.removeAt(i);
- continue;
- }
- SparseBooleanArray targetSparseArray = mShouldFilterCache.valueAt(i);
- for (int j = targetSparseArray.size() - 1; j >= 0; j--) {
- if (UserHandle.getAppId(targetSparseArray.keyAt(j)) == appId) {
- targetSparseArray.removeAt(j);
- }
+ // The key was deleted so the list of keys has shifted left. That means i
+ // is now pointing at the next key to be examined. The decrement here and
+ // the loop increment together mean that i will be unchanged in the need
+ // iteration and will correctly point to the next key to be examined.
+ i--;
}
}
}
private void updateEntireShouldFilterCache() {
mStateProvider.runWithState((settings, users) -> {
- SparseArray<SparseBooleanArray> cache =
+ WatchedSparseBooleanMatrix cache =
updateEntireShouldFilterCacheInner(settings, users);
synchronized (mCacheLock) {
mShouldFilterCache = cache;
@@ -837,10 +841,10 @@
});
}
- private SparseArray<SparseBooleanArray> updateEntireShouldFilterCacheInner(
+ private WatchedSparseBooleanMatrix updateEntireShouldFilterCacheInner(
ArrayMap<String, PackageSetting> settings, UserInfo[] users) {
- SparseArray<SparseBooleanArray> cache =
- new SparseArray<>(users.length * settings.size());
+ WatchedSparseBooleanMatrix cache =
+ new WatchedSparseBooleanMatrix(users.length * settings.size());
for (int i = settings.size() - 1; i >= 0; i--) {
updateShouldFilterCacheForPackage(cache,
null /*skipPackage*/, settings.valueAt(i), settings, users, i);
@@ -864,7 +868,7 @@
packagesCache.put(settings.keyAt(i), pkg);
}
});
- SparseArray<SparseBooleanArray> cache =
+ WatchedSparseBooleanMatrix cache =
updateEntireShouldFilterCacheInner(settingsCopy, usersRef[0]);
boolean[] changed = new boolean[1];
// We have a cache, let's make sure the world hasn't changed out from under us.
@@ -916,7 +920,7 @@
}
}
- private void updateShouldFilterCacheForPackage(SparseArray<SparseBooleanArray> cache,
+ private void updateShouldFilterCacheForPackage(WatchedSparseBooleanMatrix cache,
@Nullable String skipPackageName, PackageSetting subjectSetting, ArrayMap<String,
PackageSetting> allSettings, UserInfo[] allUsers, int maxIndex) {
for (int i = Math.min(maxIndex, allSettings.size() - 1); i >= 0; i--) {
@@ -935,17 +939,11 @@
for (int ou = 0; ou < userCount; ou++) {
int otherUser = allUsers[ou].id;
int subjectUid = UserHandle.getUid(subjectUser, subjectSetting.appId);
- if (!cache.contains(subjectUid)) {
- cache.put(subjectUid, new SparseBooleanArray(appxUidCount));
- }
int otherUid = UserHandle.getUid(otherUser, otherSetting.appId);
- if (!cache.contains(otherUid)) {
- cache.put(otherUid, new SparseBooleanArray(appxUidCount));
- }
- cache.get(subjectUid).put(otherUid,
+ cache.put(subjectUid, otherUid,
shouldFilterApplicationInternal(
subjectUid, subjectSetting, otherSetting, otherUser));
- cache.get(otherUid).put(subjectUid,
+ cache.put(otherUid, subjectUid,
shouldFilterApplicationInternal(
otherUid, otherSetting, subjectSetting, subjectUser));
}
@@ -1198,22 +1196,20 @@
}
synchronized (mCacheLock) {
if (mShouldFilterCache != null) { // use cache
- SparseBooleanArray shouldFilterTargets = mShouldFilterCache.get(callingUid);
- final int targetUid = UserHandle.getUid(userId, targetPkgSetting.appId);
- if (shouldFilterTargets == null) {
+ final int callingIndex = mShouldFilterCache.indexOfKey(callingUid);
+ if (callingIndex < 0) {
Slog.wtf(TAG, "Encountered calling uid with no cached rules: "
+ callingUid);
return true;
}
- int indexOfTargetUid = shouldFilterTargets.indexOfKey(targetUid);
- if (indexOfTargetUid < 0) {
+ final int targetUid = UserHandle.getUid(userId, targetPkgSetting.appId);
+ final int targetIndex = mShouldFilterCache.indexOfKey(targetUid);
+ if (targetIndex < 0) {
Slog.w(TAG, "Encountered calling -> target with no cached rules: "
+ callingUid + " -> " + targetUid);
return true;
}
- if (!shouldFilterTargets.valueAt(indexOfTargetUid)) {
- return false;
- }
+ return mShouldFilterCache.valueAt(callingIndex, targetIndex);
} else {
if (!shouldFilterApplicationInternal(
callingUid, callingSetting, targetPkgSetting, userId)) {
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index de9add0..b135e88 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -1207,8 +1207,16 @@
final long ident = Binder.clearCallingIdentity();
try {
String packageName = component.getPackageName();
+ int uId = -1;
+ try {
+ uId = mContext.getPackageManager().getApplicationInfo(
+ packageName, PackageManager.MATCH_ANY_USER).uid;
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.d(TAG, "package not found: " + e);
+ }
intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", packageName, null));
+ intent.putExtra("uId", uId);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.setSourceBounds(sourceBounds);
} finally {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 62aca3d..1f0a8ca 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -635,13 +635,14 @@
throw new IllegalArgumentException(
"This device doesn't support the installation of APEX files");
}
- if (!params.isStaged) {
- throw new IllegalArgumentException(
- "APEX files can only be installed as part of a staged session.");
- }
if (params.isMultiPackage) {
throw new IllegalArgumentException("A multi-session can't be set as APEX.");
}
+ if (!params.isStaged
+ && (params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
+ throw new IllegalArgumentException(
+ "Non-staged APEX session doesn't support INSTALL_ENABLE_ROLLBACK");
+ }
}
if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0
@@ -877,7 +878,7 @@
}
private File buildSessionDir(int sessionId, SessionParams params) {
- if (params.isStaged) {
+ if (params.isStaged || (params.installFlags & PackageManager.INSTALL_APEX) != 0) {
final File sessionStagingDir = Environment.getDataStagingDirectory(params.volumeUuid);
return new File(sessionStagingDir, "session_" + sessionId);
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 1da80f4..8202587 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2246,12 +2246,6 @@
return;
}
- if (isApexSession()) {
- destroyInternal();
- dispatchSessionFinished(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
- "APEX packages can only be installed using staged sessions.", null);
- return;
- }
verify();
}
@@ -2276,6 +2270,13 @@
synchronized (mLock) {
childSessions = getChildSessionsLocked();
}
+ // Spot check to reject a non-staged multi package install of APEXes and APKs.
+ if (!params.isStaged && containsApkSession()
+ && sessionContains(s -> s.isApexSession())) {
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_SESSION_INVALID,
+ "Non-staged multi package install of APEX and APK packages is not supported");
+ }
List<PackageManagerService.VerificationParams> verifyingChildSessions =
new ArrayList<>(childSessions.size());
boolean success = true;
@@ -2320,8 +2321,6 @@
private void installNonStaged()
throws PackageManagerException {
- Preconditions.checkArgument(containsApkSession());
-
final PackageManagerService.InstallParams installingSession = makeInstallParams();
if (installingSession == null) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
@@ -2609,8 +2608,9 @@
}
}
- // Do not try to install apex session. Parent session will have at least one apk session.
- if (!isMultiPackage() && isApexSession()) {
+ // Do not try to install staged apex session. Parent session will have at least one apk
+ // session.
+ if (!isMultiPackage() && isApexSession() && params.isStaged) {
sendUpdateToRemoteStatusReceiver(INSTALL_SUCCEEDED,
"Apex package should have been installed by apexd", null);
return null;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6fccbdd..14861c2d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -780,7 +780,6 @@
private static final String COMPANION_PACKAGE_NAME = "com.android.companiondevicemanager";
// Compilation reasons.
- public static final int REASON_UNKNOWN = -1;
public static final int REASON_FIRST_BOOT = 0;
public static final int REASON_BOOT_AFTER_OTA = 1;
public static final int REASON_POST_BOOT = 2;
@@ -793,7 +792,8 @@
public static final int REASON_BACKGROUND_DEXOPT = 9;
public static final int REASON_AB_OTA = 10;
public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 11;
- public static final int REASON_SHARED = 12;
+ public static final int REASON_CMDLINE = 12;
+ public static final int REASON_SHARED = 13;
public static final int REASON_LAST = REASON_SHARED;
@@ -6762,7 +6762,12 @@
mSettings.enableSystemPackageLPw(packageName);
try {
- scanPackageTracedLI(scanFile, reparseFlags, rescanFlags, 0, null);
+ final AndroidPackage newPkg = scanPackageTracedLI(
+ scanFile, reparseFlags, rescanFlags, 0, null);
+ // We rescanned a stub, add it to the list of stubbed system packages
+ if (newPkg.isStub()) {
+ stubSystemApps.add(packageName);
+ }
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse original system package: "
+ e.getMessage());
@@ -8467,7 +8472,7 @@
libInfo.getPackageName(), libInfo.getAllCodePaths(),
libInfo.getName(), libInfo.getLongVersion(),
libInfo.getType(), libInfo.getDeclaringPackage(),
- getPackagesUsingSharedLibraryLPr(libInfo, flags, userId),
+ getPackagesUsingSharedLibraryLPr(libInfo, flags, callingUid, userId),
(libInfo.getDependencies() == null
? null
: new ArrayList<>(libInfo.getDependencies())),
@@ -8539,9 +8544,11 @@
libraryInfo.getPath(), libraryInfo.getPackageName(),
libraryInfo.getAllCodePaths(), libraryInfo.getName(),
libraryInfo.getLongVersion(), libraryInfo.getType(),
- libraryInfo.getDeclaringPackage(), getPackagesUsingSharedLibraryLPr(
- libraryInfo, flags, userId), libraryInfo.getDependencies() == null
- ? null : new ArrayList<>(libraryInfo.getDependencies()),
+ libraryInfo.getDeclaringPackage(),
+ getPackagesUsingSharedLibraryLPr(
+ libraryInfo, flags, callingUid, userId),
+ libraryInfo.getDependencies() == null
+ ? null : new ArrayList<>(libraryInfo.getDependencies()),
libraryInfo.isNative());
if (result == null) {
@@ -8557,7 +8564,7 @@
@GuardedBy("mLock")
private List<VersionedPackage> getPackagesUsingSharedLibraryLPr(
- SharedLibraryInfo libInfo, int flags, int userId) {
+ SharedLibraryInfo libInfo, int flags, int callingUid, int userId) {
List<VersionedPackage> versionedPackages = null;
final int packageCount = mSettings.getPackagesLocked().size();
for (int i = 0; i < packageCount; i++) {
@@ -8580,6 +8587,9 @@
if (ps.usesStaticLibrariesVersions[libIdx] != libInfo.getLongVersion()) {
continue;
}
+ if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
+ continue;
+ }
if (versionedPackages == null) {
versionedPackages = new ArrayList<>();
}
@@ -8592,6 +8602,9 @@
} else if (ps.pkg != null) {
if (ArrayUtils.contains(ps.pkg.getUsesLibraries(), libName)
|| ArrayUtils.contains(ps.pkg.getUsesOptionalLibraries(), libName)) {
+ if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
+ continue;
+ }
if (versionedPackages == null) {
versionedPackages = new ArrayList<>();
}
@@ -11937,7 +11950,7 @@
int flags = (checkProfiles ? DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES : 0) |
(force ? DexoptOptions.DEXOPT_FORCE : 0) |
(bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0);
- return performDexOpt(new DexoptOptions(packageName, REASON_UNKNOWN,
+ return performDexOpt(new DexoptOptions(packageName, REASON_CMDLINE,
targetCompilerFilter, splitName, flags));
}
@@ -14316,7 +14329,7 @@
// Remove the shared library overlays from its dependent packages.
for (int currentUserId : UserManagerService.getInstance().getUserIds()) {
final List<VersionedPackage> dependents = getPackagesUsingSharedLibraryLPr(
- libraryInfo, 0, currentUserId);
+ libraryInfo, 0, Process.SYSTEM_UID, currentUserId);
if (dependents == null) {
continue;
}
@@ -16428,25 +16441,95 @@
private void processInstallRequestsAsync(boolean success,
List<InstallRequest> installRequests) {
mHandler.post(() -> {
+ List<InstallRequest> apexInstallRequests = new ArrayList<>();
+ List<InstallRequest> apkInstallRequests = new ArrayList<>();
+ for (InstallRequest request : installRequests) {
+ if ((request.args.installFlags & PackageManager.INSTALL_APEX) != 0) {
+ apexInstallRequests.add(request);
+ } else {
+ apkInstallRequests.add(request);
+ }
+ }
+ // Note: supporting multi package install of both APEXes and APKs might requir some
+ // thinking to ensure atomicity of the install.
+ if (!apexInstallRequests.isEmpty() && !apkInstallRequests.isEmpty()) {
+ // This should've been caught at the validation step, but for some reason wasn't.
+ throw new IllegalStateException(
+ "Attempted to do a multi package install of both APEXes and APKs");
+ }
+ if (!apexInstallRequests.isEmpty()) {
+ if (success) {
+ // Since installApexPackages requires talking to external service (apexd), we
+ // schedule to run it async. Once it finishes, it will resume the install.
+ Thread t = new Thread(() -> installApexPackagesTraced(apexInstallRequests),
+ "installApexPackages");
+ t.start();
+ } else {
+ // Non-staged APEX installation failed somewhere before
+ // processInstallRequestAsync. In that case just notify the observer about the
+ // failure.
+ InstallRequest request = apexInstallRequests.get(0);
+ notifyInstallObserver(request.installResult, request.args.observer);
+ }
+ return;
+ }
if (success) {
- for (InstallRequest request : installRequests) {
+ for (InstallRequest request : apkInstallRequests) {
request.args.doPreInstall(request.installResult.returnCode);
}
synchronized (mInstallLock) {
- installPackagesTracedLI(installRequests);
+ installPackagesTracedLI(apkInstallRequests);
}
- for (InstallRequest request : installRequests) {
+ for (InstallRequest request : apkInstallRequests) {
request.args.doPostInstall(
request.installResult.returnCode, request.installResult.uid);
}
}
- for (InstallRequest request : installRequests) {
+ for (InstallRequest request : apkInstallRequests) {
restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
new PostInstallData(request.args, request.installResult, null));
}
});
}
+ private void installApexPackagesTraced(List<InstallRequest> requests) {
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installApexPackages");
+ installApexPackages(requests);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ private void installApexPackages(List<InstallRequest> requests) {
+ if (requests.isEmpty()) {
+ return;
+ }
+ if (requests.size() != 1) {
+ throw new IllegalStateException(
+ "Only a non-staged install of a single APEX is supported");
+ }
+ InstallRequest request = requests.get(0);
+ try {
+ // Should directory scanning logic be moved to ApexManager for better test coverage?
+ final File dir = request.args.origin.resolvedFile;
+ final String[] apexes = dir.list();
+ if (apexes == null) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ dir.getAbsolutePath() + " is not a directory");
+ }
+ if (apexes.length != 1) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Expected exactly one .apex file under " + dir.getAbsolutePath()
+ + " got: " + apexes.length);
+ }
+ mApexManager.installPackage(dir.getAbsolutePath() + "/" + apexes[0]);
+ } catch (PackageManagerException e) {
+ request.installResult.setError("APEX installation failed", e);
+ }
+ notifyInstallObserver(request.installResult, request.args.observer);
+ }
+
private PackageInstalledInfo createPackageInstalledInfo(
int currentStatus) {
PackageInstalledInfo res = new PackageInstalledInfo();
@@ -17058,6 +17141,10 @@
* on the install location.
*/
public void handleStartCopy() {
+ if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
+ mRet = INSTALL_SUCCEEDED;
+ return;
+ }
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
mPackageLite, origin.resolvedPath, installFlags, packageAbiOverride);
@@ -20605,7 +20692,7 @@
continue;
}
List<VersionedPackage> libClientPackages = getPackagesUsingSharedLibraryLPr(
- libraryInfo, MATCH_KNOWN_PACKAGES, currUserId);
+ libraryInfo, MATCH_KNOWN_PACKAGES, Process.SYSTEM_UID, currUserId);
if (!ArrayUtils.isEmpty(libClientPackages)) {
Slog.w(TAG, "Not removing package " + pkg.getManifestPackageName()
+ " hosting lib " + libraryInfo.getName() + " version "
@@ -26716,7 +26803,7 @@
continue;
}
final List<VersionedPackage> dependents = getPackagesUsingSharedLibraryLPr(
- info, 0, userId);
+ info, 0, Process.SYSTEM_UID, userId);
if (dependents == null) {
continue;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 636db11..7c1f054 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -40,6 +40,7 @@
"bg-dexopt",
"ab-ota",
"inactive",
+ "cmdline",
// "shared" must be the last entry
"shared"
};
@@ -141,9 +142,6 @@
}
public static String getReasonName(int reason) {
- if (reason == PackageManagerService.REASON_UNKNOWN) {
- return "unknown";
- }
if (reason < 0 || reason >= REASON_STRINGS.length) {
throw new IllegalArgumentException("reason " + reason + " invalid");
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index a69caa9..4ebf476 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -121,6 +121,7 @@
import java.net.URISyntaxException;
import java.security.SecureRandom;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Base64;
import java.util.Collection;
import java.util.Collections;
@@ -253,6 +254,8 @@
return runSuspend(true);
case "unsuspend":
return runSuspend(false);
+ case "set-distracting-restriction":
+ return runSetDistractingRestriction();
case "grant":
return runGrantRevokePermission(true);
case "revoke":
@@ -2207,6 +2210,57 @@
return 0;
}
+ private int runSetDistractingRestriction() {
+ final PrintWriter pw = getOutPrintWriter();
+ int userId = UserHandle.USER_SYSTEM;
+ String opt;
+ int flags = 0;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "--user":
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+ case "--flag":
+ final String flag = getNextArgRequired();
+ switch (flag) {
+ case "hide-notifications":
+ flags |= PackageManager.RESTRICTION_HIDE_NOTIFICATIONS;
+ break;
+ case "hide-from-suggestions":
+ flags |= PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS;
+ break;
+ default:
+ pw.println("Unrecognized flag: " + flag);
+ return 1;
+ }
+ break;
+ default:
+ pw.println("Error: Unknown option: " + opt);
+ return 1;
+ }
+ }
+
+ final List<String> packageNames = getRemainingArgs();
+ if (packageNames.isEmpty()) {
+ pw.println("Error: package name not specified");
+ return 1;
+ }
+ try {
+ final int translatedUserId = translateUserId(userId, UserHandle.USER_NULL,
+ "set-distracting");
+ final String[] errored = mInterface.setDistractingPackageRestrictionsAsUser(
+ packageNames.toArray(new String[]{}), flags, translatedUserId);
+ if (errored.length > 0) {
+ pw.println("Could not set restriction for: " + Arrays.toString(errored));
+ return 1;
+ }
+ return 0;
+ } catch (RemoteException | IllegalArgumentException e) {
+ pw.println(e.toString());
+ return 1;
+ }
+ }
+
private int runSuspend(boolean suspendedState) {
final PrintWriter pw = getOutPrintWriter();
int userId = UserHandle.USER_SYSTEM;
@@ -2689,6 +2743,7 @@
String opt;
boolean replaceExisting = true;
+ boolean forceNonStaged = false;
while ((opt = getNextOption()) != null) {
switch (opt) {
case "-r": // ignore
@@ -2783,6 +2838,9 @@
sessionParams.setInstallAsApex();
sessionParams.setStaged();
break;
+ case "--force-non-staged":
+ forceNonStaged = true;
+ break;
case "--multi-package":
sessionParams.setMultiPackage();
break;
@@ -2818,6 +2876,9 @@
if (replaceExisting) {
sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
}
+ if (forceNonStaged) {
+ sessionParams.isStaged = false;
+ }
return params;
}
@@ -3681,6 +3742,16 @@
pw.println(" unsuspend [--user USER_ID] PACKAGE [PACKAGE...]");
pw.println(" Unsuspends the specified package(s) (as user).");
pw.println("");
+ pw.println(" set-distracting-restriction [--user USER_ID] [--flag FLAG ...]");
+ pw.println(" PACKAGE [PACKAGE...]");
+ pw.println(" Sets the specified restriction flags to given package(s) (for user).");
+ pw.println(" Flags are:");
+ pw.println(" hide-notifications: Hides notifications from this package");
+ pw.println(" hide-from-suggestions: Hides this package from suggestions");
+ pw.println(" (by the launcher, etc.)");
+ pw.println(" Any existing flags are overwritten, which also means that if no flags are");
+ pw.println(" specified then all existing flags will be cleared.");
+ pw.println("");
pw.println(" grant [--user USER_ID] PACKAGE PERMISSION");
pw.println(" revoke [--user USER_ID] PACKAGE PERMISSION");
pw.println(" These commands either grant or revoke permissions to apps. The permissions");
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 3576950..1859b4c 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -607,6 +607,7 @@
TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED_WITH_DM = 19;
private static final int TRON_COMPILATION_REASON_BOOT_AFTER_OTA = 20;
private static final int TRON_COMPILATION_REASON_POST_BOOT = 21;
+ private static final int TRON_COMPILATION_REASON_CMDLINE = 22;
// The annotation to add as a suffix to the compilation reason when dexopt was
// performed with dex metadata.
@@ -617,7 +618,7 @@
*/
private static int getCompilationReasonTronValue(String compilationReason) {
switch (compilationReason) {
- case "unknown" : return TRON_COMPILATION_REASON_UNKNOWN;
+ case "cmdline" : return TRON_COMPILATION_REASON_CMDLINE;
case "error" : return TRON_COMPILATION_REASON_ERROR;
case "first-boot" : return TRON_COMPILATION_REASON_FIRST_BOOT;
case "boot-after-ota": return TRON_COMPILATION_REASON_BOOT_AFTER_OTA;
diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
index 091d820..83d4ce7 100644
--- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
+++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
@@ -22,8 +22,8 @@
import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
-import android.util.jar.StrictJarFile;
import android.util.Slog;
+import android.util.jar.StrictJarFile;
import com.android.internal.art.ArtStatsLog;
import com.android.server.pm.PackageManagerService;
@@ -58,8 +58,6 @@
private static final Map<Integer, Integer> COMPILATION_REASON_MAP = new HashMap();
static {
- COMPILATION_REASON_MAP.put(PackageManagerService.REASON_UNKNOWN, ArtStatsLog.
- ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_UNKNOWN);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_FIRST_BOOT, ArtStatsLog.
ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_FIRST_BOOT);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_BOOT_AFTER_OTA, ArtStatsLog.
@@ -85,6 +83,8 @@
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE,
ArtStatsLog.
ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INACTIVE);
+ COMPILATION_REASON_MAP.put(PackageManagerService.REASON_CMDLINE,
+ ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_CMDLINE);
COMPILATION_REASON_MAP.put(PackageManagerService.REASON_SHARED,
ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_SHARED);
}
@@ -163,7 +163,7 @@
uid,
compilationReason,
compilerFilter,
- ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES,
+ ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_COUNTER_BYTES,
getDexBytes(apkPath),
dexMetadataType,
apkType,
@@ -173,7 +173,7 @@
uid,
compilationReason,
compilerFilter,
- ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME,
+ ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME_COUNTER_MILLIS,
compileTime,
dexMetadataType,
apkType,
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index a7bac20..bad7e5c 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -720,7 +720,8 @@
for (String voiceInteractPackageName : voiceInteractPackageNames) {
grantPermissionsToSystemPackage(pm, voiceInteractPackageName, userId,
CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
- PHONE_PERMISSIONS, SMS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS);
+ PHONE_PERMISSIONS, SMS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS,
+ NEARBY_DEVICES_PERMISSIONS);
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 983b5b1..9c25159 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -192,6 +192,7 @@
import com.android.internal.R;
import com.android.internal.accessibility.AccessibilityShortcutController;
+import com.android.internal.app.AssistUtils;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
@@ -650,7 +651,8 @@
case MSG_LAUNCH_ASSIST:
final int deviceId = msg.arg1;
final Long eventTime = (Long) msg.obj;
- launchAssistAction(null /* hint */, deviceId, eventTime);
+ launchAssistAction(null /* hint */, deviceId, eventTime,
+ AssistUtils.INVOCATION_TYPE_UNKNOWN);
break;
case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK:
launchVoiceAssistWithWakeLock();
@@ -1108,7 +1110,8 @@
performHapticFeedback(HapticFeedbackConstants.ASSISTANT_BUTTON, false,
"Power - Long Press - Go To Assistant");
final int powerKeyDeviceId = Integer.MIN_VALUE;
- launchAssistAction(null, powerKeyDeviceId, eventTime);
+ launchAssistAction(null, powerKeyDeviceId, eventTime,
+ AssistUtils.INVOCATION_TYPE_POWER_BUTTON_LONG_PRESS);
break;
}
}
@@ -1541,7 +1544,8 @@
launchAllAppsAction();
break;
case LONG_PRESS_HOME_ASSIST:
- launchAssistAction(null, deviceId, eventTime);
+ launchAssistAction(null, deviceId, eventTime,
+ AssistUtils.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
break;
case LONG_PRESS_HOME_NOTIFICATION_PANEL:
toggleNotificationPanel();
@@ -2772,7 +2776,7 @@
} else if (mPendingMetaAction) {
launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD,
event.getDeviceId(),
- event.getEventTime());
+ event.getEventTime(), AssistUtils.INVOCATION_TYPE_UNKNOWN);
mPendingMetaAction = false;
}
}
@@ -3036,7 +3040,8 @@
// various parts of the UI.
/** Asks the status bar to startAssist(), usually a full "assistant" interface */
- private void launchAssistAction(String hint, int deviceId, long eventTime) {
+ private void launchAssistAction(String hint, int deviceId, long eventTime,
+ int invocationType) {
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
if (!isUserSetupComplete()) {
// Disable opening assist window during setup
@@ -3053,6 +3058,7 @@
args.putBoolean(hint, true);
}
args.putLong(Intent.EXTRA_TIME, eventTime);
+ args.putInt(AssistUtils.INVOCATION_TYPE_KEY, invocationType);
((SearchManager) mContext.createContextAsUser(UserHandle.of(mCurrentUserId), 0)
.getSystemService(Context.SEARCH_SERVICE)).launchAssist(args);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 3018e5f..b5f3253 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -2329,10 +2329,14 @@
final int numWakeLocks = mWakeLocks.size();
for (int i = 0; i < numWakeLocks; i++) {
final WakeLock wakeLock = mWakeLocks.get(i);
+ final Integer groupId = wakeLock.getDisplayGroupId();
+ if (groupId == null) {
+ continue;
+ }
+
final int wakeLockFlags = getWakeLockSummaryFlags(wakeLock);
mWakeLockSummary |= wakeLockFlags;
- final int groupId = wakeLock.getDisplayGroupId();
if (groupId != Display.INVALID_DISPLAY_GROUP) {
int wakeLockSummary = mDisplayGroupPowerStateMapper.getWakeLockSummaryLocked(
groupId);
@@ -4876,13 +4880,19 @@
mWorkSource = copyWorkSource(workSource);
}
- public int getDisplayGroupId() {
+ /** Returns the DisplayGroup Id of this wakeLock or {@code null} if no longer valid. */
+ public Integer getDisplayGroupId() {
if (!mSystemReady || mDisplayId == Display.INVALID_DISPLAY) {
return Display.INVALID_DISPLAY_GROUP;
}
+ final int[] ids = mDisplayGroupPowerStateMapper.getDisplayGroupIdsLocked();
final DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
- return displayInfo == null ? Display.INVALID_DISPLAY_GROUP : displayInfo.displayGroupId;
+ if (displayInfo != null && ArrayUtils.contains(ids, displayInfo.displayGroupId)) {
+ return displayInfo.displayGroupId;
+ }
+
+ return null;
}
@Override
diff --git a/services/core/java/com/android/server/power/WakeLockLog.java b/services/core/java/com/android/server/power/WakeLockLog.java
index d6060fa..88c9850 100644
--- a/services/core/java/com/android/server/power/WakeLockLog.java
+++ b/services/core/java/com/android/server/power/WakeLockLog.java
@@ -16,16 +16,12 @@
package com.android.server.power;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
import android.os.PowerManager;
import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
-import com.android.internal.os.SomeArgs;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
@@ -74,8 +70,6 @@
private static final boolean DEBUG = false;
- private static final int MSG_ON_WAKE_LOCK_EVENT = 1;
-
private static final int TYPE_TIME_RESET = 0x0;
private static final int TYPE_ACQUIRE = 0x1;
private static final int TYPE_RELEASE = 0x2;
@@ -130,7 +124,6 @@
private final Injector mInjector;
private final TheLog mLog;
private final TagDatabase mTagDatabase;
- private final Handler mHandler;
private final SimpleDateFormat mDumpsysDateFormat;
WakeLockLog() {
@@ -140,7 +133,6 @@
@VisibleForTesting
WakeLockLog(Injector injector) {
mInjector = injector;
- mHandler = new WakeLockLogHandler(injector.getLooper());
mTagDatabase = new TagDatabase(injector);
EntryByteTranslator translator = new EntryByteTranslator(mTagDatabase);
mLog = new TheLog(injector, translator, mTagDatabase);
@@ -172,7 +164,7 @@
* Dumps all the wake lock data currently saved in the wake lock log to the specified
* {@code PrintWriter}.
*
- * @param The {@code PrintWriter} to write to.
+ * @param pw The {@code PrintWriter} to write to.
*/
public void dump(PrintWriter pw) {
dump(pw, false);
@@ -221,9 +213,6 @@
/**
* Adds a new entry to the log based on the specified wake lock parameters.
*
- * Grabs the current time for the event and then posts the rest of the logic (actually
- * adding it to the log) to a background thread.
- *
* @param eventType The type of event (ACQUIRE, RELEASE);
* @param tag The wake lock's identifying tag.
* @param ownerUid The owner UID of the wake lock.
@@ -239,15 +228,11 @@
}
final long time = mInjector.currentTimeMillis();
-
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = tagNameReducer(tag);
- args.argi1 = eventType;
- args.argi2 = ownerUid;
- args.argi3 = eventType == TYPE_ACQUIRE ? translateFlagsFromPowerManager(flags) : 0;
- args.argi4 = (int) ((time >> 32) & 0xFFFFFFFFL);
- args.argi5 = (int) (time & 0xFFFFFFFFL);
- mHandler.obtainMessage(MSG_ON_WAKE_LOCK_EVENT, args).sendToTarget();
+ final int translatedFlags = eventType == TYPE_ACQUIRE
+ ? translateFlagsFromPowerManager(flags)
+ : 0;
+ handleWakeLockEventInternal(eventType, tagNameReducer(tag), ownerUid, translatedFlags,
+ time);
}
/**
@@ -273,8 +258,8 @@
* flags, {@code WakeLockLog.FLAG_*}, and a log-level, {@code WakeLockLog.LEVEL_*}.
*
* @param flags Wake lock flags including {@code PowerManager.*_WAKE_LOCK}
- * {@link PowerManager.ACQUIRE_CAUSES_WAKEUP}, and
- * {@link PowerManager.ON_AFTER_RELEASE}.
+ * {@link PowerManager#ACQUIRE_CAUSES_WAKEUP}, and
+ * {@link PowerManager#ON_AFTER_RELEASE}.
* @return The compressed flags value.
*/
int translateFlagsFromPowerManager(int flags) {
@@ -328,9 +313,9 @@
}
String reduciblePrefix = null;
- for (int tp = 0; tp < REDUCED_TAG_PREFIXES.length; tp++) {
- if (tag.startsWith(REDUCED_TAG_PREFIXES[tp])) {
- reduciblePrefix = REDUCED_TAG_PREFIXES[tp];
+ for (String reducedTagPrefix : REDUCED_TAG_PREFIXES) {
+ if (tag.startsWith(reducedTagPrefix)) {
+ reduciblePrefix = reducedTagPrefix;
break;
}
}
@@ -339,7 +324,7 @@
final StringBuilder sb = new StringBuilder();
// add prefix first
- sb.append(tag.substring(0, reduciblePrefix.length()));
+ sb.append(tag, 0, reduciblePrefix.length());
// Stop looping on final marker
final int end = Math.max(tag.lastIndexOf("/"), tag.lastIndexOf("."));
@@ -604,7 +589,7 @@
* @return The number of bytes written to buffer, or required to write to the buffer.
*/
int toBytes(LogEntry entry, byte[] bytes, long timeReference) {
- int sizeNeeded = -1;
+ final int sizeNeeded;
switch (entry.type) {
case TYPE_ACQUIRE: {
sizeNeeded = 3;
@@ -696,8 +681,9 @@
* {@link EntryByteTranslator} to convert byte {@link LogEntry} to bytes within the buffer.
*
* This class also implements the logic around TIME_RESET events. Since the LogEntries store
- * their time (8-bit) relative to the previous event, this class can add {@link TYPE_TIME_RESET}
- * LogEntries as necessary to allow a LogEntry's relative time to fit within that range.
+ * their time (8-bit) relative to the previous event, this class can add
+ * {@link #TYPE_TIME_RESET} LogEntries as necessary to allow a LogEntry's relative time to fit
+ * within that range.
*/
static class TheLog {
private final EntryByteTranslator mTranslator;
@@ -711,7 +697,7 @@
/**
* Second temporary buffer used when reading and writing bytes from the buffer.
* A second temporary buffer is necessary since additional items can be read concurrently
- * from {@link mTempBuffer}. E.g., Adding an entry to a full buffer requires removing
+ * from {@link #mTempBuffer}. E.g., Adding an entry to a full buffer requires removing
* other entries from the buffer.
*/
private final byte[] mReadWriteTempBuffer = new byte[MAX_LOG_ENTRY_BYTE_SIZE];
@@ -832,7 +818,7 @@
* Returns an {@link Iterator} of {@link LogEntry}s for all the entries in the log.
*
* If the log is modified while the entries are being read, the iterator will throw a
- * {@link ConcurrentModificationExceptoin}.
+ * {@link ConcurrentModificationException}.
*
* @param tempEntry A temporary {@link LogEntry} instance to use so that new instances
* aren't allocated with every call to {@code Iterator.next}.
@@ -1063,7 +1049,7 @@
* instanced into bytes.
*
* If a new tag is added when the database is full, the oldest tag is removed. The oldest tag
- * is calcualted using {@link TagData.lastUsedTime}.
+ * is calculated using {@link TagData#lastUsedTime}.
*/
static class TagDatabase {
private final int mInvalidIndex;
@@ -1086,9 +1072,9 @@
int byteEstimate = 0;
int tagSize = 0;
int tags = 0;
- for (int i = 0; i < mArray.length; i++) {
+ for (TagData tagData : mArray) {
byteEstimate += 8; // reference pointer
- TagData data = mArray[i];
+ TagData data = tagData;
if (data != null) {
entries++;
byteEstimate += data.getByteSize();
@@ -1280,10 +1266,6 @@
@Override
public String toString() {
- StringBuilder sb = new StringBuilder();
- if (DEBUG) {
- sb.append("(").append(index).append(")");
- }
return "[" + ownerUid + " ; " + tag + "]";
}
@@ -1308,10 +1290,6 @@
* Injector used by {@link WakeLockLog} for testing purposes.
*/
public static class Injector {
- public Looper getLooper() {
- return BackgroundThread.get().getLooper();
- }
-
public int getTagDatabaseSize() {
return TAG_DATABASE_SIZE;
}
@@ -1328,28 +1306,4 @@
return DATE_FORMAT;
}
}
-
- private class WakeLockLogHandler extends Handler {
- WakeLockLogHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message message) {
- switch(message.what) {
- case MSG_ON_WAKE_LOCK_EVENT:
- final SomeArgs args = (SomeArgs) message.obj;
- final String tag = (String) args.arg1;
- final int eventType = args.argi1;
- final int ownerUid = args.argi2;
- final int flags = args.argi3;
- final long time = (((long) args.argi4) << 32) + (args.argi5 & 0xFFFFFFFFL);
- args.recycle();
- handleWakeLockEventInternal(eventType, tag, ownerUid, flags, time);
- break;
- default:
- break;
- }
- }
- }
}
diff --git a/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java b/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
index 35aff8d..a582914 100644
--- a/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
+++ b/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
@@ -126,14 +126,12 @@
void cancelInternal() {
- synchronized (mLock) {
- if (mIsFulfilled) {
- return;
- }
- mIsFulfilled = true;
- }
Handler.getMain().post(() -> {
synchronized (mLock) {
+ if (mIsFulfilled) {
+ return;
+ }
+ mIsFulfilled = true;
try {
if (mCancellation != null) {
mCancellation.cancel();
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index a82c91e..dc868b3 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -126,6 +126,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.connectivity.WifiActivityEnergyInfo;
+import android.os.incremental.IncrementalManager;
import android.os.storage.DiskInfo;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
@@ -426,6 +427,7 @@
private final Object mHealthHalLock = new Object();
private final Object mAttributedAppOpsLock = new Object();
private final Object mSettingsStatsLock = new Object();
+ private final Object mInstalledIncrementalPackagesLock = new Object();
public StatsPullAtomService(Context context) {
super(context);
@@ -695,6 +697,10 @@
synchronized (mSettingsStatsLock) {
return pullSettingsStatsLocked(atomTag, data);
}
+ case FrameworkStatsLog.INSTALLED_INCREMENTAL_PACKAGE:
+ synchronized (mInstalledIncrementalPackagesLock) {
+ return pullInstalledIncrementalPackagesLocked(atomTag, data);
+ }
default:
throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
}
@@ -877,6 +883,7 @@
registerBatteryVoltage();
registerBatteryCycleCount();
registerSettingsStats();
+ registerInstalledIncrementalPackages();
}
private void initAndRegisterNetworkStatsPullers() {
@@ -3949,6 +3956,31 @@
return StatsManager.PULL_SUCCESS;
}
+ private void registerInstalledIncrementalPackages() {
+ int tagId = FrameworkStatsLog.INSTALLED_INCREMENTAL_PACKAGE;
+ mStatsManager.setPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ DIRECT_EXECUTOR,
+ mStatsCallbackImpl
+ );
+ }
+
+ int pullInstalledIncrementalPackagesLocked(int atomTag, List<StatsEvent> pulledData) {
+ final PackageManager pm = mContext.getPackageManager();
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY)) {
+ // Incremental is not enabled on this device. The result list will be empty.
+ return StatsManager.PULL_SUCCESS;
+ }
+ List<PackageInfo> installedPackages = pm.getInstalledPackages(0);
+ for (PackageInfo pi : installedPackages) {
+ if (IncrementalManager.isIncrementalPath(pi.applicationInfo.getBaseCodePath())) {
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, pi.applicationInfo.uid));
+ }
+ }
+ return StatsManager.PULL_SUCCESS;
+ }
+
// Thermal event received from vendor thermal management subsystem
private static final class ThermalEventListener extends IThermalEventListener.Stub {
@Override
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index d6e7574..8926af4 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -18,6 +18,7 @@
import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
import static android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE;
+import static android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import static android.view.Display.DEFAULT_DISPLAY;
import android.Manifest;
@@ -789,12 +790,13 @@
@Override
public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
- int userId, String opPackageName, long operationId) {
+ int userId, String opPackageName, long operationId,
+ @BiometricMultiSensorMode int multiSensorConfig) {
enforceBiometricDialog();
if (mBar != null) {
try {
mBar.showAuthenticationDialog(promptInfo, receiver, sensorIds, credentialAllowed,
- requireConfirmation, userId, opPackageName, operationId);
+ requireConfirmation, userId, opPackageName, operationId, multiSensorConfig);
} catch (RemoteException ex) {
}
}
diff --git a/services/core/java/com/android/server/utils/WatchedSparseBooleanMatrix.java b/services/core/java/com/android/server/utils/WatchedSparseBooleanMatrix.java
new file mode 100644
index 0000000..42a2f81
--- /dev/null
+++ b/services/core/java/com/android/server/utils/WatchedSparseBooleanMatrix.java
@@ -0,0 +1,562 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import android.annotation.Nullable;
+import android.annotation.Size;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import java.util.Arrays;
+
+/**
+ * A {@link WatchedSparseBooleanMatrix} is an compact NxN array of booleans. The rows and
+ * columns of the array are indexed by integers, which need not be contiguous. The matrix
+ * is square and the row and column indices are identical. This matrix is intended to be
+ * very memory efficient.
+ *
+ * The matrix contains a map from indices to columns: this map requires 2*N integers. The
+ * boolean array is bit-packed and requires N*N/8 bytes. The memory required for an
+ * order-N matrix is therefore 2*N*4 + N*N bytes.
+ *
+ * See {@link SparseBooleanArray} for a discussion of sparse arrays.
+ */
+public class WatchedSparseBooleanMatrix extends WatchableImpl implements Snappable {
+
+ /**
+ * The matrix is implemented through four arrays. The matrix of booleans is stored in
+ * a one-dimensional {@code mValues} array. {@code mValues} is always of size
+ * {@code mOrder * mOrder}. Elements of {@code mValues} are addressed with
+ * arithmetic: the offset of the element {@code {row, col}} is at
+ * {@code row * mOrder + col}. The term "storage index" applies to {@code mValues}.
+ * A storage index designates a row (column) in the underlying storage. This is not
+ * the same as the row seen by client code.
+ *
+ * Client code addresses the matrix through indices. These are integers that need not
+ * be contiguous. Client indices are mapped to storage indices through two linear
+ * integer arrays. {@code mKeys} is a sorted list of client indices.
+ * {@code mIndices} is a parallel array that contains storage indices. The storage
+ * index of a client index {@code k} is {@code mIndices[i]}, where
+ * {@code mKeys[i] == k}.
+ *
+ * A final array, {@code mInUse} records if storage indices are free or in use. This
+ * array is of size {@code mOrder}. A client index is deleted by removing it from
+ * {@code mKeys} and {@code mIndices} and then setting the original storage index
+ * false in {@code mInUse}.
+ *
+ * Some notes:
+ * <ul>
+ * <li> The matrix never shrinks.
+ * <li> Equality is a very, very expesive operation.
+ * </ul>
+ */
+
+ /**
+ * mOrder is always a multiple of this value. A minimal matrix therefore holds 2^12
+ * values and requires 1024 bytes.
+ */
+ private static final int STEP = 64;
+
+ /**
+ * The order of the matrix storage, including any padding. The matrix is always
+ * square. mOrder is always greater than or equal to mSize.
+ */
+ private int mOrder;
+
+ /**
+ * The number of client keys. This is always less than or equal to mOrder. It is the
+ * order of the matrix as seen by the client.
+ */
+ private int mSize;
+
+ /**
+ * The in-use list.
+ */
+ private boolean[] mInUse;
+
+ /**
+ * The array of client keys (indices), in sorted order.
+ */
+ private int[] mKeys;
+
+ /**
+ * The mapping from a client key to an storage index. If client key K is at index N
+ * in mKeys, then the storage index for K is at mMap[N].
+ */
+ private int[] mMap;
+
+ /**
+ * The boolean array. This array is always {@code mOrder x mOrder} in size.
+ */
+ private boolean[] mValues;
+
+ /**
+ * A convenience function called when the elements are added to or removed from the storage.
+ * The watchable is always {@link this}.
+ */
+ private void onChanged() {
+ dispatchChange(this);
+ }
+
+ /**
+ * Creates a new WatchedSparseBooleanMatrix containing no mappings.
+ */
+ public WatchedSparseBooleanMatrix() {
+ this(STEP);
+ }
+
+ /**
+ * Creates a new SparseBooleanMatrix containing no mappings that will not require any
+ * additional memory allocation to store the specified number of mappings. The
+ * capacity is always rounded up to a non-zero multiple of STEP.
+ */
+ public WatchedSparseBooleanMatrix(int initialCapacity) {
+ mOrder = initialCapacity;
+ if (mOrder < STEP) {
+ mOrder = STEP;
+ }
+ if (mOrder % STEP != 0) {
+ mOrder = ((initialCapacity / STEP) + 1) * STEP;
+ }
+ if (mOrder < STEP || (mOrder % STEP != 0)) {
+ throw new RuntimeException("mOrder is " + mOrder + " initCap is " + initialCapacity);
+ }
+
+ mInUse = new boolean[mOrder];
+ mKeys = ArrayUtils.newUnpaddedIntArray(mOrder);
+ mMap = ArrayUtils.newUnpaddedIntArray(mOrder);
+ mValues = new boolean[mOrder * mOrder];
+ mSize = 0;
+ }
+
+ /**
+ * A copy constructor that can be used for snapshotting.
+ */
+ private WatchedSparseBooleanMatrix(WatchedSparseBooleanMatrix r) {
+ mOrder = r.mOrder;
+ mSize = r.mSize;
+ mKeys = r.mKeys.clone();
+ mMap = r.mMap.clone();
+ mInUse = r.mInUse.clone();
+ mValues = r.mValues.clone();
+ }
+
+ /**
+ * Return a copy of this object.
+ */
+ public WatchedSparseBooleanMatrix snapshot() {
+ return new WatchedSparseBooleanMatrix(this);
+ }
+
+ /**
+ * Gets the boolean mapped from the specified key, or <code>false</code>
+ * if no such mapping has been made.
+ */
+ public boolean get(int row, int col) {
+ return get(row, col, false);
+ }
+
+ /**
+ * Gets the boolean mapped from the specified key, or the specified value
+ * if no such mapping has been made.
+ */
+ public boolean get(int row, int col, boolean valueIfKeyNotFound) {
+ int r = indexOfKey(row, false);
+ int c = indexOfKey(col, false);
+ if (r >= 0 && c >= 0) {
+ return valueAt(r, c);
+ } else {
+ return valueIfKeyNotFound;
+ }
+ }
+
+ /**
+ * Adds a mapping from the specified keys to the specified value, replacing the
+ * previous mapping from the specified keys if there was one.
+ */
+ public void put(int row, int col, boolean value) {
+ int r = indexOfKey(row);
+ int c = indexOfKey(col);
+ if (r < 0 || c < 0) {
+ // One or both of the keys has not be installed yet. Install them now.
+ // Installing either key may shift the other key. The safest course is to
+ // install the keys that are not present and then recompute both indices.
+ if (r < 0) {
+ r = indexOfKey(row, true);
+ }
+ if (c < 0) {
+ c = indexOfKey(col, true);
+ }
+ r = indexOfKey(row);
+ c = indexOfKey(col);
+ }
+ if (r >= 0 && c >= 0) {
+ setValueAt(r, c, value);
+ onChanged();
+ } else {
+ throw new RuntimeException("matrix overflow");
+ }
+ }
+
+ /**
+ * Removes the mapping from the specified key, if there was any. Note that deletion
+ * applies to a single index, not to an element. The matrix never shrinks but the
+ * space will be reused the next time an index is added.
+ */
+ public void deleteKey(int key) {
+ int i = indexOfKey(key, false);
+ if (i >= 0) {
+ removeAt(i);
+ }
+ }
+
+ /**
+ * Removes the mapping at the specified index. The matrix does not shrink. This
+ * throws ArrayIndexOutOfBounds if the index out outside the range {@code 0..size()-1}.
+ */
+ public void removeAt(int index) {
+ validateIndex(index);
+ mInUse[mMap[index]] = false;
+ System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
+ System.arraycopy(mMap, index + 1, mMap, index, mSize - (index + 1));
+ mSize--;
+ onChanged();
+ }
+
+ /**
+ * Returns the number of key-value mappings that this WatchedSparseBooleanMatrix
+ * currently stores.
+ */
+ public int size() {
+ return mSize;
+ }
+
+ /**
+ * Removes all key-value mappings from this WatchedSparseBooleanMatrix.
+ */
+ public void clear() {
+ mSize = 0;
+ Arrays.fill(mInUse, false);
+ onChanged();
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns the key from the
+ * <code>index</code>th key-value mapping that this WatchedSparseBooleanMatrix stores.
+ *
+ * <p>The keys corresponding to indices in ascending order are guaranteed to be in
+ * ascending order, e.g., <code>keyAt(0)</code> will return the smallest key and
+ * <code>keyAt(size()-1)</code> will return the largest key.</p>
+ *
+ * <p>{@link ArrayIndexOutOfBoundsException} is thrown for indices outside of the
+ * range <code>0...size()-1</code></p>
+ */
+ public int keyAt(int index) {
+ validateIndex(index);
+ return mKeys[index];
+ }
+
+ /**
+ * Given a row and column, each in the range <code>0...size()-1</code>, returns the
+ * value from the <code>index</code>th key-value mapping that this WatchedSparseBooleanMatrix
+ * stores.
+ */
+ public boolean valueAt(int rowIndex, int colIndex) {
+ validateIndex(rowIndex, colIndex);
+ int r = mMap[rowIndex];
+ int c = mMap[colIndex];
+ int element = r * mOrder + c;
+ return mValues[element];
+ }
+
+ /**
+ * Directly set the value at a particular index.
+ */
+ public void setValueAt(int rowIndex, int colIndex, boolean value) {
+ validateIndex(rowIndex, colIndex);
+ int r = mMap[rowIndex];
+ int c = mMap[colIndex];
+ int element = r * mOrder + c;
+ mValues[element] = value;
+ onChanged();
+ }
+
+ /**
+ * Returns the index for which {@link #keyAt} would return the specified key, or a
+ * negative number if the specified key is not mapped.
+ */
+ public int indexOfKey(int key) {
+ return binarySearch(mKeys, mSize, key);
+ }
+
+ /**
+ * Return true if the matrix knows the user index.
+ */
+ public boolean contains(int key) {
+ return indexOfKey(key) >= 0;
+ }
+
+ /**
+ * Fetch the index of a key. If the key does not exist and grow is true, then add the
+ * key. If the does not exist and grow is false, return -1.
+ */
+ private int indexOfKey(int key, boolean grow) {
+ int i = binarySearch(mKeys, mSize, key);
+ if (i < 0 && grow) {
+ i = ~i;
+ if (mSize >= mOrder) {
+ // Preemptively grow the matrix, which also grows the free list.
+ growMatrix();
+ }
+ int newIndex = nextFree();
+ mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
+ mMap = GrowingArrayUtils.insert(mMap, mSize, i, newIndex);
+ mSize++;
+ // Initialize the row and column corresponding to the new index.
+ for (int n = 0; n < mSize; n++) {
+ mValues[n * mOrder + newIndex] = false;
+ mValues[newIndex * mOrder + n] = false;
+ }
+ onChanged();
+ }
+ return i;
+ }
+
+ /**
+ * Validate the index. This can throw.
+ */
+ private void validateIndex(int index) {
+ if (index >= mSize) {
+ // The array might be slightly bigger than mSize, in which case, indexing won't fail.
+ throw new ArrayIndexOutOfBoundsException(index);
+ }
+ }
+
+ /**
+ * Validate two indices.
+ */
+ private void validateIndex(int row, int col) {
+ validateIndex(row);
+ validateIndex(col);
+ }
+
+ /**
+ * Find an unused storage index, mark it in-use, and return it.
+ */
+ private int nextFree() {
+ for (int i = 0; i < mInUse.length; i++) {
+ if (!mInUse[i]) {
+ mInUse[i] = true;
+ return i;
+ }
+ }
+ throw new RuntimeException();
+ }
+
+ /**
+ * Expand the 2D array. This also extends the free list.
+ */
+ private void growMatrix() {
+ int newOrder = mOrder + STEP;
+
+ boolean[] newInuse = Arrays.copyOf(mInUse, newOrder);
+
+ boolean[] newValues = new boolean[newOrder * newOrder];
+ for (int i = 0; i < mOrder; i++) {
+ int row = mOrder * i;
+ int newRow = newOrder * i;
+ for (int j = 0; j < mOrder; j++) {
+ int index = row + j;
+ int newIndex = newRow + j;
+ newValues[newIndex] = mValues[index];
+ }
+ }
+
+ mInUse = newInuse;
+ mValues = newValues;
+ mOrder = newOrder;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ int hashCode = mSize;
+ for (int i = 0; i < mSize; i++) {
+ hashCode = 31 * hashCode + mKeys[i];
+ hashCode = 31 * hashCode + mMap[i];
+ }
+ for (int i = 0; i < mSize; i++) {
+ int row = mMap[i] * mOrder;
+ for (int j = 0; j < mSize; j++) {
+ int element = mMap[j] + row;
+ hashCode = 31 * hashCode + (mValues[element] ? 1 : 0);
+ }
+ }
+ return hashCode;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(@Nullable Object that) {
+ if (this == that) {
+ return true;
+ }
+
+ if (!(that instanceof WatchedSparseBooleanMatrix)) {
+ return false;
+ }
+
+ WatchedSparseBooleanMatrix other = (WatchedSparseBooleanMatrix) that;
+ if (mSize != other.mSize) {
+ return false;
+ }
+
+ for (int i = 0; i < mSize; i++) {
+ if (mKeys[i] != other.mKeys[i]) {
+ return false;
+ }
+ if (mMap[i] != other.mMap[i]) {
+ return false;
+ }
+ }
+ for (int i = 0; i < mSize; i++) {
+ int row = mMap[i] * mOrder;
+ for (int j = 0; j < mSize; j++) {
+ int element = mMap[j] + row;
+ if (mValues[element] != other.mValues[element]) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Return the matrix meta information. This is always three strings long.
+ */
+ private @Size(3) String[] matrixToStringMeta() {
+ String[] result = new String[3];
+
+ StringBuilder k = new StringBuilder();
+ for (int i = 0; i < mSize; i++) {
+ k.append(mKeys[i]);
+ if (i < mSize - 1) {
+ k.append(" ");
+ }
+ }
+ result[0] = k.substring(0);
+
+ StringBuilder m = new StringBuilder();
+ for (int i = 0; i < mSize; i++) {
+ m.append(mMap[i]);
+ if (i < mSize - 1) {
+ m.append(" ");
+ }
+ }
+ result[1] = m.substring(0);
+
+ StringBuilder u = new StringBuilder();
+ for (int i = 0; i < mOrder; i++) {
+ u.append(mInUse[i] ? "1" : "0");
+ }
+ result[2] = u.substring(0);
+ return result;
+ }
+
+ /**
+ * Return the matrix as an array of strings. There is one string per row. Each
+ * string has a '1' or a '0' in the proper column.
+ */
+ private String[] matrixToStringRaw() {
+ String[] result = new String[mOrder];
+ for (int i = 0; i < mOrder; i++) {
+ int row = i * mOrder;
+ StringBuilder line = new StringBuilder(mOrder);
+ for (int j = 0; j < mOrder; j++) {
+ int element = row + j;
+ line.append(mValues[element] ? "1" : "0");
+ }
+ result[i] = line.substring(0);
+ }
+ return result;
+ }
+
+ private String[] matrixToStringCooked() {
+ String[] result = new String[mSize];
+ for (int i = 0; i < mSize; i++) {
+ int row = mMap[i] * mOrder;
+ StringBuilder line = new StringBuilder(mSize);
+ for (int j = 0; j < mSize; j++) {
+ int element = row + mMap[j];
+ line.append(mValues[element] ? "1" : "0");
+ }
+ result[i] = line.substring(0);
+ }
+ return result;
+ }
+
+ public String[] matrixToString(boolean raw) {
+ String[] meta = matrixToStringMeta();
+ String[] data;
+ if (raw) {
+ data = matrixToStringRaw();
+ } else {
+ data = matrixToStringCooked();
+ }
+ String[] result = new String[meta.length + data.length];
+ System.arraycopy(meta, 0, result, 0, meta.length);
+ System.arraycopy(data, 0, result, meta.length, data.length);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation creates a string that describes the size of the array. A
+ * string with all the values could easily exceed 1Mb.
+ */
+ @Override
+ public String toString() {
+ return "{" + mSize + "x" + mSize + "}";
+ }
+
+ // Copied from android.util.ContainerHelpers, which is not visible outside the
+ // android.util package.
+ private static int binarySearch(int[] array, int size, int value) {
+ int lo = 0;
+ int hi = size - 1;
+
+ while (lo <= hi) {
+ final int mid = (lo + hi) >>> 1;
+ final int midVal = array[mid];
+
+ if (midVal < value) {
+ lo = mid + 1;
+ } else if (midVal > value) {
+ hi = mid - 1;
+ } else {
+ return mid; // value found
+ }
+ }
+ return ~lo; // value not present
+ }
+}
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index 5565ccb..fca706b 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -39,7 +39,6 @@
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
@@ -222,12 +221,10 @@
if (SubscriptionManager.isValidSubscriptionId(subId)) {
final PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId);
if (mDeps.isConfigForIdentifiedCarrier(carrierConfigs)) {
- Slog.v(TAG, String.format("SubId %s ready for SlotId %s", subId, slotId));
mReadySubIdsBySlotId.put(slotId, subId);
handleSubscriptionsChanged();
}
} else {
- Slog.v(TAG, "Slot unloaded: " + slotId);
mReadySubIdsBySlotId.remove(slotId);
handleSubscriptionsChanged();
}
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index fb4c623..7320359 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -20,6 +20,8 @@
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener;
+import static com.android.server.VcnManagementService.LOCAL_LOG;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.ConnectivityManager;
@@ -40,6 +42,7 @@
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
@@ -106,6 +109,17 @@
@VisibleForTesting(visibility = Visibility.PRIVATE)
static final int PRIORITY_ANY = Integer.MAX_VALUE;
+ private static final SparseArray<String> PRIORITY_TO_STRING_MAP = new SparseArray<>();
+
+ static {
+ PRIORITY_TO_STRING_MAP.put(
+ PRIORITY_OPPORTUNISTIC_CELLULAR, "PRIORITY_OPPORTUNISTIC_CELLULAR");
+ PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_IN_USE, "PRIORITY_WIFI_IN_USE");
+ PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_PROSPECTIVE, "PRIORITY_WIFI_PROSPECTIVE");
+ PRIORITY_TO_STRING_MAP.put(PRIORITY_MACRO_CELLULAR, "PRIORITY_MACRO_CELLULAR");
+ PRIORITY_TO_STRING_MAP.put(PRIORITY_ANY, "PRIORITY_ANY");
+ }
+
@NonNull private final VcnContext mVcnContext;
@NonNull private final ParcelUuid mSubscriptionGroup;
@NonNull private final Set<Integer> mRequiredUnderlyingNetworkCapabilities;
@@ -403,12 +417,12 @@
}
private void reevaluateNetworks() {
- TreeSet<UnderlyingNetworkRecord> sorted =
- new TreeSet<>(
- UnderlyingNetworkRecord.getComparator(
- mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig));
- sorted.addAll(mRouteSelectionCallback.getUnderlyingNetworks());
+ if (mRouteSelectionCallback == null) {
+ return; // UnderlyingNetworkTracker has quit.
+ }
+ TreeSet<UnderlyingNetworkRecord> sorted =
+ mRouteSelectionCallback.getSortedUnderlyingNetworks();
UnderlyingNetworkRecord candidate = sorted.isEmpty() ? null : sorted.first();
if (Objects.equals(mCurrentRecord, candidate)) {
return;
@@ -421,7 +435,7 @@
private static boolean isOpportunistic(
@NonNull TelephonySubscriptionSnapshot snapshot, Set<Integer> subIds) {
if (snapshot == null) {
- Slog.wtf(TAG, "Got null snapshot");
+ logWtf("Got null snapshot");
return false;
}
@@ -454,17 +468,23 @@
private final Map<Network, UnderlyingNetworkRecord.Builder>
mUnderlyingNetworkRecordBuilders = new ArrayMap<>();
- private List<UnderlyingNetworkRecord> getUnderlyingNetworks() {
- final List<UnderlyingNetworkRecord> records = new ArrayList<>();
+ private TreeSet<UnderlyingNetworkRecord> getSortedUnderlyingNetworks() {
+ TreeSet<UnderlyingNetworkRecord> sorted =
+ new TreeSet<>(
+ UnderlyingNetworkRecord.getComparator(
+ mSubscriptionGroup,
+ mLastSnapshot,
+ mCurrentRecord,
+ mCarrierConfig));
for (UnderlyingNetworkRecord.Builder builder :
mUnderlyingNetworkRecordBuilders.values()) {
if (builder.isValid()) {
- records.add(builder.build());
+ sorted.add(builder.build());
}
}
- return records;
+ return sorted;
}
@Override
@@ -486,7 +506,7 @@
final UnderlyingNetworkRecord.Builder builder =
mUnderlyingNetworkRecordBuilders.get(network);
if (builder == null) {
- Slog.wtf(TAG, "Got capabilities change for unknown key: " + network);
+ logWtf("Got capabilities change for unknown key: " + network);
return;
}
@@ -502,7 +522,7 @@
final UnderlyingNetworkRecord.Builder builder =
mUnderlyingNetworkRecordBuilders.get(network);
if (builder == null) {
- Slog.wtf(TAG, "Got link properties change for unknown key: " + network);
+ logWtf("Got link properties change for unknown key: " + network);
return;
}
@@ -517,7 +537,7 @@
final UnderlyingNetworkRecord.Builder builder =
mUnderlyingNetworkRecordBuilders.get(network);
if (builder == null) {
- Slog.wtf(TAG, "Got blocked status change for unknown key: " + network);
+ logWtf("Got blocked status change for unknown key: " + network);
return;
}
@@ -605,7 +625,7 @@
// mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED
if (isBlocked) {
- Slog.wtf(TAG, "Network blocked for System Server: " + network);
+ logWtf("Network blocked for System Server: " + network);
return PRIORITY_ANY;
}
@@ -668,10 +688,21 @@
}
/** Dumps the state of this record for logging and debugging purposes. */
- public void dump(IndentingPrintWriter pw) {
+ private void dump(
+ IndentingPrintWriter pw,
+ ParcelUuid subscriptionGroup,
+ TelephonySubscriptionSnapshot snapshot,
+ UnderlyingNetworkRecord currentlySelected,
+ PersistableBundle carrierConfig) {
pw.println("UnderlyingNetworkRecord:");
pw.increaseIndent();
+ final int priorityClass =
+ calculatePriorityClass(
+ subscriptionGroup, snapshot, currentlySelected, carrierConfig);
+ pw.println(
+ "Priority class: " + PRIORITY_TO_STRING_MAP.get(priorityClass) + " ("
+ + priorityClass + ")");
pw.println("mNetwork: " + network);
pw.println("mNetworkCapabilities: " + networkCapabilities);
pw.println("mLinkProperties: " + linkProperties);
@@ -741,6 +772,40 @@
}
}
+ private static void logWtf(String msg) {
+ Slog.wtf(TAG, msg);
+ LOCAL_LOG.log(TAG + " WTF: " + msg);
+ }
+
+ private static void logWtf(String msg, Throwable tr) {
+ Slog.wtf(TAG, msg, tr);
+ LOCAL_LOG.log(TAG + " WTF: " + msg + tr);
+ }
+
+ /** Dumps the state of this record for logging and debugging purposes. */
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("UnderlyingNetworkTracker:");
+ pw.increaseIndent();
+
+ pw.println("Carrier WiFi Entry Threshold: " + getWifiEntryRssiThreshold(mCarrierConfig));
+ pw.println("Carrier WiFi Exit Threshold: " + getWifiExitRssiThreshold(mCarrierConfig));
+ pw.println(
+ "Currently selected: " + (mCurrentRecord == null ? null : mCurrentRecord.network));
+
+ pw.println("Underlying networks:");
+ pw.increaseIndent();
+ if (mRouteSelectionCallback != null) {
+ for (UnderlyingNetworkRecord record :
+ mRouteSelectionCallback.getSortedUnderlyingNetworks()) {
+ record.dump(pw, mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig);
+ }
+ }
+ pw.decreaseIndent();
+ pw.println();
+
+ pw.decreaseIndent();
+ }
+
private class VcnActiveDataSubscriptionIdListener extends TelephonyCallback
implements ActiveDataSubscriptionIdListener {
@Override
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index f918827..f7d6136 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -24,6 +24,7 @@
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+import static com.android.server.VcnManagementService.LOCAL_LOG;
import static com.android.server.VcnManagementService.VDBG;
import android.annotation.NonNull;
@@ -513,37 +514,44 @@
}
private String getLogPrefix() {
- return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "]: ";
+ return "[" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "] ";
}
private void logVdbg(String msg) {
if (VDBG) {
Slog.v(TAG, getLogPrefix() + msg);
+ LOCAL_LOG.log(getLogPrefix() + "VDBG: " + msg);
}
}
private void logDbg(String msg) {
Slog.d(TAG, getLogPrefix() + msg);
+ LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg);
}
private void logDbg(String msg, Throwable tr) {
Slog.d(TAG, getLogPrefix() + msg, tr);
+ LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg + tr);
}
private void logErr(String msg) {
Slog.e(TAG, getLogPrefix() + msg);
+ LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg);
}
private void logErr(String msg, Throwable tr) {
Slog.e(TAG, getLogPrefix() + msg, tr);
+ LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg + tr);
}
private void logWtf(String msg) {
Slog.wtf(TAG, getLogPrefix() + msg);
+ LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg);
}
private void logWtf(String msg, Throwable tr) {
Slog.wtf(TAG, getLogPrefix() + msg, tr);
+ LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg + tr);
}
/**
@@ -557,11 +565,14 @@
pw.println("mCurrentStatus: " + mCurrentStatus);
pw.println("mIsMobileDataEnabled: " + mIsMobileDataEnabled);
+ pw.println();
pw.println("mVcnGatewayConnections:");
+ pw.increaseIndent();
for (VcnGatewayConnection gw : mVcnGatewayConnections.values()) {
gw.dump(pw);
}
+ pw.decreaseIndent();
pw.println();
pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 5cecff6..55e3ed6 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -30,6 +30,7 @@
import static android.net.vcn.VcnManager.VCN_ERROR_CODE_INTERNAL_ERROR;
import static android.net.vcn.VcnManager.VCN_ERROR_CODE_NETWORK_ERROR;
+import static com.android.server.VcnManagementService.LOCAL_LOG;
import static com.android.server.VcnManagementService.VDBG;
import android.annotation.NonNull;
@@ -1645,7 +1646,7 @@
@NonNull IpSecTransform transform,
int direction) {
if (direction != IpSecManager.DIRECTION_IN && direction != IpSecManager.DIRECTION_OUT) {
- Slog.wtf(TAG, "Applying transform for unexpected direction: " + direction);
+ logWtf("Applying transform for unexpected direction: " + direction);
}
try {
@@ -1970,6 +1971,9 @@
}
builder.setAdministratorUids(adminUids);
+ builder.setLinkUpstreamBandwidthKbps(underlyingCaps.getLinkUpstreamBandwidthKbps());
+ builder.setLinkDownstreamBandwidthKbps(underlyingCaps.getLinkDownstreamBandwidthKbps());
+
// Set TransportInfo for SysUI use (never parcelled out of SystemServer).
if (underlyingCaps.hasTransport(TRANSPORT_WIFI)
&& underlyingCaps.getTransportInfo() instanceof WifiInfo) {
@@ -1986,6 +1990,11 @@
"Unknown transport type or missing TransportInfo/NetworkSpecifier for"
+ " non-null underlying network");
}
+ } else {
+ Slog.wtf(
+ TAG,
+ "No underlying network while building network capabilities",
+ new IllegalStateException());
}
return builder.build();
@@ -2013,7 +2022,18 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/,
null /*iface*/, RouteInfo.RTN_UNICAST));
- final int underlyingMtu = (underlying == null) ? 0 : underlying.linkProperties.getMtu();
+ int underlyingMtu = 0;
+ if (underlying != null) {
+ final LinkProperties underlyingLp = underlying.linkProperties;
+
+ lp.setTcpBufferSizes(underlyingLp.getTcpBufferSizes());
+ underlyingMtu = underlyingLp.getMtu();
+ } else {
+ Slog.wtf(
+ TAG,
+ "No underlying network while building link properties",
+ new IllegalStateException());
+ }
lp.setMtu(
MtuUtils.getMtu(
ikeTunnelParams.getTunnelModeChildSessionParams().getSaProposals(),
@@ -2115,37 +2135,44 @@
+ LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup)
+ "-"
+ mConnectionConfig.getGatewayConnectionName()
- + "]: ";
+ + "] ";
}
private void logVdbg(String msg) {
if (VDBG) {
Slog.v(TAG, getLogPrefix() + msg);
+ LOCAL_LOG.log(getLogPrefix() + "VDBG: " + msg);
}
}
private void logDbg(String msg) {
Slog.d(TAG, getLogPrefix() + msg);
+ LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg);
}
private void logDbg(String msg, Throwable tr) {
Slog.d(TAG, getLogPrefix() + msg, tr);
+ LOCAL_LOG.log(getLogPrefix() + "DBG: " + msg + tr);
}
private void logErr(String msg) {
Slog.e(TAG, getLogPrefix() + msg);
+ LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg);
}
private void logErr(String msg, Throwable tr) {
Slog.e(TAG, getLogPrefix() + msg, tr);
+ LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg + tr);
}
private void logWtf(String msg) {
Slog.wtf(TAG, getLogPrefix() + msg);
+ LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg);
}
private void logWtf(String msg, Throwable tr) {
Slog.wtf(TAG, getLogPrefix() + msg, tr);
+ LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg + tr);
}
/**
@@ -2169,15 +2196,9 @@
pw.println(
"mNetworkAgent.getNetwork(): "
+ (mNetworkAgent == null ? null : mNetworkAgent.getNetwork()));
+ pw.println();
- pw.println("mUnderlying:");
- pw.increaseIndent();
- if (mUnderlying != null) {
- mUnderlying.dump(pw);
- } else {
- pw.println("null");
- }
- pw.decreaseIndent();
+ mUnderlyingNetworkTracker.dump(pw);
pw.println();
pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
index 72cd788..31ee247 100644
--- a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
+++ b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java
@@ -172,6 +172,10 @@
}
private void handleNetworkRequestWithdrawn(@NonNull NetworkRequest request) {
+ if (VDBG) {
+ Slog.v(TAG, "Network request withdrawn: Request = " + request);
+ }
+
mRequests.remove(request);
}
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 2ac50b6..b296ef2 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -42,6 +42,7 @@
import android.os.IInterface;
import android.os.Looper;
import android.os.Message;
+import android.os.PackageTagsList;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -85,7 +86,6 @@
import java.util.Collection;
import java.util.Date;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
/**
@@ -856,14 +856,13 @@
// If user changed drop restrictions for the old user.
if (oldUserId != newUserId) {
appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
- false, mOverlayToken, (Map<String, String[]>) null, oldUserId);
+ false, mOverlayToken, null, oldUserId);
}
// Apply the restrictions for the current user based on vr state
- ArrayMap<String, String[]> exemptions = null;
+ PackageTagsList exemptions = null;
if (exemptedPackage != null) {
- exemptions = new ArrayMap<>(1);
- exemptions.put(exemptedPackage, new String[0]);
+ exemptions = new PackageTagsList.Builder(1).add(exemptedPackage).build();
}
appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 065dc6e..38966b9 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
@@ -90,7 +89,6 @@
import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_OVERRIDE;
import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.res.Configuration.ASSETS_SEQ_UNDEFINED;
import static android.content.res.Configuration.EMPTY;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -279,7 +277,6 @@
import android.os.Trace;
import android.os.UserHandle;
import android.os.storage.StorageManager;
-import android.permission.PermissionManager;
import android.service.dreams.DreamActivity;
import android.service.dreams.DreamManagerInternal;
import android.service.voice.IVoiceInteractionSession;
@@ -7457,11 +7454,9 @@
@Override
public boolean providesMaxBounds() {
- // System and SystemUI should always be able to access the physical display bounds,
- // so do not provide it with the overridden maximum bounds.
- // TODO(b/179179513) check WindowState#mOwnerCanAddInternalSystemWindow instead
- if (getUid() == SYSTEM_UID || PermissionManager.checkPermission(INTERNAL_SYSTEM_WINDOW,
- getPid(), info.applicationInfo.uid) == PERMISSION_GRANTED) {
+ // System should always be able to access the DisplayArea bounds, so do not provide it with
+ // compat max window bounds.
+ if (getUid() == SYSTEM_UID) {
return false;
}
// Do not sandbox to activity window bounds if the feature is disabled.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 9178a8d..01ee3be 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -618,7 +618,7 @@
/**
* Commit changes.
*/
- void commit() throws RemoteException;
+ void commit();
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 37a9b80..134ecde 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1638,15 +1638,20 @@
mAmInternal.enforceCallingPermission(BIND_VOICE_INTERACTION, "startAssistantActivity()");
userId = handleIncomingUser(callingPid, callingUid, userId, "startAssistantActivity");
- return getActivityStartController().obtainStarter(intent, "startAssistantActivity")
- .setCallingUid(callingUid)
- .setCallingPackage(callingPackage)
- .setCallingFeatureId(callingFeatureId)
- .setResolvedType(resolvedType)
- .setActivityOptions(bOptions)
- .setUserId(userId)
- .setAllowBackgroundActivityStart(true)
- .execute();
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ return getActivityStartController().obtainStarter(intent, "startAssistantActivity")
+ .setCallingUid(callingUid)
+ .setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
+ .setResolvedType(resolvedType)
+ .setActivityOptions(bOptions)
+ .setUserId(userId)
+ .setAllowBackgroundActivityStart(true)
+ .execute();
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
}
/**
@@ -6385,9 +6390,7 @@
@Override
public PackageConfigurationUpdater createPackageConfigurationUpdater() {
- synchronized (mGlobalLock) {
- return new PackageConfigurationUpdaterImpl(Binder.getCallingPid());
- }
+ return new PackageConfigurationUpdaterImpl(Binder.getCallingPid());
}
@Override
@@ -6400,7 +6403,7 @@
final class PackageConfigurationUpdaterImpl implements
ActivityTaskManagerInternal.PackageConfigurationUpdater {
- private int mPid;
+ private final int mPid;
private int mNightMode;
PackageConfigurationUpdaterImpl(int pid) {
@@ -6414,24 +6417,26 @@
}
@Override
- public void commit() throws RemoteException {
- if (mPid == 0) {
- throw new RemoteException("Invalid process");
- }
+ public void commit() {
synchronized (mGlobalLock) {
- final WindowProcessController wpc = mProcessMap.getProcess(mPid);
- if (wpc == null) {
- Slog.w(TAG, "Override application configuration: cannot find application");
- return;
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ final WindowProcessController wpc = mProcessMap.getProcess(mPid);
+ if (wpc == null) {
+ Slog.w(TAG, "Override application configuration: cannot find pid " + mPid);
+ return;
+ }
+ if (wpc.getNightMode() == mNightMode) {
+ return;
+ }
+ if (!wpc.setOverrideNightMode(mNightMode)) {
+ return;
+ }
+ wpc.updateNightModeForAllActivities(mNightMode);
+ mPackageConfigPersister.updateFromImpl(wpc.mName, wpc.mUserId, this);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- if (wpc.getNightMode() == mNightMode) {
- return;
- }
- if (!wpc.setOverrideNightMode(mNightMode)) {
- return;
- }
- wpc.updateNightModeForAllActivities(mNightMode);
- mPackageConfigPersister.updateFromImpl(wpc.mName, wpc.mUserId, this);
}
}
diff --git a/services/core/java/com/android/server/wm/BlurController.java b/services/core/java/com/android/server/wm/BlurController.java
index ff10168..0363944 100644
--- a/services/core/java/com/android/server/wm/BlurController.java
+++ b/services/core/java/com/android/server/wm/BlurController.java
@@ -29,6 +29,7 @@
import android.os.RemoteException;
import android.provider.Settings;
import android.view.ICrossWindowBlurEnabledListener;
+import android.view.TunnelModeEnabledListener;
/**
* Keeps track of the different factors that determine whether cross-window blur is enabled
@@ -45,6 +46,16 @@
private volatile boolean mBlurEnabled;
private boolean mInPowerSaveMode;
private boolean mBlurDisabledSetting;
+ private boolean mTunnelModeEnabled = false;
+
+ private TunnelModeEnabledListener mTunnelModeListener =
+ new TunnelModeEnabledListener(Runnable::run) {
+ @Override
+ public void onTunnelModeEnabledChanged(boolean tunnelModeEnabled) {
+ mTunnelModeEnabled = tunnelModeEnabled;
+ updateBlurEnabled();
+ }
+ };
BlurController(Context context, PowerManager powerManager) {
mContext = context;
@@ -78,6 +89,8 @@
});
mBlurDisabledSetting = getBlurDisabledSetting();
+ TunnelModeEnabledListener.register(mTunnelModeListener);
+
updateBlurEnabled();
}
@@ -99,7 +112,7 @@
private void updateBlurEnabled() {
synchronized (mLock) {
final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED && !mBlurDisabledSetting
- && !mInPowerSaveMode;
+ && !mInPowerSaveMode && !mTunnelModeEnabled;
if (mBlurEnabled == newEnabled) {
return;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d6bf461..306137a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -200,6 +200,7 @@
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.MagnificationSpec;
+import android.view.PrivacyIndicatorBounds;
import android.view.RemoteAnimationDefinition;
import android.view.RoundedCorners;
import android.view.Surface;
@@ -342,6 +343,11 @@
private final RotationCache<RoundedCorners, RoundedCorners> mRoundedCornerCache =
new RotationCache<>(this::calculateRoundedCornersForRotationUncached);
+ PrivacyIndicatorBounds mCurrentPrivacyIndicatorBounds = new PrivacyIndicatorBounds();
+ private final RotationCache<PrivacyIndicatorBounds, PrivacyIndicatorBounds>
+ mPrivacyIndicatorBoundsCache = new
+ RotationCache<>(this::calculatePrivacyIndicatorBoundsForRotationUncached);
+
/**
* Overridden display size. Initialized with {@link #mInitialDisplayWidth}
* and {@link #mInitialDisplayHeight}, but can be set via shell command "adb shell wm size".
@@ -996,7 +1002,8 @@
mInsetsStateController = new InsetsStateController(this);
mDisplayFrames = new DisplayFrames(mDisplayId, mInsetsStateController.getRawInsetsState(),
mDisplayInfo, calculateDisplayCutoutForRotation(mDisplayInfo.rotation),
- calculateRoundedCornersForRotation(mDisplayInfo.rotation));
+ calculateRoundedCornersForRotation(mDisplayInfo.rotation),
+ calculatePrivacyIndicatorBoundsForRotation(mDisplayInfo.rotation));
initializeDisplayBaseInfo();
mAppTransition = new AppTransition(mWmService.mContext, mWmService, this);
@@ -1723,8 +1730,10 @@
final DisplayInfo info = computeScreenConfiguration(mTmpConfiguration, rotation);
final WmDisplayCutout cutout = calculateDisplayCutoutForRotation(rotation);
final RoundedCorners roundedCorners = calculateRoundedCornersForRotation(rotation);
+ final PrivacyIndicatorBounds indicatorBounds =
+ calculatePrivacyIndicatorBoundsForRotation(rotation);
final DisplayFrames displayFrames = new DisplayFrames(mDisplayId, new InsetsState(), info,
- cutout, roundedCorners);
+ cutout, roundedCorners, indicatorBounds);
token.applyFixedRotationTransform(info, displayFrames, mTmpConfiguration);
}
@@ -1792,7 +1801,7 @@
return false;
}
final FadeRotationAnimationController controller = mFadeRotationAnimationController;
- return controller == null || !controller.isTargetToken(w.mToken);
+ return controller == null || !controller.isHandledToken(w.mToken);
}
void notifyInsetsChanged(Consumer<WindowState> dispatchInsetsChanged) {
@@ -2022,6 +2031,19 @@
return roundedCorners.rotate(rotation, mInitialDisplayWidth, mInitialDisplayHeight);
}
+ PrivacyIndicatorBounds calculatePrivacyIndicatorBoundsForRotation(int rotation) {
+ return mPrivacyIndicatorBoundsCache.getOrCompute(mCurrentPrivacyIndicatorBounds, rotation);
+ }
+
+ private PrivacyIndicatorBounds calculatePrivacyIndicatorBoundsForRotationUncached(
+ PrivacyIndicatorBounds bounds, int rotation) {
+ if (bounds == null) {
+ return new PrivacyIndicatorBounds(new Rect[4], rotation);
+ }
+
+ return bounds.rotate(rotation);
+ }
+
/**
* Compute display info and configuration according to the given rotation without changing
* current display.
@@ -2537,14 +2559,30 @@
onDisplayChanged(this);
}
+ void updatePrivacyIndicatorBounds(Rect[] staticBounds) {
+ PrivacyIndicatorBounds oldBounds = mCurrentPrivacyIndicatorBounds;
+ mCurrentPrivacyIndicatorBounds =
+ mCurrentPrivacyIndicatorBounds.updateStaticBounds(staticBounds);
+ if (!Objects.equals(oldBounds, mCurrentPrivacyIndicatorBounds)) {
+ final DisplayInfo info = mDisplayInfo;
+ if (mDisplayFrames.onDisplayInfoUpdated(info,
+ calculateDisplayCutoutForRotation(info.rotation),
+ calculateRoundedCornersForRotation(info.rotation),
+ calculatePrivacyIndicatorBoundsForRotation(info.rotation))) {
+ mInsetsStateController.onDisplayInfoUpdated(true);
+ }
+ }
+ }
+
void onDisplayInfoChanged() {
final DisplayInfo info = mDisplayInfo;
if (mDisplayFrames.onDisplayInfoUpdated(info,
calculateDisplayCutoutForRotation(info.rotation),
- calculateRoundedCornersForRotation(info.rotation))) {
+ calculateRoundedCornersForRotation(info.rotation),
+ calculatePrivacyIndicatorBoundsForRotation(info.rotation))) {
// TODO(b/161810301): Set notifyInsetsChange to true while the server no longer performs
// layout.
- mInsetsStateController.onDisplayInfoUpdated(false /* notifyInsetsChange */);
+ mInsetsStateController.onDisplayInfoUpdated(false /* notifyInsetsChanged */);
}
mInputMonitor.layoutInputConsumers(info.logicalWidth, info.logicalHeight);
mDisplayPolicy.onDisplayInfoChanged(info);
@@ -2579,6 +2617,8 @@
mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
mInitialDisplayCutout = mDisplayInfo.displayCutout;
mInitialRoundedCorners = mDisplayInfo.roundedCorners;
+ mCurrentPrivacyIndicatorBounds = new PrivacyIndicatorBounds(new Rect[4],
+ mDisplayInfo.rotation);
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index a37f3f2..32e43ca 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -27,6 +27,7 @@
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.InsetsState;
+import android.view.PrivacyIndicatorBounds;
import android.view.RoundedCorners;
import com.android.server.wm.utils.WmDisplayCutout;
@@ -59,10 +60,11 @@
public int mRotation;
public DisplayFrames(int displayId, InsetsState insetsState, DisplayInfo info,
- WmDisplayCutout displayCutout, RoundedCorners roundedCorners) {
+ WmDisplayCutout displayCutout, RoundedCorners roundedCorners,
+ PrivacyIndicatorBounds indicatorBounds) {
mDisplayId = displayId;
mInsetsState = insetsState;
- onDisplayInfoUpdated(info, displayCutout, roundedCorners);
+ onDisplayInfoUpdated(info, displayCutout, roundedCorners, indicatorBounds);
}
/**
@@ -74,15 +76,17 @@
* @return {@code true} if the insets state has been changed; {@code false} otherwise.
*/
public boolean onDisplayInfoUpdated(DisplayInfo info, @NonNull WmDisplayCutout displayCutout,
- @NonNull RoundedCorners roundedCorners) {
+ @NonNull RoundedCorners roundedCorners,
+ @NonNull PrivacyIndicatorBounds indicatorBounds) {
mRotation = info.rotation;
final InsetsState state = mInsetsState;
final Rect safe = mDisplayCutoutSafe;
final DisplayCutout cutout = displayCutout.getDisplayCutout();
if (mDisplayWidth == info.logicalWidth && mDisplayHeight == info.logicalHeight
- && state.getDisplayCutout().equals(cutout)
- && state.getRoundedCorners().equals(roundedCorners)) {
+ && state.getDisplayCutout().equals(cutout)
+ && state.getRoundedCorners().equals(roundedCorners)
+ && state.getPrivacyIndicatorBounds().equals(indicatorBounds)) {
return false;
}
mDisplayWidth = info.logicalWidth;
@@ -93,6 +97,7 @@
state.setDisplayFrame(unrestricted);
state.setDisplayCutout(cutout);
state.setRoundedCorners(roundedCorners);
+ state.setPrivacyIndicatorBounds(indicatorBounds);
if (!cutout.isEmpty()) {
if (cutout.getSafeInsetLeft() > 0) {
safe.left = unrestricted.left + cutout.getSafeInsetLeft();
diff --git a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
index 644256a..53b6b41 100644
--- a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
+++ b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
@@ -123,8 +123,13 @@
}
/** Returns {@code true} if the window is handled by this controller. */
+ boolean isHandledToken(WindowToken token) {
+ return token == mNavBarToken || isTargetToken(token);
+ }
+
+ /** Returns {@code true} if the controller will run fade animations on the window. */
boolean isTargetToken(WindowToken token) {
- return token == mNavBarToken || mTargetWindowTokens.contains(token);
+ return mTargetWindowTokens.contains(token);
}
void setOnShowRunnable(Runnable onShowRunnable) {
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index c387d33..f2f1926 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -22,6 +22,8 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.view.InsetsController.ANIMATION_TYPE_HIDE;
import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
+import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
+import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
@@ -522,7 +524,10 @@
mAnimationControl = new InsetsAnimationControlImpl(controls,
null /* frame */, state, mListener, typesReady, this,
mListener.getDurationMs(), getInsetsInterpolator(),
- show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE, null /* translator */);
+ show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE, show
+ ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
+ : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
+ null /* translator */);
SurfaceAnimationThread.getHandler().post(
() -> mListener.onReady(mAnimationControl, typesReady));
}
diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS
index 1077736..6602d29 100644
--- a/services/core/java/com/android/server/wm/OWNERS
+++ b/services/core/java/com/android/server/wm/OWNERS
@@ -12,3 +12,5 @@
louischang@google.com
winsonc@google.com
tigerhuang@google.com
+lihongyu@google.com
+mariiasand@google.com
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 737e7d1..2feb8a7 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -1163,9 +1163,6 @@
// Apply the task's pending transaction in case it is detached and its transaction
// is not reachable.
mTask.getPendingTransaction().apply();
-
- // Reset whether this task can affect the sysui flags
- mTask.setCanAffectSystemUiFlags(true);
}
}
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index c9d5fa4..4892005 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -20,6 +20,9 @@
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.Manifest.permission.STATUS_BAR_SERVICE;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.activityTypeToString;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.view.Display.INVALID_DISPLAY;
@@ -29,12 +32,15 @@
import android.annotation.Nullable;
import android.app.ActivityOptions;
+import android.app.AppGlobals;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Process;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Slog;
import android.view.RemoteAnimationAdapter;
@@ -281,19 +287,65 @@
}
// If launched from bubble is specified, then ensure that the caller is system or sysui.
- if (options.getLaunchedFromBubble() && callingUid != Process.SYSTEM_UID) {
- final int statusBarPerm = ActivityTaskManagerService.checkPermission(
- STATUS_BAR_SERVICE, callingPid, callingUid);
- if (statusBarPerm == PERMISSION_DENIED) {
+ if (options.getLaunchedFromBubble() && !isSystemOrSystemUI(callingPid, callingUid)) {
+ final String msg = "Permission Denial: starting " + getIntentString(intent)
+ + " from " + callerApp + " (pid=" + callingPid
+ + ", uid=" + callingUid + ") with launchedFromBubble=true";
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+
+ final int activityType = options.getLaunchActivityType();
+ if (activityType != ACTIVITY_TYPE_UNDEFINED
+ && !isSystemOrSystemUI(callingPid, callingUid)) {
+ // Granted if it is assistant type and the calling uid is assistant.
+ boolean activityTypeGranted = false;
+ if (activityType == ACTIVITY_TYPE_ASSISTANT
+ && isAssistant(supervisor.mService, callingUid)) {
+ activityTypeGranted = true;
+ }
+
+ if (!activityTypeGranted) {
final String msg = "Permission Denial: starting " + getIntentString(intent)
+ " from " + callerApp + " (pid=" + callingPid
- + ", uid=" + callingUid + ") with launchedFromBubble=true";
+ + ", uid=" + callingUid + ") with launchActivityType="
+ + activityTypeToString(options.getLaunchActivityType());
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
}
}
+ private boolean isAssistant(ActivityTaskManagerService atmService, int callingUid) {
+ if (atmService.mActiveVoiceInteractionServiceComponent == null) {
+ return false;
+ }
+
+ final String assistantPackage =
+ atmService.mActiveVoiceInteractionServiceComponent.getPackageName();
+ try {
+ final int uid = AppGlobals.getPackageManager().getPackageUid(assistantPackage,
+ PackageManager.MATCH_DIRECT_BOOT_AUTO,
+ UserHandle.getUserId(callingUid));
+ if (uid == callingUid) {
+ return true;
+ }
+ } catch (RemoteException e) {
+ // Should not happen
+ }
+ return false;
+ }
+
+ private boolean isSystemOrSystemUI(int callingPid, int callingUid) {
+ if (callingUid == Process.SYSTEM_UID) {
+ return true;
+ }
+
+ final int statusBarPerm = ActivityTaskManagerService.checkPermission(
+ STATUS_BAR_SERVICE, callingPid, callingUid);
+ return statusBarPerm == PERMISSION_GRANTED;
+ }
+
private String getIntentString(Intent intent) {
return intent != null ? intent.toString() : "(no intent)";
}
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 50749a9..9d8b8f7 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -372,7 +372,7 @@
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
R.anim.screen_rotate_0_exit);
mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
- R.anim.screen_rotate_0_enter);
+ R.anim.rotation_animation_enter);
break;
case Surface.ROTATION_90:
mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 93fc4f2..039422d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -5407,17 +5407,17 @@
: WINDOWING_MODE_FULLSCREEN;
}
if (currentMode == WINDOWING_MODE_PINNED) {
+ mRootWindowContainer.notifyActivityPipModeChanged(null);
+ }
+ if (likelyResolvedMode == WINDOWING_MODE_PINNED) {
// In the case that we've disabled affecting the SysUI flags as a part of seamlessly
// transferring the transform on the leash to the task, reset this state once we've
// actually entered pip
setCanAffectSystemUiFlags(true);
- mRootWindowContainer.notifyActivityPipModeChanged(null);
- }
- if (likelyResolvedMode == WINDOWING_MODE_PINNED
- && taskDisplayArea.getRootPinnedTask() != null) {
-
- // Can only have 1 pip at a time, so replace an existing pip
- taskDisplayArea.getRootPinnedTask().dismissPip();
+ if (taskDisplayArea.getRootPinnedTask() != null) {
+ // Can only have 1 pip at a time, so replace an existing pip
+ taskDisplayArea.getRootPinnedTask().dismissPip();
+ }
}
if (likelyResolvedMode != WINDOWING_MODE_FULLSCREEN
&& topActivity != null && !topActivity.noDisplay
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8bee862..7df5744 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5945,6 +5945,20 @@
}
}
+ @Override
+ public void updateStaticPrivacyIndicatorBounds(int displayId,
+ Rect[] staticBounds) {
+ synchronized (mGlobalLock) {
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ if (displayContent != null) {
+ displayContent.updatePrivacyIndicatorBounds(staticBounds);
+ } else {
+ Slog.w(TAG, "updateStaticPrivacyIndicatorBounds with invalid displayId="
+ + displayId);
+ }
+ }
+ }
+
public void setNavBarVirtualKeyHapticFeedbackEnabled(boolean enabled) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
!= PackageManager.PERMISSION_GRANTED) {
@@ -8091,11 +8105,10 @@
// This could prevent if there is no container animation, we still have to apply the
// pending transaction and exit waiting.
mAnimator.mNotifyWhenNoAnimation = true;
- WindowContainer animatingContainer = null;
- while (mAnimator.isAnimationScheduled() || timeoutRemaining > 0) {
- animatingContainer = mRoot.getAnimatingContainer(TRANSITION | CHILDREN,
- ANIMATION_TYPE_ALL);
- if (animatingContainer == null) {
+ while (timeoutRemaining > 0) {
+ boolean isAnimating = mAnimator.isAnimationScheduled()
+ || mRoot.isAnimating(TRANSITION | CHILDREN, ANIMATION_TYPE_ALL);
+ if (!isAnimating) {
break;
}
long startTime = System.currentTimeMillis();
@@ -8107,6 +8120,9 @@
}
mAnimator.mNotifyWhenNoAnimation = false;
+ WindowContainer animatingContainer;
+ animatingContainer = mRoot.getAnimatingContainer(TRANSITION | CHILDREN,
+ ANIMATION_TYPE_ALL);
if (mAnimator.isAnimationScheduled() || animatingContainer != null) {
Slog.w(TAG, "Timed out waiting for animations to complete,"
+ " animatingContainer=" + animatingContainer
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 653e7e8..b754644 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -160,9 +160,10 @@
static struct {
jclass clazz;
jmethodID constructor;
- jfieldID lightTypeSingle;
+ jfieldID lightTypeInput;
jfieldID lightTypePlayerId;
- jfieldID lightTypeRgb;
+ jfieldID lightCapabilityBrightness;
+ jfieldID lightCapabilityRgb;
} gLightClassInfo;
static struct {
@@ -1996,25 +1997,34 @@
continue;
}
- jint jTypeId = 0;
- if (lightInfo->type == InputDeviceLightType::SINGLE) {
- jTypeId =
- env->GetStaticIntField(gLightClassInfo.clazz, gLightClassInfo.lightTypeSingle);
- } else if (lightInfo->type == InputDeviceLightType::PLAYER_ID) {
- jTypeId = env->GetStaticIntField(gLightClassInfo.clazz,
- gLightClassInfo.lightTypePlayerId);
+ jint jTypeId =
+ env->GetStaticIntField(gLightClassInfo.clazz, gLightClassInfo.lightTypeInput);
+ jint jCapability = 0;
+
+ if (lightInfo->type == InputDeviceLightType::MONO) {
+ jCapability = env->GetStaticIntField(gLightClassInfo.clazz,
+ gLightClassInfo.lightCapabilityBrightness);
} else if (lightInfo->type == InputDeviceLightType::RGB ||
lightInfo->type == InputDeviceLightType::MULTI_COLOR) {
- jTypeId = env->GetStaticIntField(gLightClassInfo.clazz, gLightClassInfo.lightTypeRgb);
+ jCapability =
+ env->GetStaticIntField(gLightClassInfo.clazz,
+ gLightClassInfo.lightCapabilityBrightness) |
+ env->GetStaticIntField(gLightClassInfo.clazz,
+ gLightClassInfo.lightCapabilityRgb);
+ } else if (lightInfo->type == InputDeviceLightType::PLAYER_ID) {
+ jTypeId = env->GetStaticIntField(gLightClassInfo.clazz,
+ gLightClassInfo.lightTypePlayerId);
} else {
ALOGW("Unknown light type %d", lightInfo->type);
continue;
}
- ScopedLocalRef<jobject>
- lightObj(env,
- env->NewObject(gLightClassInfo.clazz, gLightClassInfo.constructor,
- (jint)lightInfo->id, (jint)lightInfo->ordinal, jTypeId,
- env->NewStringUTF(lightInfo->name.c_str())));
+ ScopedLocalRef<jobject> lightObj(env,
+ env->NewObject(gLightClassInfo.clazz,
+ gLightClassInfo.constructor,
+ static_cast<jint>(lightInfo->id),
+ env->NewStringUTF(lightInfo->name.c_str()),
+ static_cast<jint>(lightInfo->ordinal),
+ jTypeId, jCapability));
// Add light object to list
env->CallBooleanMethod(jLights, gArrayListClassInfo.add, lightObj.get());
}
@@ -2540,15 +2550,17 @@
FIND_CLASS(gLightClassInfo.clazz, "android/hardware/lights/Light");
gLightClassInfo.clazz = jclass(env->NewGlobalRef(gLightClassInfo.clazz));
GET_METHOD_ID(gLightClassInfo.constructor, gLightClassInfo.clazz, "<init>",
- "(IIILjava/lang/String;)V");
+ "(ILjava/lang/String;III)V");
gLightClassInfo.clazz = jclass(env->NewGlobalRef(gLightClassInfo.clazz));
- gLightClassInfo.lightTypeSingle =
- env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_TYPE_INPUT_SINGLE", "I");
+ gLightClassInfo.lightTypeInput =
+ env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_TYPE_INPUT", "I");
gLightClassInfo.lightTypePlayerId =
- env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_TYPE_INPUT_PLAYER_ID", "I");
- gLightClassInfo.lightTypeRgb =
- env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_TYPE_INPUT_RGB", "I");
+ env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_TYPE_PLAYER_ID", "I");
+ gLightClassInfo.lightCapabilityBrightness =
+ env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_CAPABILITY_BRIGHTNESS", "I");
+ gLightClassInfo.lightCapabilityRgb =
+ env->GetStaticFieldID(gLightClassInfo.clazz, "LIGHT_CAPABILITY_RGB", "I");
// ArrayList
FIND_CLASS(gArrayListClassInfo.clazz, "java/util/ArrayList");
diff --git a/services/core/jni/gnss/GnssMeasurementCallback.cpp b/services/core/jni/gnss/GnssMeasurementCallback.cpp
index dd9a525..8c6c673 100644
--- a/services/core/jni/gnss/GnssMeasurementCallback.cpp
+++ b/services/core/jni/gnss/GnssMeasurementCallback.cpp
@@ -54,7 +54,6 @@
jmethodID method_reportMeasurementData;
jmethodID method_satellitePvtBuilderBuild;
jmethodID method_satellitePvtBuilderCtor;
-jmethodID method_satellitePvtBuilderSetFlags;
jmethodID method_satellitePvtBuilderSetPositionEcef;
jmethodID method_satellitePvtBuilderSetVelocityEcef;
jmethodID method_satellitePvtBuilderSetClockInfo;
@@ -90,9 +89,6 @@
jclass satellitePvtBuilder = env->FindClass("android/location/SatellitePvt$Builder");
class_satellitePvtBuilder = (jclass)env->NewGlobalRef(satellitePvtBuilder);
method_satellitePvtBuilderCtor = env->GetMethodID(class_satellitePvtBuilder, "<init>", "()V");
- method_satellitePvtBuilderSetFlags =
- env->GetMethodID(class_satellitePvtBuilder, "setFlags",
- "(I)Landroid/location/SatellitePvt$Builder;");
method_satellitePvtBuilderSetPositionEcef =
env->GetMethodID(class_satellitePvtBuilder, "setPositionEcef",
"(Landroid/location/SatellitePvt$PositionEcef;)"
@@ -321,6 +317,8 @@
jobject positionEcef = nullptr;
jobject velocityEcef = nullptr;
jobject clockInfo = nullptr;
+ jobject satellitePvtBuilderObject =
+ env->NewObject(class_satellitePvtBuilder, method_satellitePvtBuilderCtor);
if (satFlags & SatellitePvt::HAS_POSITION_VELOCITY_CLOCK_INFO) {
positionEcef = env->NewObject(class_positionEcef, method_positionEcef,
@@ -337,31 +335,30 @@
satellitePvt.satClockInfo.satHardwareCodeBiasMeters,
satellitePvt.satClockInfo.satTimeCorrectionMeters,
satellitePvt.satClockInfo.satClkDriftMps);
+ env->CallObjectMethod(satellitePvtBuilderObject,
+ method_satellitePvtBuilderSetPositionEcef, positionEcef);
+ env->CallObjectMethod(satellitePvtBuilderObject,
+ method_satellitePvtBuilderSetVelocityEcef, velocityEcef);
+ env->CallObjectMethod(satellitePvtBuilderObject, method_satellitePvtBuilderSetClockInfo,
+ clockInfo);
}
- jobject satellitePvtBuilderObject =
- env->NewObject(class_satellitePvtBuilder, method_satellitePvtBuilderCtor);
+ if (satFlags & SatellitePvt::HAS_IONO) {
+ env->CallObjectMethod(satellitePvtBuilderObject,
+ method_satellitePvtBuilderSetIonoDelayMeters,
+ satellitePvt.ionoDelayMeters);
+ }
- env->CallObjectMethod(satellitePvtBuilderObject, method_satellitePvtBuilderSetFlags,
- satellitePvt.flags);
- env->CallObjectMethod(satellitePvtBuilderObject, method_satellitePvtBuilderSetPositionEcef,
- positionEcef);
- env->CallObjectMethod(satellitePvtBuilderObject, method_satellitePvtBuilderSetVelocityEcef,
- velocityEcef);
- env->CallObjectMethod(satellitePvtBuilderObject, method_satellitePvtBuilderSetClockInfo,
- clockInfo);
- env->CallObjectMethod(satellitePvtBuilderObject,
- method_satellitePvtBuilderSetIonoDelayMeters,
- satellitePvt.ionoDelayMeters);
- env->CallObjectMethod(satellitePvtBuilderObject,
- method_satellitePvtBuilderSetTropoDelayMeters,
- satellitePvt.tropoDelayMeters);
+ if (satFlags & SatellitePvt::HAS_TROPO) {
+ env->CallObjectMethod(satellitePvtBuilderObject,
+ method_satellitePvtBuilderSetTropoDelayMeters,
+ satellitePvt.tropoDelayMeters);
+ }
+
jobject satellitePvtObject =
env->CallObjectMethod(satellitePvtBuilderObject, method_satellitePvtBuilderBuild);
-
env->CallVoidMethod(object.get(), method_gnssMeasurementsSetSatellitePvt,
satellitePvtObject);
-
env->DeleteLocalRef(positionEcef);
env->DeleteLocalRef(velocityEcef);
env->DeleteLocalRef(clockInfo);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index ff7514a..ce8f6df 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -150,7 +150,6 @@
private static final String ATTR_VALUE = "value";
private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
- private static final boolean PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT = true;
DeviceAdminInfo info;
@@ -297,7 +296,7 @@
public String mEnrollmentSpecificId;
public boolean mAdminCanGrantSensorsPermissions;
public boolean mPreferentialNetworkServiceEnabled =
- PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT;
+ DevicePolicyManager.PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT;
private static final boolean USB_DATA_SIGNALING_ENABLED_DEFAULT = true;
boolean mUsbDataSignalingEnabled = USB_DATA_SIGNALING_ENABLED_DEFAULT;
@@ -576,10 +575,8 @@
}
writeAttributeValueToXml(out, TAG_ADMIN_CAN_GRANT_SENSORS_PERMISSIONS,
mAdminCanGrantSensorsPermissions);
- if (mPreferentialNetworkServiceEnabled != PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT) {
- writeAttributeValueToXml(out, TAG_PREFERENTIAL_NETWORK_SERVICE_ENABLED,
- mPreferentialNetworkServiceEnabled);
- }
+ writeAttributeValueToXml(out, TAG_PREFERENTIAL_NETWORK_SERVICE_ENABLED,
+ mPreferentialNetworkServiceEnabled);
if (mUsbDataSignalingEnabled != USB_DATA_SIGNALING_ENABLED_DEFAULT) {
writeAttributeValueToXml(out, TAG_USB_DATA_SIGNALING, mUsbDataSignalingEnabled);
}
@@ -807,8 +804,8 @@
} else if (TAG_ALWAYS_ON_VPN_LOCKDOWN.equals(tag)) {
mAlwaysOnVpnLockdown = parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_PREFERENTIAL_NETWORK_SERVICE_ENABLED.equals(tag)) {
- mPreferentialNetworkServiceEnabled = parser.getAttributeBoolean(
- null, ATTR_VALUE, PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT);
+ mPreferentialNetworkServiceEnabled = parser.getAttributeBoolean(null, ATTR_VALUE,
+ DevicePolicyManager.PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT);
} else if (TAG_COMMON_CRITERIA_MODE.equals(tag)) {
mCommonCriteriaMode = parser.getAttributeBoolean(null, ATTR_VALUE, false);
} else if (TAG_PASSWORD_COMPLEXITY.equals(tag)) {
@@ -1193,7 +1190,7 @@
pw.println(mEnrollmentSpecificId);
}
- pw.print("mAdminCanGrantSensorsPermissions");
+ pw.print("mAdminCanGrantSensorsPermissions=");
pw.println(mAdminCanGrantSensorsPermissions);
pw.print("mUsbDataSignaling=");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8089fb1..bc130e2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3176,11 +3176,12 @@
updatePermissionPolicyCache(userId);
updateAdminCanGrantSensorsPermissionCache(userId);
- boolean preferentialNetworkServiceEnabled = true;
+ final boolean preferentialNetworkServiceEnabled;
synchronized (getLockObject()) {
ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId);
preferentialNetworkServiceEnabled = owner != null
- ? owner.mPreferentialNetworkServiceEnabled : true;
+ ? owner.mPreferentialNetworkServiceEnabled
+ : DevicePolicyManager.PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT;
}
updateNetworkPreferenceForUser(userId, preferentialNetworkServiceEnabled);
@@ -4951,10 +4952,16 @@
final CallerIdentity caller = getCallerIdentity();
final int userHandle = caller.getUserId();
- // As of R, only privlleged caller holding RESET_PASSWORD can call resetPassword() to
+ // As of R, only privileged caller holding RESET_PASSWORD can call resetPassword() to
// set password to an unsecured user.
if (hasCallingPermission(permission.RESET_PASSWORD)) {
- return setPasswordPrivileged(password, flags, caller);
+ final boolean result = setPasswordPrivileged(password, flags, caller);
+ if (result) {
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.RESET_PASSWORD)
+ .write();
+ }
+ return result;
}
// If caller has PO (or DO) throw or fail silently depending on its target SDK level.
@@ -8572,6 +8579,7 @@
final DevicePolicyData policyData = getUserData(userId);
policyData.mCurrentInputMethodSet = false;
saveSettingsLocked(userId);
+ mPolicyCache.onUserRemoved(userId);
final DevicePolicyData systemPolicyData = getUserData(UserHandle.USER_SYSTEM);
systemPolicyData.mLastSecurityLogRetrievalTime = -1;
systemPolicyData.mLastBugReportRequestTime = -1;
@@ -15243,8 +15251,15 @@
DevicePolicyData policy = getUserData(caller.getUserId());
if (policy.mPasswordTokenHandle != 0) {
final String password = passwordOrNull != null ? passwordOrNull : "";
- return resetPasswordInternal(password, policy.mPasswordTokenHandle, token,
- flags, caller);
+ final boolean result = resetPasswordInternal(password, policy.mPasswordTokenHandle,
+ token, flags, caller);
+ if (result) {
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.RESET_PASSWORD_WITH_TOKEN)
+ .setAdmin(caller.getComponentName())
+ .write();
+ }
+ return result;
} else {
Slogf.w(LOG_TAG, "No saved token handle");
}
diff --git a/services/incremental/OWNERS b/services/incremental/OWNERS
index ad5eca7..7ebb962 100644
--- a/services/incremental/OWNERS
+++ b/services/incremental/OWNERS
@@ -5,3 +5,4 @@
schfan@google.com
toddke@google.com
zyy@google.com
+patb@google.com
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ad89e96..d487483 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -103,7 +103,6 @@
import com.android.internal.widget.ILockSettings;
import com.android.server.am.ActivityManagerService;
import com.android.server.appbinding.AppBindingService;
-import com.android.server.art.ArtManagerLocal;
import com.android.server.attention.AttentionManagerService;
import com.android.server.audio.AudioService;
import com.android.server.biometrics.AuthService;
@@ -2632,10 +2631,6 @@
mSystemServiceManager.startService(GAME_MANAGER_SERVICE_CLASS);
t.traceEnd();
- t.traceBegin("ArtManagerLocal");
- LocalManagerRegistry.addManager(ArtManagerLocal.class, new ArtManagerLocal());
- t.traceEnd();
-
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)) {
t.traceBegin("UwbService");
mSystemServiceManager.startService(UWB_SERVICE_CLASS);
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index 47505a3..e31be82 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -43,6 +43,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.util.EventLog;
import android.util.Log;
import com.android.internal.content.PackageMonitor;
@@ -736,13 +737,19 @@
@Override
public MidiDeviceInfo getServiceDeviceInfo(String packageName, String className) {
+ int uid = Binder.getCallingUid();
synchronized (mDevicesByInfo) {
for (Device device : mDevicesByInfo.values()) {
ServiceInfo serviceInfo = device.getServiceInfo();
if (serviceInfo != null &&
packageName.equals(serviceInfo.packageName) &&
className.equals(serviceInfo.name)) {
- return device.getDeviceInfo();
+ if (device.isUidAllowed(uid)) {
+ return device.getDeviceInfo();
+ } else {
+ EventLog.writeEvent(0x534e4554, "185796676", -1, "");
+ return null;
+ }
}
}
return null;
diff --git a/services/people/java/com/android/server/people/data/ConversationStatusExpirationBroadcastReceiver.java b/services/people/java/com/android/server/people/data/ConversationStatusExpirationBroadcastReceiver.java
index c631026..49d5e50 100644
--- a/services/people/java/com/android/server/people/data/ConversationStatusExpirationBroadcastReceiver.java
+++ b/services/people/java/com/android/server/people/data/ConversationStatusExpirationBroadcastReceiver.java
@@ -20,26 +20,18 @@
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.PendingIntent;
-import android.app.job.JobInfo;
-import android.app.job.JobParameters;
-import android.app.job.JobScheduler;
-import android.app.job.JobService;
import android.app.people.ConversationStatus;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
+import android.os.Binder;
import android.os.CancellationSignal;
-import android.os.SystemClock;
import com.android.server.LocalServices;
-import com.android.server.notification.NotificationRecord;
import com.android.server.people.PeopleServiceInternal;
-import java.util.concurrent.TimeUnit;
-
/**
* If a {@link ConversationStatus} is added to the system with an expiration time, remove that
* status at that time
@@ -53,18 +45,22 @@
void scheduleExpiration(Context context, @UserIdInt int userId, String pkg,
String conversationId, ConversationStatus status) {
-
- final PendingIntent pi = PendingIntent.getBroadcast(context,
- REQUEST_CODE,
- new Intent(ACTION)
- .setData(new Uri.Builder().scheme(SCHEME)
- .appendPath(getKey(userId, pkg, conversationId, status))
- .build())
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
- .putExtra(EXTRA_USER_ID, userId),
- PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
- context.getSystemService(AlarmManager.class).setExactAndAllowWhileIdle(
- AlarmManager.RTC_WAKEUP, status.getEndTimeMillis(), pi);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ final PendingIntent pi = PendingIntent.getBroadcast(context,
+ REQUEST_CODE,
+ new Intent(ACTION)
+ .setData(new Uri.Builder().scheme(SCHEME)
+ .appendPath(getKey(userId, pkg, conversationId, status))
+ .build())
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ .putExtra(EXTRA_USER_ID, userId),
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+ context.getSystemService(AlarmManager.class).setExactAndAllowWhileIdle(
+ AlarmManager.RTC_WAKEUP, status.getEndTimeMillis(), pi);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
private static String getKey(@UserIdInt int userId, String pkg,
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index e7a4c92..4d86c87 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -412,7 +412,7 @@
reportedModes.add(mode);
}
assertEquals(requiredModes.length, reportedModes.size());
- for (int requiredMode : reportedModes) {
+ for (int requiredMode : requiredModes) {
assertTrue("Required game mode not supported: " + requiredMode,
reportedModes.contains(requiredMode));
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 68cb8f9..3dc7bc1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -48,14 +48,18 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.job.JobInfo;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManagerInternal;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkPolicyManager;
+import android.os.BatteryManager;
+import android.os.BatteryManagerInternal;
import android.os.Build;
import android.os.Looper;
import android.os.SystemClock;
@@ -70,6 +74,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@@ -83,6 +88,8 @@
@Mock
private Context mContext;
@Mock
+ private BatteryManagerInternal mBatteryManagerInternal;
+ @Mock
private ConnectivityManager mConnManager;
@Mock
private NetworkPolicyManager mNetPolicyManager;
@@ -108,6 +115,9 @@
LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
LocalServices.addService(NetworkPolicyManagerInternal.class, mNetPolicyManagerInternal);
+ LocalServices.removeServiceForTest(BatteryManagerInternal.class);
+ LocalServices.addService(BatteryManagerInternal.class, mBatteryManagerInternal);
+
when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
// Freeze the clocks at this moment in time
@@ -143,8 +153,18 @@
DataUnit.MEBIBYTES.toBytes(1))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+ final ArgumentCaptor<BroadcastReceiver> chargingCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ when(mBatteryManagerInternal.isPowered(eq(BatteryManager.BATTERY_PLUGGED_ANY)))
+ .thenReturn(false);
final ConnectivityController controller = new ConnectivityController(mService);
+ verify(mContext).registerReceiver(chargingCaptor.capture(),
+ ArgumentMatchers.argThat(filter ->
+ filter.hasAction(BatteryManager.ACTION_CHARGING)
+ && filter.hasAction(BatteryManager.ACTION_DISCHARGING)));
when(mService.getMaxJobExecutionTimeMs(any())).thenReturn(10 * 60_000L);
+ final BroadcastReceiver chargingReceiver = chargingCaptor.getValue();
+ chargingReceiver.onReceive(mContext, new Intent(BatteryManager.ACTION_DISCHARGING));
// Slow network is too slow
assertFalse(controller.isSatisfied(createJobStatus(job), net,
@@ -166,7 +186,18 @@
assertTrue(controller.isSatisfied(createJobStatus(job), net,
createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(130)
.setLinkDownstreamBandwidthKbps(130).build(), mConstants));
+ // Slow network is too slow, but device is charging and network is unmetered.
+ when(mBatteryManagerInternal.isPowered(eq(BatteryManager.BATTERY_PLUGGED_ANY)))
+ .thenReturn(true);
+ chargingReceiver.onReceive(mContext, new Intent(BatteryManager.ACTION_CHARGING));
+ assertTrue(controller.isSatisfied(createJobStatus(job), net,
+ createCapabilitiesBuilder().addCapability(NET_CAPABILITY_NOT_METERED)
+ .setLinkUpstreamBandwidthKbps(1).setLinkDownstreamBandwidthKbps(1).build(),
+ mConstants));
+ when(mBatteryManagerInternal.isPowered(eq(BatteryManager.BATTERY_PLUGGED_ANY)))
+ .thenReturn(false);
+ chargingReceiver.onReceive(mContext, new Intent(BatteryManager.ACTION_DISCHARGING));
when(mService.getMaxJobExecutionTimeMs(any())).thenReturn(60_000L);
// Slow network is too slow
@@ -189,6 +220,14 @@
assertFalse(controller.isSatisfied(createJobStatus(job), net,
createCapabilitiesBuilder().setLinkUpstreamBandwidthKbps(130)
.setLinkDownstreamBandwidthKbps(130).build(), mConstants));
+ // Slow network is too slow, but device is charging and network is unmetered.
+ when(mBatteryManagerInternal.isPowered(eq(BatteryManager.BATTERY_PLUGGED_ANY)))
+ .thenReturn(true);
+ chargingReceiver.onReceive(mContext, new Intent(BatteryManager.ACTION_CHARGING));
+ assertTrue(controller.isSatisfied(createJobStatus(job), net,
+ createCapabilitiesBuilder().addCapability(NET_CAPABILITY_NOT_METERED)
+ .setLinkUpstreamBandwidthKbps(1).setLinkDownstreamBandwidthKbps(1).build(),
+ mConstants));
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeSettingsHelper.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeSettingsHelper.java
index 2e10107..f1099f0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeSettingsHelper.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeSettingsHelper.java
@@ -16,6 +16,7 @@
package com.android.server.location.injector;
+import android.os.PackageTagsList;
import android.os.UserHandle;
import android.util.IndentingPrintWriter;
import android.util.SparseArray;
@@ -40,7 +41,7 @@
private final CopyOnWriteArrayList<UserSettingChangedListener> mListeners;
- private Setting(Object defaultValue) {
+ Setting(Object defaultValue) {
mValues = new SparseArray<>();
mDefaultValue = defaultValue;
mListeners = new CopyOnWriteArrayList<>();
@@ -83,7 +84,8 @@
private final Setting mBackgroundThrottlePackageWhitelistSetting = new Setting(
Collections.emptySet());
private final Setting mGnssMeasurementsFullTrackingSetting = new Setting(Boolean.FALSE);
- private final Setting mIgnoreSettingsPackageWhitelist = new Setting(Collections.emptySet());
+ private final Setting mIgnoreSettingsAllowlist = new Setting(
+ new PackageTagsList.Builder().build());
private final Setting mBackgroundThrottleProximityAlertIntervalSetting = new Setting(
30 * 60 * 1000L);
private final Setting mCoarseLocationAccuracySetting = new Setting(2000.0f);
@@ -192,24 +194,24 @@
}
@Override
- public Set<String> getIgnoreSettingsPackageWhitelist() {
- return mIgnoreSettingsPackageWhitelist.getValue(Set.class);
+ public PackageTagsList getIgnoreSettingsAllowlist() {
+ return mIgnoreSettingsAllowlist.getValue(PackageTagsList.class);
}
- public void setIgnoreSettingsPackageWhitelist(Set<String> newValue) {
- mIgnoreSettingsPackageWhitelist.setValue(newValue);
+ public void setIgnoreSettingsAllowlist(PackageTagsList newValue) {
+ mIgnoreSettingsAllowlist.setValue(newValue);
}
@Override
- public void addOnIgnoreSettingsPackageWhitelistChangedListener(
+ public void addIgnoreSettingsAllowlistChangedListener(
GlobalSettingChangedListener listener) {
- mIgnoreSettingsPackageWhitelist.addListener(listener);
+ mIgnoreSettingsAllowlist.addListener(listener);
}
@Override
- public void removeOnIgnoreSettingsPackageWhitelistChangedListener(
+ public void removeIgnoreSettingsAllowlistChangedListener(
GlobalSettingChangedListener listener) {
- mIgnoreSettingsPackageWhitelist.removeListener(listener);
+ mIgnoreSettingsAllowlist.removeListener(listener);
}
@Override
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index 00246dd..6bc3b60 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -71,6 +71,7 @@
import android.os.Bundle;
import android.os.ICancellationSignal;
import android.os.IRemoteCallback;
+import android.os.PackageTagsList;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
@@ -923,8 +924,9 @@
@Test
public void testProviderRequest_IgnoreLocationSettings() {
- mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(
- Collections.singleton(IDENTITY.getPackageName()));
+ mInjector.getSettingsHelper().setIgnoreSettingsAllowlist(
+ new PackageTagsList.Builder().add(
+ IDENTITY.getPackageName()).build());
ILocationListener listener1 = createMockLocationListener();
LocationRequest request1 = new LocationRequest.Builder(5)
@@ -950,8 +952,9 @@
@Test
public void testProviderRequest_IgnoreLocationSettings_ProviderDisabled() {
- mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(
- Collections.singleton(IDENTITY.getPackageName()));
+ mInjector.getSettingsHelper().setIgnoreSettingsAllowlist(
+ new PackageTagsList.Builder().add(
+ IDENTITY.getPackageName()).build());
ILocationListener listener1 = createMockLocationListener();
LocationRequest request1 = new LocationRequest.Builder(1)
@@ -975,8 +978,9 @@
@Test
public void testProviderRequest_IgnoreLocationSettings_NoAllowlist() {
- mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(
- Collections.singleton(IDENTITY.getPackageName()));
+ mInjector.getSettingsHelper().setIgnoreSettingsAllowlist(
+ new PackageTagsList.Builder().add(
+ IDENTITY.getPackageName()).build());
ILocationListener listener = createMockLocationListener();
LocationRequest request = new LocationRequest.Builder(1)
@@ -985,7 +989,8 @@
.build();
mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
- mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(Collections.emptySet());
+ mInjector.getSettingsHelper().setIgnoreSettingsAllowlist(
+ new PackageTagsList.Builder().build());
assertThat(mProvider.getRequest().isActive()).isTrue();
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(1);
@@ -994,8 +999,9 @@
@Test
public void testProviderRequest_BackgroundThrottle_IgnoreLocationSettings() {
- mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(
- Collections.singleton(IDENTITY.getPackageName()));
+ mInjector.getSettingsHelper().setIgnoreSettingsAllowlist(
+ new PackageTagsList.Builder().add(
+ IDENTITY.getPackageName()).build());
ILocationListener listener1 = createMockLocationListener();
LocationRequest request1 = new LocationRequest.Builder(5)
diff --git a/services/tests/servicestests/src/com/android/server/am/FgsTempAllowListTest.java b/services/tests/servicestests/src/com/android/server/am/FgsTempAllowListTest.java
index f85f0f8..50d4d84 100644
--- a/services/tests/servicestests/src/com/android/server/am/FgsTempAllowListTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/FgsTempAllowListTest.java
@@ -29,6 +29,9 @@
import org.junit.Test;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+
/**
* Build/Install/Run:
* atest FrameworksServicesTests:TempAllowListTest
@@ -41,7 +44,7 @@
*/
@Test
public void testIsAllowed() {
- FgsTempAllowList<Integer, String> allowList = new FgsTempAllowList();
+ FgsTempAllowList<String> allowList = new FgsTempAllowList();
allowList.add(10001, 2000, "description1");
allowList.add(10002, 2000, "description2");
@@ -55,7 +58,7 @@
assertNotNull(entry2);
assertEquals(entry2.second, "description2");
- allowList.remove(10001);
+ allowList.removeUid(10001);
assertFalse(allowList.isAllowed(10001));
assertNull(allowList.get(10001));
}
@@ -65,7 +68,7 @@
*/
@Test
public void testExpired() {
- FgsTempAllowList<Integer, String> allowList = new FgsTempAllowList();
+ FgsTempAllowList<String> allowList = new FgsTempAllowList();
// temp allow for 2000ms.
allowList.add(10001, 2000, "uid1-2000ms");
// sleep for 3000ms.
@@ -74,4 +77,51 @@
assertFalse(allowList.isAllowed(10001));
assertNull(allowList.get(10001));
}
+
+ @Test
+ public void testRemoveAppId() {
+ FgsTempAllowList<String> allowList = new FgsTempAllowList();
+ allowList.add(10001, 2000, "description1");
+ allowList.add(10002, 2000, "description2");
+ allowList.add(10_10001, 2000, "description3");
+
+ assertTrue(allowList.isAllowed(10001));
+ assertTrue(allowList.isAllowed(10002));
+ assertTrue(allowList.isAllowed(10_10001));
+
+ allowList.removeAppId(10001);
+
+ assertFalse(allowList.isAllowed(10001));
+ assertTrue(allowList.isAllowed(10002));
+ assertFalse(allowList.isAllowed(10_10001));
+ }
+
+ @Test
+ public void testForEach() {
+ final FgsTempAllowList<String> allowList = new FgsTempAllowList();
+
+
+ // Call forEach(), return the sum of all the UIDs, and make sure the item is
+ // "uid" + uid.
+ final Supplier<Integer> callForEach = () -> {
+ final AtomicInteger sum = new AtomicInteger();
+ sum.set(0);
+ allowList.forEach((uid, entry) -> {
+ sum.set(sum.get() + uid);
+ assertEquals(entry.second, "uid" + uid);
+ });
+ return sum.get();
+ };
+
+ // Call on th empty list.
+ assertEquals(0, (int) callForEach.get());
+
+ // Add one item.
+ allowList.add(1, 2000, "uid1");
+ assertEquals(1, (int) callForEach.get());
+
+ // Add one more item.
+ allowList.add(10, 2000, "uid10");
+ assertEquals(11, (int) callForEach.get());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
index 96bab61..4afb7dd 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
@@ -38,6 +38,7 @@
import android.app.admin.DevicePolicyManager;
import android.app.trust.ITrustManager;
import android.content.Context;
+import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.IBiometricAuthenticator;
@@ -170,21 +171,42 @@
session.onCookieReceived(cookie2);
assertTrue(session.allCookiesReceived());
+
+ // for multi-sensor face then fingerprint is the default policy
for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
- verify(sensor.impl).startPreparedClient(eq(sensor.getCookie()));
- assertEquals(BiometricSensor.STATE_AUTHENTICATING, sensor.getSensorState());
+ if (sensor.modality == TYPE_FACE) {
+ verify(sensor.impl).startPreparedClient(eq(sensor.getCookie()));
+ assertEquals(BiometricSensor.STATE_AUTHENTICATING, sensor.getSensorState());
+ } else if (sensor.modality == TYPE_FINGERPRINT) {
+ assertEquals(BiometricSensor.STATE_COOKIE_RETURNED, sensor.getSensorState());
+ }
}
}
@Test
- public void testUdfpsAuth_sensorStartsAfterDialogAnimationCompletes() throws RemoteException {
- // For UDFPS-only setups, ensure that the sensor does not start auth until after the
- // BiometricPrompt UI is finished animating. Otherwise, the UDFPS affordance will be
- // shown before the BiometricPrompt is shown.
+ public void testMultiAuth_singleSensor_fingerprintSensorStartsAfterDialogAnimationCompletes()
+ throws Exception {
setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
+ testMultiAuth_fingerprintSensorStartsAfter(false /* fingerprintStartsAfterDelay */);
+ }
+ @Test
+ public void testMultiAuth_fingerprintSensorStartsAfterDialogAnimationCompletes()
+ throws Exception {
+ setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
+ setupFace(1 /* id */, false, mock(IBiometricAuthenticator.class));
+ testMultiAuth_fingerprintSensorStartsAfter(true /* fingerprintStartsAfterDelay */);
+ }
+
+ public void testMultiAuth_fingerprintSensorStartsAfter(boolean fingerprintStartsAfterDelay)
+ throws Exception {
final long operationId = 123;
final int userId = 10;
+ final int fingerprintSensorId = mSensors.stream()
+ .filter(s -> s.modality == TYPE_FINGERPRINT)
+ .map(s -> s.id)
+ .findFirst()
+ .orElse(-1);
final AuthSession session = createAuthSession(mSensors,
false /* checkDevicePolicyManager */,
@@ -200,27 +222,37 @@
session.goToInitialState();
- final int cookie1 = session.mPreAuthInfo.eligibleSensors.get(0).getCookie();
- session.onCookieReceived(cookie1);
for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
- if (cookie1 == sensor.getCookie()) {
+ assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState());
+ session.onCookieReceived(
+ session.mPreAuthInfo.eligibleSensors.get(sensor.id).getCookie());
+ if (fingerprintSensorId == sensor.id) {
assertEquals(BiometricSensor.STATE_COOKIE_RETURNED, sensor.getSensorState());
} else {
- assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState());
+ assertEquals(BiometricSensor.STATE_AUTHENTICATING, sensor.getSensorState());
}
}
assertTrue(session.allCookiesReceived());
- // UDFPS does not start even if all cookies are received
+ // fingerprint sensor does not start even if all cookies are received
assertEquals(STATE_AUTH_STARTED, session.getState());
verify(mStatusBarService).showAuthenticationDialog(any(), any(), any(),
- anyBoolean(), anyBoolean(), anyInt(), any(), anyLong());
+ anyBoolean(), anyBoolean(), anyInt(), any(), anyLong(), anyInt());
- // Notify AuthSession that the UI is shown. Then, UDFPS sensor should be started.
+ // Notify AuthSession that the UI is shown. Then, fingerprint sensor should be started.
session.onDialogAnimatedIn();
+ if (fingerprintStartsAfterDelay) {
+ assertEquals(STATE_AUTH_STARTED_UI_SHOWING, session.getState());
+ assertEquals(BiometricSensor.STATE_COOKIE_RETURNED,
+ session.mPreAuthInfo.eligibleSensors.get(fingerprintSensorId).getSensorState());
+ session.onErrorReceived(fingerprintSensorId,
+ session.mPreAuthInfo.eligibleSensors.get(fingerprintSensorId).getCookie(),
+ BiometricConstants.BIOMETRIC_ERROR_VENDOR, 0 /* vendorCode */);
+ session.onStartFingerprint();
+ }
assertEquals(STATE_AUTH_STARTED_UI_SHOWING, session.getState());
assertEquals(BiometricSensor.STATE_AUTHENTICATING,
- session.mPreAuthInfo.eligibleSensors.get(0).getSensorState());
+ session.mPreAuthInfo.eligibleSensors.get(fingerprintSensorId).getSensorState());
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index ec3bea3..98777ac 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -17,8 +17,17 @@
package com.android.server.biometrics;
import static android.hardware.biometrics.BiometricManager.Authenticators;
+import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT;
-import static com.android.server.biometrics.BiometricServiceStateProto.*;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTHENTICATED_PENDING_SYSUI;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_CALLED;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_PAUSED;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_PAUSED_RESUMING;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_PENDING_CONFIRM;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_AUTH_STARTED;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_CLIENT_DIED_CANCELLING;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_ERROR_PENDING_SYSUI;
+import static com.android.server.biometrics.BiometricServiceStateProto.STATE_SHOWING_DEVICE_CREDENTIAL;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -264,7 +273,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
}
@Test
@@ -348,7 +358,8 @@
eq(false) /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
}
@Test
@@ -465,6 +476,7 @@
assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState());
// startPreparedClient invoked
+ mBiometricService.mCurrentAuthSession.onDialogAnimatedIn();
verify(mBiometricService.mSensors.get(0).impl)
.startPreparedClient(cookieCaptor.getValue());
@@ -477,7 +489,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
// Hardware authenticated
final byte[] HAT = generateRandomHAT();
@@ -531,7 +544,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
}
@Test
@@ -692,7 +706,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
anyString(),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
}
@Test
@@ -791,7 +806,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
}
@Test
@@ -870,7 +886,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
}
@Test
@@ -1367,7 +1384,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
// Requesting strong and credential, when credential is setup
resetReceivers();
@@ -1388,7 +1406,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
// Un-downgrading the authenticator allows successful strong auth
for (BiometricSensor sensor : mBiometricService.mSensors) {
@@ -1412,7 +1431,8 @@
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */);
+ anyLong() /* sessionId */,
+ eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
}
@Test(expected = IllegalStateException.class)
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 bfdf5af..654d9fc 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4030,7 +4030,7 @@
}
@Test
- public void testUpdateNetworkPreferenceOnStartOnStopUser() throws Exception {
+ public void testUpdateNetworkPreferenceOnStartUser() throws Exception {
final int managedProfileUserId = 15;
final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
addManagedProfile(admin1, managedProfileAdminUid, admin1);
@@ -4044,6 +4044,15 @@
any(),
any()
);
+ }
+
+ @Test
+ public void testUpdateNetworkPreferenceOnStopUser() throws Exception {
+ final int managedProfileUserId = 15;
+ final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
+ addManagedProfile(admin1, managedProfileAdminUid, admin1);
+ mContext.binder.callingUid = managedProfileAdminUid;
+ mServiceContext.permissions.add(permission.INTERACT_ACROSS_USERS_FULL);
dpms.handleStopUser(managedProfileUserId);
verify(getServices().connectivityManager, times(1)).setProfileNetworkPreference(
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
index 4cd17e8..b820df3 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/OneTouchPlayActionTest.java
@@ -37,7 +37,6 @@
import android.os.Looper;
import android.os.PowerManager;
import android.os.test.TestLooper;
-import android.provider.Settings;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -51,6 +50,7 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.Collections;
/** Tests for {@link OneTouchPlayAction} */
@SmallTest
@@ -69,6 +69,7 @@
private Context mContextSpy;
private HdmiControlService mHdmiControlService;
private FakeNativeWrapper mNativeWrapper;
+ private FakeHdmiCecConfig mHdmiCecConfig;
private TestLooper mTestLooper = new TestLooper();
private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
@@ -88,6 +89,7 @@
MockitoAnnotations.initMocks(this);
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
+ mHdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
setHdmiControlEnabled(hdmiControlEnabled);
@@ -99,7 +101,7 @@
mIThermalServiceMock, new Handler(mTestLooper.getLooper())));
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
- mHdmiControlService = new HdmiControlService(mContextSpy) {
+ mHdmiControlService = new HdmiControlService(mContextSpy, Collections.emptyList()) {
@Override
AudioManager getAudioManager() {
return new AudioManager() {
@@ -134,7 +136,7 @@
Looper looper = mTestLooper.getLooper();
mHdmiControlService.setIoLooper(looper);
- mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(mContextSpy));
+ mHdmiControlService.setHdmiCecConfig(mHdmiCecConfig);
mNativeWrapper = new FakeNativeWrapper();
HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
@@ -479,7 +481,7 @@
mTestLooper.dispatchAll();
assertThat(callback.hasResult()).isFalse();
- assertThat(playbackDevice.isActiveSource()).isFalse();
+ mNativeWrapper.clearResultMessages();
setHdmiControlEnabled(true);
mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
@@ -498,6 +500,12 @@
assertThat(mHdmiControlService.isAddressAllocated()).isTrue();
assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
assertThat(playbackDevice.isActiveSource()).isTrue();
+ HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
+ playbackDevice.mAddress, mPhysicalAddress);
+ HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
+ ADDR_TV);
+ assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+ assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
}
@Test
@@ -527,6 +535,12 @@
assertThat(callback.getResult()).isEqualTo(HdmiControlManager.RESULT_SUCCESS);
assertThat(playbackDevice.isActiveSource()).isTrue();
+ HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
+ playbackDevice.mAddress, mPhysicalAddress);
+ HdmiCecMessage textViewOn = HdmiCecMessageBuilder.buildTextViewOn(playbackDevice.mAddress,
+ ADDR_TV);
+ assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
+ assertThat(mNativeWrapper.getResultMessages()).contains(textViewOn);
}
@Test
@@ -602,8 +616,8 @@
}
private void setHdmiControlEnabled(boolean enabled) {
- int value = enabled ? 1 : 0;
- Settings.Global.putInt(mContextSpy.getContentResolver(),
- Settings.Global.HDMI_CONTROL_ENABLED, value);
+ int value = enabled ? HdmiControlManager.HDMI_CEC_CONTROL_ENABLED :
+ HdmiControlManager.HDMI_CEC_CONTROL_DISABLED;
+ mHdmiCecConfig.setIntValue(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED, value);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index aecc794..b01c1c8 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -165,7 +165,17 @@
mRebootEscrow = null;
mServerBased = true;
RebootEscrowProviderServerBasedImpl.Injector injector =
- new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection);
+ new RebootEscrowProviderServerBasedImpl.Injector(serviceConnection) {
+ @Override
+ long getServiceTimeoutInSeconds() {
+ return 30;
+ }
+
+ @Override
+ long getServerBlobLifetimeInMillis() {
+ return 600_000;
+ }
+ };
mDefaultRebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(
storage, injector);
mUserManager = userManager;
@@ -189,6 +199,11 @@
}
@Override
+ public boolean isNetworkConnected() {
+ return false;
+ }
+
+ @Override
public RebootEscrowProviderInterface createRebootEscrowProviderIfNeeded() {
mRebootEscrowProviderInUse = mDefaultRebootEscrowProvider;
return mRebootEscrowProviderInUse;
@@ -602,7 +617,7 @@
// Sleep 5s for the retry to complete
Thread.sleep(5 * 1000);
assertFalse(metricsSuccessCaptor.getValue());
- assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_RETRY_COUNT_EXHAUSTED),
+ assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_NO_NETWORK),
metricsErrorCodeCaptor.getValue());
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
index ef5f00b..fdb6e9f5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
@@ -28,8 +28,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import org.mockito.Mock;
import org.mockito.InOrder;
+import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.IOException;
@@ -277,7 +277,7 @@
UID,
COMPILATION_REASON,
COMPILER_FILTER,
- ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES,
+ ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_COUNTER_BYTES,
DEX_CONTENT.length,
dexMetadataType,
ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
@@ -287,7 +287,7 @@
UID,
COMPILATION_REASON,
COMPILER_FILTER,
- ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME,
+ ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME_COUNTER_MILLIS,
COMPILE_TIME,
dexMetadataType,
ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 874f8dc..38f976c 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -923,6 +923,47 @@
}
@Test
+ public void testRemovedDisplayGroupWakeLock_affectsNoDisplayGroups() throws Exception {
+ final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+ final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
+ final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+ new AtomicReference<>();
+ doAnswer((Answer<Void>) invocation -> {
+ listener.set(invocation.getArgument(0));
+ return null;
+ }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+ final DisplayInfo info = new DisplayInfo();
+ info.displayGroupId = nonDefaultDisplayGroupId;
+ when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info);
+
+ final String pkg = mContextSpy.getOpPackageName();
+ final Binder token = new Binder();
+ final String tag = "testRemovedDisplayGroupWakeLock_affectsNoDisplayGroups";
+
+ setMinimumScreenOffTimeoutConfig(5);
+ createService();
+ startSystem();
+ listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+
+ mService.getBinderServiceInstance().acquireWakeLock(token,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, tag, pkg,
+ null /* workSource */, null /* historyTag */, nonDefaultDisplay);
+
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+ WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+
+ listener.get().onDisplayGroupRemoved(nonDefaultDisplayGroupId);
+
+ advanceTime(15000);
+ assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+ WAKEFULNESS_DOZING);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+ }
+
+ @Test
public void testBoot_ShouldBeAwake() throws Exception {
createService();
startSystem();
diff --git a/services/tests/servicestests/src/com/android/server/power/WakeLockLogTest.java b/services/tests/servicestests/src/com/android/server/power/WakeLockLogTest.java
index a03ba9c..09612e3 100644
--- a/services/tests/servicestests/src/com/android/server/power/WakeLockLogTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/WakeLockLogTest.java
@@ -20,12 +20,8 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
-import android.os.Looper;
import android.os.PowerManager;
-import android.os.test.TestLooper;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
import java.io.PrintWriter;
@@ -38,17 +34,6 @@
*/
public class WakeLockLogTest {
- private TestLooper mTestLooper;
-
- @Before
- public void setUp() throws Exception {
- mTestLooper = new TestLooper();
- }
-
- @After
- public void tearDown() throws Exception {
- }
-
@Test
public void testAddTwoItems() {
final int tagDatabaseSize = 128;
@@ -70,7 +55,7 @@
+ " -\n"
+ " Events: 2, Time-Resets: 0\n"
+ " Buffer, Bytes used: 6\n",
- dispatchAndDump(log, false));
+ dumpLog(log, false));
}
@Test
@@ -92,7 +77,7 @@
+ " -\n"
+ " Events: 2, Time-Resets: 1\n"
+ " Buffer, Bytes used: 15\n",
- dispatchAndDump(log, false));
+ dumpLog(log, false));
}
@Test
@@ -114,7 +99,7 @@
+ " -\n"
+ " Events: 2, Time-Resets: 0\n"
+ " Buffer, Bytes used: 6\n",
- dispatchAndDump(log, false));
+ dumpLog(log, false));
}
@Test
@@ -142,7 +127,7 @@
+ " -\n"
+ " Events: 3, Time-Resets: 0\n"
+ " Buffer, Bytes used: 9\n",
- dispatchAndDump(log, false));
+ dumpLog(log, false));
}
@Test
@@ -160,7 +145,7 @@
+ " -\n"
+ " Events: 0, Time-Resets: 0\n"
+ " Buffer, Bytes used: 0\n",
- dispatchAndDump(log, false));
+ dumpLog(log, false));
}
@Test
@@ -179,7 +164,7 @@
+ " -\n"
+ " Events: 1, Time-Resets: 0\n"
+ " Buffer, Bytes used: 3\n",
- dispatchAndDump(log, false));
+ dumpLog(log, false));
}
@Test
@@ -201,7 +186,7 @@
+ " Events: 2, Time-Resets: 0\n"
+ " Buffer, Bytes used: 5\n"
+ " Tag Database: size(5), entries: 1, Bytes used: 80\n",
- dispatchAndDump(log, true));
+ dumpLog(log, true));
}
@Test
@@ -223,11 +208,10 @@
+ " -\n"
+ " Events: 1, Time-Resets: 0\n"
+ " Buffer, Bytes used: 3\n",
- dispatchAndDump(log, false));
+ dumpLog(log, false));
}
- private String dispatchAndDump(WakeLockLog log, boolean includeTagDb) {
- mTestLooper.dispatchAll();
+ private String dumpLog(WakeLockLog log, boolean includeTagDb) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
log.dump(pw, includeTagDb);
@@ -244,11 +228,6 @@
}
@Override
- public Looper getLooper() {
- return mTestLooper.getLooper();
- }
-
- @Override
public int getTagDatabaseSize() {
return mTagDatabaseSize;
}
diff --git a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
index 9679e58..5db9492 100644
--- a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
@@ -22,6 +22,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import android.util.LongSparseArray;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -34,9 +35,12 @@
import org.junit.Test;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Random;
/**
- * Test class for {@link Watcher}, {@link Watchable}, {@link WatchableImpl},
+ * Test class for various utility classes that support the Watchable or Snappable
+ * features. This covers {@link Watcher}, {@link Watchable}, {@link WatchableImpl},
* {@link WatchedArrayMap}, {@link WatchedSparseArray}, and
* {@link WatchedSparseBooleanArray}.
*
@@ -858,6 +862,93 @@
}
}
+ private static class IndexGenerator {
+ private final int mSeed;
+ private final Random mRandom;
+ public IndexGenerator(int seed) {
+ mSeed = seed;
+ mRandom = new Random(mSeed);
+ }
+ public int index() {
+ return mRandom.nextInt(50000);
+ }
+ public void reset() {
+ mRandom.setSeed(mSeed);
+ }
+ }
+
+ // Return a value based on the row and column. The algorithm tries to avoid simple
+ // patterns like checkerboard.
+ private final boolean cellValue(int row, int col) {
+ return (((row * 4 + col) % 3)& 1) == 1;
+ }
+
+ // This is an inefficient way to know if a value appears in an array.
+ private final boolean contains(int[] s, int length, int k) {
+ for (int i = 0; i < length; i++) {
+ if (s[i] == k) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void matrixTest(WatchedSparseBooleanMatrix matrix, int size, IndexGenerator indexer) {
+ indexer.reset();
+ int[] indexes = new int[size];
+ for (int i = 0; i < size; i++) {
+ int key = indexer.index();
+ // Ensure the list of indices are unique.
+ while (contains(indexes, i, key)) {
+ key = indexer.index();
+ }
+ indexes[i] = key;
+ }
+ // Set values in the matrix.
+ for (int i = 0; i < size; i++) {
+ int row = indexes[i];
+ for (int j = 0; j < size; j++) {
+ int col = indexes[j];
+ boolean want = cellValue(i, j);
+ matrix.put(row, col, want);
+ }
+ }
+
+ assertEquals(matrix.size(), size);
+
+ // Read back and verify
+ for (int i = 0; i < matrix.size(); i++) {
+ int row = indexes[i];
+ for (int j = 0; j < matrix.size(); j++) {
+ int col = indexes[j];
+ boolean want = cellValue(i, j);
+ boolean actual = matrix.get(row, col);
+ String msg = String.format("matrix(%d:%d, %d:%d) == %s, expected %s",
+ i, row, j, col, actual, want);
+ assertEquals(msg, actual, want);
+ }
+ }
+
+ // Test the keyAt/indexOfKey methods
+ for (int i = 0; i < matrix.size(); i++) {
+ int key = indexes[i];
+ assertEquals(matrix.keyAt(matrix.indexOfKey(key)), key);
+ }
+ }
+
+ @Test
+ public void testWatchedSparseBooleanMatrix() {
+ final String name = "WatchedSparseBooleanMatrix";
+
+ // The first part of this method tests the core matrix functionality. The second
+ // part tests the watchable behavior. The third part tests the snappable
+ // behavior.
+ IndexGenerator indexer = new IndexGenerator(3);
+ matrixTest(new WatchedSparseBooleanMatrix(), 10, indexer);
+ matrixTest(new WatchedSparseBooleanMatrix(1000), 500, indexer);
+ matrixTest(new WatchedSparseBooleanMatrix(1000), 2000, indexer);
+ }
+
@Test
public void testNestedArrays() {
final String name = "NestedArrays";
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 985b2d5..c2298d0 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -42,6 +42,7 @@
<uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
<uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
<uses-permission android:name="android.permission.CAPTURE_BLACKOUT_CONTENT"/>
+ <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
<!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) -->
<application android:debuggable="true"
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 5a0466a..03304bb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -65,6 +65,7 @@
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.InsetsState;
+import android.view.PrivacyIndicatorBounds;
import android.view.RoundedCorners;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Type;
@@ -176,7 +177,7 @@
? mDisplayContent.calculateRoundedCornersForRotation(mRotation)
: RoundedCorners.NO_ROUNDED_CORNERS;
return new DisplayFrames(mDisplayContent.getDisplayId(),
- insetsState, info.first, info.second, roundedCorners);
+ insetsState, info.first, info.second, roundedCorners, new PrivacyIndicatorBounds());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 2ca7853..b793be7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -54,6 +54,7 @@
import android.view.DisplayInfo;
import android.view.InsetsSource;
import android.view.InsetsState;
+import android.view.PrivacyIndicatorBounds;
import android.view.WindowInsets.Side;
import android.view.WindowManager;
@@ -317,7 +318,7 @@
final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
mImeWindow.mAboveInsetsState.set(state);
mDisplayContent.mDisplayFrames = new DisplayFrames(mDisplayContent.getDisplayId(),
- state, displayInfo, NO_CUTOUT, NO_ROUNDED_CORNERS);
+ state, displayInfo, NO_CUTOUT, NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds());
mDisplayContent.setInputMethodWindowLocked(mImeWindow);
mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 7224a0e..8e3bb69 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -24,6 +24,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS;
import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
@@ -54,6 +55,7 @@
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doCallRealMethod;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.WindowConfiguration;
@@ -64,6 +66,8 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
import android.view.WindowManager;
import androidx.test.filters.MediumTest;
@@ -71,6 +75,8 @@
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
@@ -91,6 +97,19 @@
private Task mTask;
private ActivityRecord mActivity;
+ private Properties mInitialConstrainDisplayApisFlags;
+
+ @Before
+ public void setUp() throws Exception {
+ mInitialConstrainDisplayApisFlags = DeviceConfig.getProperties(
+ NAMESPACE_CONSTRAIN_DISPLAY_APIS);
+ clearConstrainDisplayApisFlags();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ DeviceConfig.setProperties(mInitialConstrainDisplayApisFlags);
+ }
private void setUpApp(DisplayContent display) {
mTask = new TaskBuilder(mSupervisor).setDisplay(display).setCreateActivity(true).build();
@@ -791,6 +810,90 @@
}
@Test
+ public void testNeverConstrainDisplayApisDeviceConfig_allPackagesFlagTrue_sandboxNotApplied() {
+ setUpDisplaySizeWithApp(1000, 1200);
+
+ setNeverConstrainDisplayApisAllPackagesFlag("true");
+ // Setting 'never_constrain_display_apis' as well to make sure it is ignored.
+ setNeverConstrainDisplayApisFlag("com.android.other::,com.android.other2::");
+
+ // Make the task root resizable.
+ mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE;
+
+ // Create an activity with a max aspect ratio on the same task.
+ final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false,
+ RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE);
+
+ // Activity max bounds should not be sandboxed, even though it is letterboxed.
+ assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertThat(activity.getConfiguration().windowConfiguration.getMaxBounds())
+ .isEqualTo(activity.getDisplayArea().getBounds());
+ }
+
+ @Test
+ public void testNeverConstrainDisplayApisDeviceConfig_packageInRange_sandboxingNotApplied() {
+ setUpDisplaySizeWithApp(1000, 1200);
+
+ setNeverConstrainDisplayApisFlag(
+ "com.android.frameworks.wmtests:20:,com.android.other::,"
+ + "com.android.frameworks.wmtests:0:10");
+
+ // Make the task root resizable.
+ mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE;
+
+ // Create an activity with a max aspect ratio on the same task.
+ final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false,
+ RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE);
+
+ // Activity max bounds should not be sandboxed, even though it is letterboxed.
+ assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertThat(activity.getConfiguration().windowConfiguration.getMaxBounds())
+ .isEqualTo(activity.getDisplayArea().getBounds());
+ }
+
+ @Test
+ public void testNeverConstrainDisplayApisDeviceConfig_packageOutsideRange_sandboxingApplied() {
+ setUpDisplaySizeWithApp(1000, 1200);
+
+ setNeverConstrainDisplayApisFlag("com.android.other::,com.android.frameworks.wmtests:1:5");
+
+ // Make the task root resizable.
+ mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE;
+
+ // Create an activity with a max aspect ratio on the same task.
+ final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false,
+ RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE);
+
+ // Activity max bounds should be sandboxed due to letterboxed and the mismatch with flag.
+ assertActivityMaxBoundsSandboxed(activity);
+ }
+
+ @Test
+ public void testNeverConstrainDisplayApisDeviceConfig_packageNotInFlag_sandboxingApplied() {
+ setUpDisplaySizeWithApp(1000, 1200);
+
+ setNeverConstrainDisplayApisFlag("com.android.other::,com.android.other2::");
+
+ // Make the task root resizable.
+ mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE;
+
+ // Create an activity with a max aspect ratio on the same task.
+ final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false,
+ RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+ prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE);
+
+ // Activity max bounds should be sandboxed due to letterboxed and the mismatch with flag.
+ assertActivityMaxBoundsSandboxed(activity);
+ }
+
+ @Test
@EnableCompatChanges({ActivityInfo.ALWAYS_SANDBOX_DISPLAY_APIS})
public void testAlwaysSandboxDisplayApis_configEnabled_sandboxingApplied_unresizable() {
setUpDisplaySizeWithApp(1000, 1200);
@@ -1927,4 +2030,20 @@
displayContent.computeScreenConfiguration(c);
displayContent.onRequestedOverrideConfigurationChanged(c);
}
+
+ private static void setNeverConstrainDisplayApisFlag(@Nullable String value) {
+ DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, "never_constrain_display_apis",
+ value, /* makeDefault= */ false);
+ }
+
+ private static void setNeverConstrainDisplayApisAllPackagesFlag(@Nullable String value) {
+ DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS,
+ "never_constrain_display_apis_all_packages",
+ value, /* makeDefault= */ false);
+ }
+
+ private static void clearConstrainDisplayApisFlags() {
+ setNeverConstrainDisplayApisFlag(null);
+ setNeverConstrainDisplayApisAllPackagesFlag(null);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index 8b4e947..ada58a5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -49,6 +49,7 @@
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.InsetsState;
+import android.view.PrivacyIndicatorBounds;
import android.view.RoundedCorners;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -152,7 +153,7 @@
final DisplayInfo info = dc.computeScreenConfiguration(config, Surface.ROTATION_0);
final WmDisplayCutout cutout = dc.calculateDisplayCutoutForRotation(Surface.ROTATION_0);
final DisplayFrames displayFrames = new DisplayFrames(dc.getDisplayId(), new InsetsState(),
- info, cutout, RoundedCorners.NO_ROUNDED_CORNERS);
+ info, cutout, RoundedCorners.NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds());
wallpaperWindowToken.applyFixedRotationTransform(info, displayFrames, config);
// Check that the wallpaper has the same frame in landscape than in portrait
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index aec0643..0bb09a9 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -287,6 +287,8 @@
Slog.d(TAG, "stopListening");
}
+ mRemoteHotwordDetectionService.run(service -> service.stopDetection());
+
synchronized (mLock) {
if (mCurrentAudioSink != null) {
Slog.i(TAG, "Closing audio stream to hotword detector: stopping requested");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 9be1ac4..2206b0a 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -22,6 +22,7 @@
import static android.app.ActivityManager.START_VOICE_NOT_ACTIVE_SESSION;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -36,7 +37,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
@@ -414,11 +414,31 @@
Slog.w(TAG, "Hotword detection service name not found");
throw new IllegalStateException("Hotword detection service name not found");
}
- if (!isIsolatedProcessLocked(mHotwordDetectionComponentName)) {
+ ServiceInfo hotwordDetectionServiceInfo = getServiceInfoLocked(
+ mHotwordDetectionComponentName, mUser);
+ if (hotwordDetectionServiceInfo == null) {
+ Slog.w(TAG, "Hotword detection service info not found");
+ throw new IllegalStateException("Hotword detection service info not found");
+ }
+ if (!isIsolatedProcessLocked(hotwordDetectionServiceInfo)) {
Slog.w(TAG, "Hotword detection service not in isolated process");
throw new IllegalStateException("Hotword detection service not in isolated process");
}
- // TODO : Need to check related permissions for hotword detection service
+ if (!Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE.equals(
+ hotwordDetectionServiceInfo.permission)) {
+ Slog.w(TAG, "Hotword detection service does not require permission "
+ + Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
+ throw new SecurityException("Hotword detection service does not require permission "
+ + Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
+ }
+ if (mContext.getPackageManager().checkPermission(
+ Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE,
+ mInfo.getServiceInfo().packageName) == PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "Voice interaction service should not hold permission "
+ + Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
+ throw new SecurityException("Voice interaction service should not hold permission "
+ + Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
+ }
if (sharedMemory != null && !sharedMemory.setProtect(OsConstants.PROT_READ)) {
Slog.w(TAG, "Can't set sharedMemory to be read-only");
@@ -522,23 +542,24 @@
mHotwordDetectionConnection);
}
- boolean isIsolatedProcessLocked(ComponentName componentName) {
- IPackageManager pm = AppGlobals.getPackageManager();
+ private static ServiceInfo getServiceInfoLocked(@NonNull ComponentName componentName,
+ int userHandle) {
try {
- ServiceInfo serviceInfo = pm.getServiceInfo(componentName,
+ return AppGlobals.getPackageManager().getServiceInfo(componentName,
PackageManager.GET_META_DATA
| PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, mUser);
- if (serviceInfo != null) {
- return (serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0
- && (serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) == 0;
- }
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle);
} catch (RemoteException e) {
if (DEBUG) {
- Slog.w(TAG, "isIsolatedProcess RemoteException : " + e);
+ Slog.w(TAG, "getServiceInfoLocked RemoteException : " + e);
}
}
- return false;
+ return null;
+ }
+
+ boolean isIsolatedProcessLocked(@NonNull ServiceInfo serviceInfo) {
+ return (serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0
+ && (serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) == 0;
}
public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/telecomm/java/android/telecom/CallDiagnosticService.java b/telecomm/java/android/telecom/CallDiagnosticService.java
index 011dc17..336a8ea 100644
--- a/telecomm/java/android/telecom/CallDiagnosticService.java
+++ b/telecomm/java/android/telecom/CallDiagnosticService.java
@@ -294,6 +294,10 @@
CallDiagnostics callDiagnostics;
synchronized (mLock) {
callDiagnostics = mDiagnosticCallByTelecomCallId.get(telecomCallId);
+ if (callDiagnostics == null) {
+ // Possible to get a call update after a call is removed.
+ return;
+ }
mCallByTelecomCallId.put(telecomCallId, newCallDetails);
}
getExecutor().execute(() -> callDiagnostics.handleCallUpdated(newCallDetails));
@@ -306,12 +310,12 @@
private void handleCallRemoved(@NonNull String telecomCallId) {
Log.i(this, "handleCallRemoved: callId=%s - removed", telecomCallId);
- if (mCallByTelecomCallId.containsKey(telecomCallId)) {
- mCallByTelecomCallId.remove(telecomCallId);
- }
-
CallDiagnostics callDiagnostics;
synchronized (mLock) {
+ if (mCallByTelecomCallId.containsKey(telecomCallId)) {
+ mCallByTelecomCallId.remove(telecomCallId);
+ }
+
if (mDiagnosticCallByTelecomCallId.containsKey(telecomCallId)) {
callDiagnostics = mDiagnosticCallByTelecomCallId.remove(telecomCallId);
} else {
@@ -353,7 +357,10 @@
private void handleCallDisconnected(@NonNull String callId,
@NonNull DisconnectCause disconnectCause) {
Log.i(this, "handleCallDisconnected: call=%s; cause=%s", callId, disconnectCause);
- CallDiagnostics callDiagnostics = mDiagnosticCallByTelecomCallId.get(callId);
+ CallDiagnostics callDiagnostics;
+ synchronized (mLock) {
+ callDiagnostics = mDiagnosticCallByTelecomCallId.get(callId);
+ }
CharSequence message;
if (disconnectCause.getImsReasonInfo() != null) {
message = callDiagnostics.onCallDisconnected(disconnectCause.getImsReasonInfo());
@@ -391,7 +398,9 @@
@NonNull CallQuality callQuality) {
Log.i(this, "handleCallQualityChanged; call=%s, cq=%s", callId, callQuality);
CallDiagnostics callDiagnostics;
- callDiagnostics = mDiagnosticCallByTelecomCallId.get(callId);
+ synchronized(mLock) {
+ callDiagnostics = mDiagnosticCallByTelecomCallId.get(callId);
+ }
if (callDiagnostics != null) {
callDiagnostics.onCallQualityReceived(callQuality);
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c527e66..6b7fc2f 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3682,6 +3682,13 @@
"emergency_number_prefix_string_array";
/**
+ * Indicates whether carrier treats "*67" or "*82" as a temporary mode CLIR.
+ * @hide
+ */
+ public static final String KEY_CARRIER_SUPPORTS_CALLER_ID_VERTICAL_SERVICE_CODES_BOOL =
+ "carrier_supports_caller_id_vertical_service_codes_bool";
+
+ /**
* Smart forwarding config. Smart forwarding is a feature to configure call forwarding to a
* different SIM in the device when one SIM is not reachable. The config here specifies a smart
* forwarding component that will launch UI for changing the configuration. An empty string
@@ -5496,6 +5503,7 @@
1 /* Roaming Indicator Off */
});
sDefaults.putStringArray(KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY, new String[0]);
+ sDefaults.putBoolean(KEY_CARRIER_SUPPORTS_CALLER_ID_VERTICAL_SERVICE_CODES_BOOL, false);
sDefaults.putBoolean(KEY_USE_USIM_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL, false);
sDefaults.putBoolean(KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION, true);
diff --git a/telephony/java/android/telephony/ims/DelegateStateCallback.java b/telephony/java/android/telephony/ims/DelegateStateCallback.java
index 2b4fb7d..734b520 100644
--- a/telephony/java/android/telephony/ims/DelegateStateCallback.java
+++ b/telephony/java/android/telephony/ims/DelegateStateCallback.java
@@ -79,7 +79,7 @@
* messages routing should be delayed until the {@link SipDelegate} sends the IMS configuration
* change event to reduce conditions where the remote application is using a stale IMS
* configuration.
- * @deprecated This is being removed from API surface, Use
+ * @removed This is being removed from API surface, Use
* {@link #onConfigurationChanged(SipDelegateConfiguration)} instead.
*/
@Deprecated
diff --git a/telephony/java/android/telephony/ims/SipDelegateConnection.java b/telephony/java/android/telephony/ims/SipDelegateConnection.java
index 4dbb08d..498b408 100644
--- a/telephony/java/android/telephony/ims/SipDelegateConnection.java
+++ b/telephony/java/android/telephony/ims/SipDelegateConnection.java
@@ -62,26 +62,6 @@
void notifyMessageReceived(@NonNull String viaTransactionId);
/**
- * The SIP Dialog associated with the provided Call-ID is being closed and routing resources
- * associated with the SIP dialog are free to be released.
- * <p>
- * Calling this method is also mandatory for situations where the framework IMS stack is waiting
- * for pending SIP dialogs to be closed before it can perform a handover or apply a provisioning
- * change. See {@link DelegateRegistrationState} for more information about
- * the scenarios where this can occur.
- * <p>
- * This method will need to be called for each SIP dialog managed by this application when it is
- * closed.
- * @param callId The call-ID header value associated with the ongoing SIP Dialog that is
- * closing.
- * @deprecated closeDialog does not capture INVITE forking. Use {@link #cleanupSession} instead.
- */
- @Deprecated
- default void closeDialog(@NonNull String callId) {
- cleanupSession(callId);
- }
-
- /**
* The SIP session associated with the provided Call-ID is being closed and routing resources
* associated with the session are free to be released. Each SIP session may contain multiple
* dialogs due to SIP INVITE forking, so this method must be called after all SIP dialogs
@@ -97,7 +77,7 @@
* @param callId The call-ID header value associated with the ongoing SIP Dialog that is
* closing.
*/
- default void cleanupSession(@NonNull String callId) { }
+ void cleanupSession(@NonNull String callId);
/**
* Notify the SIP delegate that the SIP message has been received from
diff --git a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
index 08513c2..fe14dd1 100644
--- a/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
+++ b/telephony/java/android/telephony/ims/SipDelegateImsConfiguration.java
@@ -34,7 +34,7 @@
/**
* @hide
- * @deprecated Use {@link SipDelegateConfiguration} instead.
+ * @removed Use {@link SipDelegateConfiguration} instead.
*/
@Deprecated
@SystemApi
diff --git a/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java b/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java
index c078637..42c53f2 100644
--- a/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java
+++ b/telephony/java/android/telephony/ims/stub/DelegateConnectionStateCallback.java
@@ -136,7 +136,7 @@
* not compleed yet.
*
* @param registeredSipConfig The configuration of the IMS stack registered on the IMS network.
- * @deprecated Will not be in final API, use
+ * @removed Will not be in final API, use
* {@link #onConfigurationChanged(SipDelegateConfiguration)} instead}.
*/
@Deprecated
@@ -161,7 +161,7 @@
*
* @param registeredSipConfig The configuration of the IMS stack registered on the IMS network.
*/
- default void onConfigurationChanged(@NonNull SipDelegateConfiguration registeredSipConfig) {}
+ void onConfigurationChanged(@NonNull SipDelegateConfiguration registeredSipConfig);
/**
* The previously created {@link SipDelegateConnection} instance delivered via
diff --git a/telephony/java/android/telephony/ims/stub/SipDelegate.java b/telephony/java/android/telephony/ims/stub/SipDelegate.java
index 997d00b..7dbefb4 100644
--- a/telephony/java/android/telephony/ims/stub/SipDelegate.java
+++ b/telephony/java/android/telephony/ims/stub/SipDelegate.java
@@ -64,25 +64,6 @@
void sendMessage(@NonNull SipMessage message, long configVersion);
/**
- * The framework is requesting that routing resources associated with the SIP dialog using the
- * provided Call-ID to be cleaned up.
- * <p>
- * Typically, a SIP Dialog close event will be signalled by that dialog receiving a BYE or
- * 200 OK message, however, the IMS application will still call
- * {@link SipDelegateConnection#closeDialog(String)} to signal to the framework that resources
- * can be released. In some cases, the framework will request that the ImsService close the
- * dialog due to the open dialog holding up an event such as applying a provisioning change or
- * handing over to another transport type. See {@link DelegateRegistrationState}.
- *
- * @param callId The call-ID header value associated with the ongoing SIP Dialog that the
- * framework is requesting be closed.
- * @deprecated This method does not take into account INVITE forking. Use
- * {@link #cleanupSession(String)} instead.
- */
- @Deprecated
- default void closeDialog(@NonNull String callId) { }
-
- /**
* The remote IMS application has closed a SIP session and the routing resources associated
* with the SIP session using the provided Call-ID may now be cleaned up.
* <p>
@@ -97,9 +78,7 @@
* @param callId The call-ID header value associated with the ongoing SIP Session that the
* framework is requesting be cleaned up.
*/
- default void cleanupSession(@NonNull String callId) {
- closeDialog(callId);
- }
+ void cleanupSession(@NonNull String callId);
/**
* The remote application has received the SIP message and is processing it.
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 91ecbf0..a096c1f 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2440,6 +2440,12 @@
boolean removeUceRequestDisallowedStatus(int subId);
/**
+ * Set the timeout for contact capabilities request.
+ * Note: This is designed for a SHELL command only.
+ */
+ boolean setCapabilitiesRequestTimeout(int subId, long timeoutAfterMs);
+
+ /**
* Set a SignalStrengthUpdateRequest to receive notification when Signal Strength breach the
* specified thresholds.
*/
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index db91eb2..0e2f5a4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -21,6 +21,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import org.junit.FixMethodOrder
import org.junit.Test
@@ -36,6 +37,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) {
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index 4f4f06d..95e55a1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -21,6 +21,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import org.junit.FixMethodOrder
import org.junit.Test
@@ -36,6 +37,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) {
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 0bae8f6..b5757fd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -26,6 +26,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
@@ -51,6 +52,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class CloseImeAutoOpenWindowToAppTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index 819d4dd..f7d3f94 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -28,6 +28,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
@@ -53,6 +54,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class CloseImeAutoOpenWindowToHomeTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 7bc004f..8cb3e4a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -25,6 +25,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.ImeAppHelper
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
@@ -51,6 +52,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 185400889)
+@Group2
class CloseImeWindowToAppTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = ImeAppHelper(instrumentation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 5f841b8..08ee6be 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -28,6 +28,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.ImeAppHelper
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
@@ -51,6 +52,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class CloseImeWindowToHomeTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = ImeAppHelper(instrumentation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 85163b3..07d8861 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -27,6 +27,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.helpers.ImeAppHelper
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
@@ -52,6 +53,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class OpenImeWindowTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = ImeAppHelper(instrumentation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index a0b0b75..432205c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -28,6 +28,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.helpers.setRotation
@@ -58,6 +59,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.config.startRotation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
index 754d9e9..52850d2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
@@ -28,6 +28,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group2
import com.android.server.wm.flicker.helpers.ImeAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
@@ -52,6 +53,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group2
class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = SimpleAppHelper(instrumentation)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 5703e6c..013e844 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -21,6 +21,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.dsl.FlickerBuilder
@@ -40,6 +41,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 185400889)
+@Group1
class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index e0179c1..67d5418 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -22,6 +22,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.startRotation
@@ -41,6 +42,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 741aad7..c6dea00 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -22,6 +22,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.dsl.FlickerBuilder
@@ -39,6 +40,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
class OpenAppWarmTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 9a9d6ff..1dbb617 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -23,6 +23,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import org.junit.FixMethodOrder
@@ -39,6 +40,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
class ChangeAppRotationTest(
testSpec: FlickerTestParameter
) : RotationTransition(testSpec) {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index 4770c3d..4627107 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -22,6 +22,7 @@
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
@@ -39,6 +40,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
class SeamlessAppRotationTest(
testSpec: FlickerTestParameter
) : RotationTransition(testSpec) {
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 39f7386..9c93f81 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -200,6 +200,9 @@
public void testMigration() throws Exception {
triggerChildOpened();
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
getChildSessionCallback()
.onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform());
mTestLooper.dispatchAll();
@@ -207,7 +210,7 @@
verify(mIpSecSvc, times(2))
.setNetworkForTunnelInterface(
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID),
- eq(TEST_UNDERLYING_NETWORK_RECORD_1.network),
+ eq(TEST_UNDERLYING_NETWORK_RECORD_2.network),
any());
for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) {
@@ -226,8 +229,10 @@
MtuUtils.getMtu(
saProposals,
mConfig.getMaxMtu(),
- TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.getMtu());
- verify(mNetworkAgent).sendLinkProperties(argThat(lp -> expectedMtu == lp.getMtu()));
+ TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.getMtu());
+ verify(mNetworkAgent).sendLinkProperties(
+ argThat(lp -> expectedMtu == lp.getMtu()
+ && TEST_TCP_BUFFER_SIZES_2.equals(lp.getTcpBufferSizes())));
}
private void triggerChildOpened() {
@@ -297,6 +302,7 @@
final LinkProperties lp = lpCaptor.getValue();
assertEquals(Collections.singletonList(TEST_INTERNAL_ADDR), lp.getLinkAddresses());
assertEquals(Collections.singletonList(TEST_DNS_ADDR), lp.getDnsServers());
+ assertEquals(TEST_TCP_BUFFER_SIZES_1, lp.getTcpBufferSizes());
final NetworkCapabilities nc = ncCaptor.getValue();
assertTrue(nc.hasTransport(TRANSPORT_CELLULAR));
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
index 9705f0f..a4f95e0 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -74,6 +74,9 @@
private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class);
private static final Map<Integer, ParcelUuid> TEST_SUBID_TO_GROUP_MAP;
+ private static final int TEST_UPSTREAM_BANDWIDTH = 1234;
+ private static final int TEST_DOWNSTREAM_BANDWIDTH = 2345;
+
static {
final Map<Integer, ParcelUuid> subIdToGroupMap = new HashMap<>();
subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID);
@@ -106,6 +109,8 @@
capBuilder.setNetworkSpecifier(
new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_1));
}
+ capBuilder.setLinkUpstreamBandwidthKbps(TEST_UPSTREAM_BANDWIDTH);
+ capBuilder.setLinkDownstreamBandwidthKbps(TEST_DOWNSTREAM_BANDWIDTH);
capBuilder.setAdministratorUids(new int[] {TEST_UID});
UnderlyingNetworkRecord record = new UnderlyingNetworkRecord(
mock(Network.class, CALLS_REAL_METHODS),
@@ -130,6 +135,8 @@
assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids());
assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo);
+ assertEquals(TEST_UPSTREAM_BANDWIDTH, vcnCaps.getLinkUpstreamBandwidthKbps());
+ assertEquals(TEST_DOWNSTREAM_BANDWIDTH, vcnCaps.getLinkDownstreamBandwidthKbps());
final VcnTransportInfo info = (VcnTransportInfo) vcnCaps.getTransportInfo();
if (transportType == TRANSPORT_WIFI) {
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index c747bc0..0a4fcbc 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -99,6 +99,7 @@
protected static final long ELAPSED_REAL_TIME = 123456789L;
protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
+ protected static final String TEST_TCP_BUFFER_SIZES_1 = "1,2,3,4";
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
new UnderlyingNetworkRecord(
mock(Network.class, CALLS_REAL_METHODS),
@@ -108,8 +109,10 @@
static {
TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setMtu(1500);
+ TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES_1);
}
+ protected static final String TEST_TCP_BUFFER_SIZES_2 = "2,3,4,5";
protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 =
new UnderlyingNetworkRecord(
mock(Network.class, CALLS_REAL_METHODS),
@@ -119,6 +122,7 @@
static {
TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setMtu(1460);
+ TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES_2);
}
protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT =
diff --git a/tools/aapt2/OWNERS b/tools/aapt2/OWNERS
index f1903a5..69dfcc9 100644
--- a/tools/aapt2/OWNERS
+++ b/tools/aapt2/OWNERS
@@ -1,3 +1,4 @@
set noparent
toddke@google.com
-rtmitchell@google.com
\ No newline at end of file
+rtmitchell@google.com
+patb@google.com
\ No newline at end of file
diff --git a/tools/aosp/aosp_sha.sh b/tools/aosp/aosp_sha.sh
index 99aaa3c..81d35ef 100755
--- a/tools/aosp/aosp_sha.sh
+++ b/tools/aosp/aosp_sha.sh
@@ -4,6 +4,9 @@
if git branch -vv | grep -q -P "^\*[^\[]+\[aosp/"; then
# Change appears to be in AOSP
exit 0
+elif git log -n 1 --format='%B' $1 | grep -q -E "^Ignore-AOSP-First: .+" ; then
+ # Change is explicitly marked as ok to skip AOSP
+ exit 0
else
# Change appears to be non-AOSP; search for files
count=0
diff --git a/tools/apilint/deprecated_at_birth.py b/tools/apilint/deprecated_at_birth.py
new file mode 100644
index 0000000..297d9c3b
--- /dev/null
+++ b/tools/apilint/deprecated_at_birth.py
@@ -0,0 +1,313 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Usage: deprecated_at_birth.py path/to/next/ path/to/previous/
+Usage: deprecated_at_birth.py prebuilts/sdk/31/public/api/ prebuilts/sdk/30/public/api/
+"""
+
+import re, sys, os, collections, traceback, argparse
+
+
+BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
+
+def format(fg=None, bg=None, bright=False, bold=False, dim=False, reset=False):
+ # manually derived from http://en.wikipedia.org/wiki/ANSI_escape_code#Codes
+ codes = []
+ if reset: codes.append("0")
+ else:
+ if not fg is None: codes.append("3%d" % (fg))
+ if not bg is None:
+ if not bright: codes.append("4%d" % (bg))
+ else: codes.append("10%d" % (bg))
+ if bold: codes.append("1")
+ elif dim: codes.append("2")
+ else: codes.append("22")
+ return "\033[%sm" % (";".join(codes))
+
+
+def ident(raw):
+ """Strips superficial signature changes, giving us a strong key that
+ can be used to identify members across API levels."""
+ raw = raw.replace(" deprecated ", " ")
+ raw = raw.replace(" synchronized ", " ")
+ raw = raw.replace(" final ", " ")
+ raw = re.sub("<.+?>", "", raw)
+ raw = re.sub("@[A-Za-z]+ ", "", raw)
+ raw = re.sub("@[A-Za-z]+\(.+?\) ", "", raw)
+ if " throws " in raw:
+ raw = raw[:raw.index(" throws ")]
+ return raw
+
+
+class Field():
+ def __init__(self, clazz, line, raw, blame):
+ self.clazz = clazz
+ self.line = line
+ self.raw = raw.strip(" {;")
+ self.blame = blame
+
+ raw = raw.split()
+ self.split = list(raw)
+
+ raw = [ r for r in raw if not r.startswith("@") ]
+ for r in ["method", "field", "public", "protected", "static", "final", "abstract", "default", "volatile", "transient"]:
+ while r in raw: raw.remove(r)
+
+ self.typ = raw[0]
+ self.name = raw[1].strip(";")
+ if len(raw) >= 4 and raw[2] == "=":
+ self.value = raw[3].strip(';"')
+ else:
+ self.value = None
+ self.ident = ident(self.raw)
+
+ def __hash__(self):
+ return hash(self.raw)
+
+ def __repr__(self):
+ return self.raw
+
+
+class Method():
+ def __init__(self, clazz, line, raw, blame):
+ self.clazz = clazz
+ self.line = line
+ self.raw = raw.strip(" {;")
+ self.blame = blame
+
+ # drop generics for now
+ raw = re.sub("<.+?>", "", raw)
+
+ raw = re.split("[\s(),;]+", raw)
+ for r in ["", ";"]:
+ while r in raw: raw.remove(r)
+ self.split = list(raw)
+
+ raw = [ r for r in raw if not r.startswith("@") ]
+ for r in ["method", "field", "public", "protected", "static", "final", "abstract", "default", "volatile", "transient"]:
+ while r in raw: raw.remove(r)
+
+ self.typ = raw[0]
+ self.name = raw[1]
+ self.args = []
+ self.throws = []
+ target = self.args
+ for r in raw[2:]:
+ if r == "throws": target = self.throws
+ else: target.append(r)
+ self.ident = ident(self.raw)
+
+ def __hash__(self):
+ return hash(self.raw)
+
+ def __repr__(self):
+ return self.raw
+
+
+class Class():
+ def __init__(self, pkg, line, raw, blame):
+ self.pkg = pkg
+ self.line = line
+ self.raw = raw.strip(" {;")
+ self.blame = blame
+ self.ctors = []
+ self.fields = []
+ self.methods = []
+
+ raw = raw.split()
+ self.split = list(raw)
+ if "class" in raw:
+ self.fullname = raw[raw.index("class")+1]
+ elif "enum" in raw:
+ self.fullname = raw[raw.index("enum")+1]
+ elif "interface" in raw:
+ self.fullname = raw[raw.index("interface")+1]
+ elif "@interface" in raw:
+ self.fullname = raw[raw.index("@interface")+1]
+ else:
+ raise ValueError("Funky class type %s" % (self.raw))
+
+ if "extends" in raw:
+ self.extends = raw[raw.index("extends")+1]
+ self.extends_path = self.extends.split(".")
+ else:
+ self.extends = None
+ self.extends_path = []
+
+ self.fullname = self.pkg.name + "." + self.fullname
+ self.fullname_path = self.fullname.split(".")
+
+ self.name = self.fullname[self.fullname.rindex(".")+1:]
+
+ def __hash__(self):
+ return hash((self.raw, tuple(self.ctors), tuple(self.fields), tuple(self.methods)))
+
+ def __repr__(self):
+ return self.raw
+
+
+class Package():
+ def __init__(self, line, raw, blame):
+ self.line = line
+ self.raw = raw.strip(" {;")
+ self.blame = blame
+
+ raw = raw.split()
+ self.name = raw[raw.index("package")+1]
+ self.name_path = self.name.split(".")
+
+ def __repr__(self):
+ return self.raw
+
+
+def _parse_stream(f, api={}):
+ line = 0
+ pkg = None
+ clazz = None
+ blame = None
+
+ re_blame = re.compile("^([a-z0-9]{7,}) \(<([^>]+)>.+?\) (.+?)$")
+ for raw in f:
+ line += 1
+ raw = raw.rstrip()
+ match = re_blame.match(raw)
+ if match is not None:
+ blame = match.groups()[0:2]
+ raw = match.groups()[2]
+ else:
+ blame = None
+
+ if raw.startswith("package"):
+ pkg = Package(line, raw, blame)
+ elif raw.startswith(" ") and raw.endswith("{"):
+ clazz = Class(pkg, line, raw, blame)
+ api[clazz.fullname] = clazz
+ elif raw.startswith(" ctor"):
+ clazz.ctors.append(Method(clazz, line, raw, blame))
+ elif raw.startswith(" method"):
+ clazz.methods.append(Method(clazz, line, raw, blame))
+ elif raw.startswith(" field"):
+ clazz.fields.append(Field(clazz, line, raw, blame))
+
+ return api
+
+
+def _parse_stream_path(path):
+ api = {}
+ print "Parsing", path
+ for f in os.listdir(path):
+ f = os.path.join(path, f)
+ if not os.path.isfile(f): continue
+ if not f.endswith(".txt"): continue
+ if f.endswith("removed.txt"): continue
+ print "\t", f
+ with open(f) as s:
+ api = _parse_stream(s, api)
+ print "Parsed", len(api), "APIs"
+ print
+ return api
+
+
+class Failure():
+ def __init__(self, sig, clazz, detail, error, rule, msg):
+ self.sig = sig
+ self.error = error
+ self.rule = rule
+ self.msg = msg
+
+ if error:
+ self.head = "Error %s" % (rule) if rule else "Error"
+ dump = "%s%s:%s %s" % (format(fg=RED, bg=BLACK, bold=True), self.head, format(reset=True), msg)
+ else:
+ self.head = "Warning %s" % (rule) if rule else "Warning"
+ dump = "%s%s:%s %s" % (format(fg=YELLOW, bg=BLACK, bold=True), self.head, format(reset=True), msg)
+
+ self.line = clazz.line
+ blame = clazz.blame
+ if detail is not None:
+ dump += "\n in " + repr(detail)
+ self.line = detail.line
+ blame = detail.blame
+ dump += "\n in " + repr(clazz)
+ dump += "\n in " + repr(clazz.pkg)
+ dump += "\n at line " + repr(self.line)
+ if blame is not None:
+ dump += "\n last modified by %s in %s" % (blame[1], blame[0])
+
+ self.dump = dump
+
+ def __repr__(self):
+ return self.dump
+
+
+failures = {}
+
+def _fail(clazz, detail, error, rule, msg):
+ """Records an API failure to be processed later."""
+ global failures
+
+ sig = "%s-%s-%s" % (clazz.fullname, repr(detail), msg)
+ sig = sig.replace(" deprecated ", " ")
+
+ failures[sig] = Failure(sig, clazz, detail, error, rule, msg)
+
+
+def warn(clazz, detail, rule, msg):
+ _fail(clazz, detail, False, rule, msg)
+
+def error(clazz, detail, rule, msg):
+ _fail(clazz, detail, True, rule, msg)
+
+
+if __name__ == "__main__":
+ next_path = sys.argv[1]
+ prev_path = sys.argv[2]
+
+ next_api = _parse_stream_path(next_path)
+ prev_api = _parse_stream_path(prev_path)
+
+ # Remove all existing things so we're left with new
+ for prev_clazz in prev_api.values():
+ if prev_clazz.fullname not in next_api: continue
+ cur_clazz = next_api[prev_clazz.fullname]
+
+ sigs = { i.ident: i for i in prev_clazz.ctors }
+ cur_clazz.ctors = [ i for i in cur_clazz.ctors if i.ident not in sigs ]
+ sigs = { i.ident: i for i in prev_clazz.methods }
+ cur_clazz.methods = [ i for i in cur_clazz.methods if i.ident not in sigs ]
+ sigs = { i.ident: i for i in prev_clazz.fields }
+ cur_clazz.fields = [ i for i in cur_clazz.fields if i.ident not in sigs ]
+
+ # Forget about class entirely when nothing new
+ if len(cur_clazz.ctors) == 0 and len(cur_clazz.methods) == 0 and len(cur_clazz.fields) == 0:
+ del next_api[prev_clazz.fullname]
+
+ for clazz in next_api.values():
+ if "@Deprecated " in clazz.raw and not clazz.fullname in prev_api:
+ error(clazz, None, None, "Found API deprecation at birth")
+
+ if "@Deprecated " in clazz.raw: continue
+
+ for i in clazz.ctors + clazz.methods + clazz.fields:
+ if "@Deprecated " in i.raw:
+ error(clazz, i, None, "Found API deprecation at birth " + i.ident)
+
+ print "%s Deprecated at birth %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True),
+ format(reset=True)))
+ for f in sorted(failures):
+ print failures[f]
+ print
diff --git a/wifi/OWNERS b/wifi/OWNERS
index 2caf9ed..8381522 100644
--- a/wifi/OWNERS
+++ b/wifi/OWNERS
@@ -1,5 +1,3 @@
set noparent
-dysu@google.com
-etancohen@google.com
-satk@google.com
+include platform/packages/modules/Wifi:/WIFI_OWNERS