Merge "Intercept quiet profile prior to suspended package"
diff --git a/Android.bp b/Android.bp
index 8926372..c1f6860 100644
--- a/Android.bp
+++ b/Android.bp
@@ -266,11 +266,19 @@
}
filegroup {
+ name: "framework-updatable-sources",
+ srcs: [
+ ":framework-sdkext-sources",
+ ":updatable-media-srcs",
+ ]
+}
+
+filegroup {
name: "framework-all-sources",
srcs: [
":framework-mime-sources",
":framework-non-updatable-sources",
- ":updatable-media-srcs",
+ ":framework-updatable-sources",
],
}
@@ -576,6 +584,12 @@
],
}
+java_library {
+ name: "framework-annotations-lib",
+ srcs: [ ":framework-annotations" ],
+ sdk_version: "current",
+}
+
filegroup {
name: "framework-networkstack-shared-srcs",
srcs: [
@@ -1019,15 +1033,15 @@
stubs_defaults {
name: "framework-doc-stubs-default",
srcs: [
- ":framework-non-updatable-sources",
":framework-mime-sources",
+ ":framework-non-updatable-sources",
+ ":framework-updatable-sources",
"core/java/**/*.logtags",
"test-base/src/**/*.java",
":opt-telephony-srcs",
":opt-net-voip-srcs",
":core-current-stubs-source",
":core_public_api_files",
- ":updatable-media-srcs",
"test-mock/src/**/*.java",
"test-runner/src/**/*.java",
],
@@ -1085,12 +1099,12 @@
name: "metalava-api-stubs-default",
srcs: [
":framework-non-updatable-sources",
+ ":framework-updatable-sources",
"core/java/**/*.logtags",
":opt-telephony-srcs",
":opt-net-voip-srcs",
":core-current-stubs-source",
":core_public_api_files",
- ":updatable-media-srcs",
":ike-api-srcs",
],
libs: ["framework-internal-utils"],
diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp
index 2cd7aa0..4ebafce8 100644
--- a/apex/appsearch/service/Android.bp
+++ b/apex/appsearch/service/Android.bp
@@ -21,4 +21,7 @@
"framework",
"services.core",
],
+ static_libs: [
+ "icing-java-proto-lite",
+ ]
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
index e611033..5ac922c 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
@@ -20,9 +20,11 @@
import android.annotation.Nullable;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.Pair;
import android.util.SparseArray;
+import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.PropertyProto;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -42,18 +44,19 @@
public class FakeIcing {
private final AtomicInteger mNextDocId = new AtomicInteger();
private final Map<String, Integer> mUriToDocIdMap = new ArrayMap<>();
- /** Array of Documents (pair of uri and content) where index into the array is the docId. */
- private final SparseArray<Pair<String, String>> mDocStore = new SparseArray<>();
+ /** Array of Documents where index into the array is the docId. */
+ private final SparseArray<DocumentProto> mDocStore = new SparseArray<>();
/** Map of term to posting-list (the set of DocIds containing that term). */
private final Map<String, Set<Integer>> mIndex = new ArrayMap<>();
/**
* Inserts a document into the index.
*
- * @param uri The globally unique identifier of the document.
- * @param doc The contents of the document.
+ * @param document The document to insert.
*/
- public void put(@NonNull String uri, @NonNull String doc) {
+ public void put(@NonNull DocumentProto document) {
+ String uri = document.getUri();
+
// Update mDocIdMap
Integer docId = mUriToDocIdMap.get(uri);
if (docId != null) {
@@ -66,18 +69,10 @@
mUriToDocIdMap.put(uri, docId);
// Update mDocStore
- mDocStore.put(docId, Pair.create(uri, doc));
+ mDocStore.put(docId, document);
// Update mIndex
- String[] words = normalizeString(doc).split("\\s+");
- for (String word : words) {
- Set<Integer> postingList = mIndex.get(word);
- if (postingList == null) {
- postingList = new ArraySet<>();
- mIndex.put(word, postingList);
- }
- postingList.add(docId);
- }
+ indexDocument(docId, document);
}
/**
@@ -87,39 +82,35 @@
* @return The body of the document, or {@code null} if no such document exists.
*/
@Nullable
- public String get(@NonNull String uri) {
+ public DocumentProto get(@NonNull String uri) {
Integer docId = mUriToDocIdMap.get(uri);
if (docId == null) {
return null;
}
- Pair<String, String> record = mDocStore.get(docId);
- if (record == null) {
- return null;
- }
- return record.second;
+ return mDocStore.get(docId);
}
/**
* Returns documents containing the given term.
*
* @param term A single exact term to look up in the index.
- * @return The URIs of the matching documents, or an empty {@code List} if no documents match.
+ * @return The matching documents, or an empty {@code List} if no documents match.
*/
@NonNull
- public List<String> query(@NonNull String term) {
+ public List<DocumentProto> query(@NonNull String term) {
String normTerm = normalizeString(term);
Set<Integer> docIds = mIndex.get(normTerm);
if (docIds == null || docIds.isEmpty()) {
return Collections.emptyList();
}
- List<String> uris = new ArrayList<>(docIds.size());
+ List<DocumentProto> matches = new ArrayList<>(docIds.size());
for (int docId : docIds) {
- Pair<String, String> record = mDocStore.get(docId);
- if (record != null) {
- uris.add(record.first);
+ DocumentProto document = mDocStore.get(docId);
+ if (document != null) {
+ matches.add(document);
}
}
- return uris;
+ return matches;
}
/**
@@ -137,6 +128,39 @@
}
}
+ private void indexDocument(int docId, DocumentProto document) {
+ for (PropertyProto property : document.getPropertiesList()) {
+ for (String stringValue : property.getStringValuesList()) {
+ String[] words = normalizeString(stringValue).split("\\s+");
+ for (String word : words) {
+ indexTerm(docId, word);
+ }
+ }
+ for (Long longValue : property.getInt64ValuesList()) {
+ indexTerm(docId, longValue.toString());
+ }
+ for (Double doubleValue : property.getDoubleValuesList()) {
+ indexTerm(docId, doubleValue.toString());
+ }
+ for (Boolean booleanValue : property.getBooleanValuesList()) {
+ indexTerm(docId, booleanValue.toString());
+ }
+ // Intentionally skipping bytes values
+ for (DocumentProto documentValue : property.getDocumentValuesList()) {
+ indexDocument(docId, documentValue);
+ }
+ }
+ }
+
+ private void indexTerm(int docId, String term) {
+ Set<Integer> postingList = mIndex.get(term);
+ if (postingList == null) {
+ postingList = new ArraySet<>();
+ mIndex.put(term, postingList);
+ }
+ postingList.add(docId);
+ }
+
/** Strips out punctuation and converts to lowercase. */
private static String normalizeString(String input) {
return input.replaceAll("\\p{P}", "").toLowerCase(Locale.getDefault());
diff --git a/apex/sdkext/Android.bp b/apex/sdkext/Android.bp
new file mode 100644
index 0000000..b8dcb90
--- /dev/null
+++ b/apex/sdkext/Android.bp
@@ -0,0 +1,32 @@
+// 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.
+
+apex {
+ name: "com.android.sdkext",
+ manifest: "manifest.json",
+ java_libs: [ "framework-sdkext" ],
+ key: "com.android.sdkext.key",
+ certificate: ":com.android.sdkext.certificate",
+}
+
+apex_key {
+ name: "com.android.sdkext.key",
+ public_key: "com.android.sdkext.avbpubkey",
+ private_key: "com.android.sdkext.pem",
+}
+
+android_app_certificate {
+ name: "com.android.sdkext.certificate",
+ certificate: "com.android.sdkext",
+}
diff --git a/apex/sdkext/OWNERS b/apex/sdkext/OWNERS
new file mode 100644
index 0000000..feb2742
--- /dev/null
+++ b/apex/sdkext/OWNERS
@@ -0,0 +1 @@
+hansson@google.com
diff --git a/apex/sdkext/com.android.sdkext.avbpubkey b/apex/sdkext/com.android.sdkext.avbpubkey
new file mode 100644
index 0000000..8f47741
--- /dev/null
+++ b/apex/sdkext/com.android.sdkext.avbpubkey
Binary files differ
diff --git a/apex/sdkext/com.android.sdkext.pem b/apex/sdkext/com.android.sdkext.pem
new file mode 100644
index 0000000..8164601
--- /dev/null
+++ b/apex/sdkext/com.android.sdkext.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAr72pTSavrziDP54AtQZlRclDxJf9HXRZwFRbYx9hWZ4z7ZtO
+pNBDPvPJCiAOVUsILgCQhBUolz2dyLob25Fd0PVp0n9ibIPEQYjTfHjOK40qb57N
+LhEp2ceGiAfsywPSi0TH1PQ6JgbCe/RM4TefI/sj3gYJPka3ksMvylhMIgUVLgME
+kYizhzwHqlLMspB858SioREZdGwcdZrMMIajGFU69Q9ZRDBzhPvxyKhYoObcOtk1
+uVaiE/fNoi3wKGJz2l2vhUuNrQW7MWlVMag+Qes4YACUTk9LZrOVFEJFjWc8xGUi
+ABtfKGs5JgNr/sWnhvifLn8lJuf0/BJmjD+L5QwXYs2cS7gcZJtTM12J94r0Twgw
+wF2lNmIxAE9sYqj5Rh3dIlTPE5vMUECmQEGjIBB/hzT65VxVqSjU/IlS506JTg3p
+IOQtZ15cUzTBpda4jrvqcq6RNVvgBCu2bV5D8Z4z9FUlPyvD+Zq/6lcoJfLtznAs
+G2463hyPAHTGBIcZ5p5bTuGxoAb6ivyqo4b9Qi4yYA6je9HJmuy8T3Mn5JROoeu9
+BH1K54r/mpT4TQPwuKUvRRtBAV2OPHjo+zp0Gd4Y6rxDYxEIdfEae7pQr/QExSPB
+q/QCr9RhixR1mO373LHuja+MxdAxIxugb2HTS61PQo+PbYrhJMcVuxTwJOECAwEA
+AQKCAgAH7ToRrMkH0ji5SdsmTx+KQkW4PFLCXVke/68PjX7KmAQnl3W4oVwnHr/W
+oROEbVn1GTlre7jU+YaAY0SWZrwgjLE1OWGrG1ZizlUbrCdAd6GOX09J4KROml1L
+DXB0x7tbZMLOrCVjSbLD/ITrM6MN8Gnxvbv0/yOQjxU8vzbP4gLOjHxMRCo001RV
+Ll7lPvcjTQ84zJilU6sE8vJ6zdfVZSK/ou2X0cekG+kP7+fvefo8/UcbEPlGhUrV
+IdVPPQGUu90K2hmN0FBdLi8Vik0klAN68Qu/bHwuKbNzsnmIoztucFFUR+fG3u84
+87aPS0L/J3+mjT2Tv6qhJANUGBmrK/h7MkelpKXlRTCITJLX9xP7hfSbJ4f6aLVq
+ZYPPciGxSBbUDgAwvPtOlMDzccg7YsYyiBBO28wh8MN97rePmc0z6nGmjeXhcbCC
+QktG50VYFCyqp5muKgqQmRfRjHFHLWs8GEqgxMeEL3U3HjYfCYr+6E8Sr5OnOBeH
+3buCi1+zgnNYCvbamgY/OJmW7f9h5O31hxmTplc2E1ZuxUGQZthabt1rN3bmNkyf
+KUmPwnIYkDkWBSV5lzyQExfS3/EVvj0EnHhx8faamimNrGo8xCcfnLT3c0WEFVmo
+yIyVRX3EpXJFM2JkeJ21/IEZXTzHSoNxk12CBG8i8lLSflWSMQKCAQEA2ZqVnOuV
+SZfLCUYUUh8Hvhc5zONstfq7ma1Zsttsdaj9t68nLRiBDvLOGnMjDkYZzoSd4fyl
+oy+YqWGBqcqa5kg1NOCH0I46p9d8RcWAfDnB4sqbLgWh70qsvni6igRijmsMDvkA
+U9HeEdPaLCjQ4UXw7GQvN5rRxuRt+OSqV3tV/Pk9JYyYjz7faC8dmbKDrWHHuOvm
+/9y6Xy+L5IgftykNlUeddSCIoMOAadM7BiRjsrHnOYBQ8xBcn0OYafpIswItrgVi
+IrsPJaBFidx8QYK4MVibyka6U0cm28OocDSPtSk/4jrnCEEhLjFUnWwuMXuBGlrd
+W7wP/muoJqb1VwKCAQEAzsAT90kkOCvAcrfGRE3KkUjwWAsQyP8u2+27JIQPqrpW
+GfWAzJXFt80TSp0Zf/Lrq3/SQ9n4AaL4K9dcMoreedoQN9C9JI7zPtZAWNrJVUcV
+dq2gZjBQ78+oK7uQgvFNWxga5D+Nh+Y+9Tp537fc5HIh0Y13PgsxxPk2OnZJTvLX
+HM5H7Aua9ssmqChsrKihuUsDSPozfBz+H7FNHEdKMqVLqJJSK6m0uMxuLovdVfka
+5S7iBMjEGZc46Iz3ckE0pdOiQLooNqfEQqFe5Uou/KZxxKI1NW25rEEBTVyQWt+2
+BNUCfKP7noZ45u5sUY3eJrgI7BrPEDbNS81WYaLchwKCAQA8Q4mHyd6wYO+EA/qA
+u8NDK9+AFMP4qhXme5HJ7Obetwx9IG7zGEQ1xZy6yoQ84cEn5qZq/bNJvFbFIhHs
+2gWIHRtPJ5e1dI5eCVmLYSUyQjSmAIJ1fm3YfY/VuE3BB3HcC11tkBw9GnQr78YO
+UMd4fAw7C4vgFGpgcMbcFUfvrmKkCsqaaZOeqETq75F9DWlWTSwo1HxHA/RBhENz
+6RcPfLkcTJcY5wevrjUUGcHQ86cAyDBHRngkuLVODkRZpU0Y9lN8TFVfVPre6sIX
+ag6nffJRCD8tB+V2RtBGMKunV4ctHt1oY/Oz34W260aJynoIjjG1ANEpJK4xQdNx
+0O9FAoIBAQCz2AGGKemHswdEwveEkuaSWpA3Bekj7lYkmTchHH9EU7JyAkx3qhDD
+QXB2hxGXawf1tsqAmypQwiJ+gGeCz6mW9UkGRF1DX9XX4yc2I5rew2a4RXAxc/Xz
+pP70i8O5I43Wn7FEusOyY2aAis1Y/eb4EQ+56QTAw5wXa3DwidRbCIJ2XDnT6oRy
+CWUnAYMG7ek/9TB2Wq5OWCn2B5S79IdmZsLZb+5qbMT3u1xcwO1Xy8jJc27IGpv6
+ZsDqCTV1/aJ+XQnWpBg28tiV3Sle6pjUzTRJh5AhWcEZRbKMSOiJI/CBY4k2Qq6t
+xuuEdgFjL7T+mTepqehUglcyiPuLEtAhAoIBAQDDQ5pTFOlunfYzm+CIvvImAgy7
+vrEabJYABATytAbXRMMbrKoEdU2ApEDyEW7PgysDnYLAZ+icObnJlBTYvNdlWFly
+XiviGVfpjFWDT9U/gUwFQu2lfEjoiivoGS92USHUy4UMVHiiznnm20VLLkgd3xna
+HUNSDdHIEgzOTmDsKJwMfA9zGckx23JJimPR5ekv6vr6QllYtECs4lTC1gVQAp2f
+5daxHRbkmO6gw1RgQADLkAnYz3aI1jNuHm5VyAZGt/d3JCtZ3Wwwejll8uJ4J09G
+oEtqyY9RVeHK50bLO4lyAXFiE+J6qqXjsGC20cpxeZYW5llMY/dhA6WV4YXV
+-----END RSA PRIVATE KEY-----
diff --git a/apex/sdkext/com.android.sdkext.pk8 b/apex/sdkext/com.android.sdkext.pk8
new file mode 100644
index 0000000..ccc0bf4
--- /dev/null
+++ b/apex/sdkext/com.android.sdkext.pk8
Binary files differ
diff --git a/apex/sdkext/com.android.sdkext.x509.pem b/apex/sdkext/com.android.sdkext.x509.pem
new file mode 100644
index 0000000..45d2ade
--- /dev/null
+++ b/apex/sdkext/com.android.sdkext.x509.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGIzCCBAugAwIBAgIUXuDL7QvzQh7S6rihWz2KRvCFVT0wDQYJKoZIhvcNAQEL
+BQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMRswGQYDVQQDDBJjb20uYW5kcm9pZC5zZGtleHQxIjAgBgkqhkiG9w0BCQEW
+E2FuZHJvaWRAYW5kcm9pZC5jb20wIBcNMTkxMjAyMTQyNDM0WhgPNDc1NzEwMjgx
+NDI0MzRaMIGfMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG
+A1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwH
+QW5kcm9pZDEbMBkGA1UEAwwSY29tLmFuZHJvaWQuc2RrZXh0MSIwIAYJKoZIhvcN
+AQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAxFvZZ6ES1oqAu1K74/ZxnC3SOhHnLISLBgJEe7DqtdpuNFAwvdVO
+RL/HULhDbjYlOhpU2x3SavDIZZ2lRfiS9Q+M25WftxTRHVjBcpgwbV77TVxPKlAa
+tVN2lUVOY+s4QAVMNIXjC4kCKK/pCQtacH715EtdV47fWdg/Nx4iP/Aord8k3KGI
+9iI2ZOUjaugTRxu5lKRNDrv0bw5rEzyYmDyMud+kR/iS3/5oog57wPE0ffAkZXWE
+p3L2Cejre3ekCizsvVh6EmH6ForKLtL6f0z5Zir1f4R9+YcENspTlJR3pDhg7y3I
+uTQT/iDCtV0l+g2PjGZPEeAQHND3+kDQR7Sno/WC1Nhws6vcu1MdrC+kIh1ewx4y
+8moy/yqb5M98PJDzTSi/AOTB/OiqLXo/T8rjLBmirs9y3fTT6gJ6qXxOWgt8dle9
+7TBfa84Xi8uVY61c+A+YI0nLal7QDPsP3RPv5sJSQ9x9YnweVfD9Q0EOi52sSNu+
+QuN/kcUrMgPgha20VhfH/CkkPDyIp6aZyHHM69MIl+cYEm8vPa5uy3dosuRomT0f
+I4HOBjULDIuj+rIi+Rg3qHvmpuejwZXI/FBNWIhLEUG3ytgksjMaBoYAYflGdrcj
+BQexuF3EO+j4uo7JGjNcaT7wRoCH9gt29VHckDg2qz6VWXrlpmME4UkCAwEAAaNT
+MFEwHQYDVR0OBBYEFISN2nmUHllgPZMZ62U7mU3ZxzlXMB8GA1UdIwQYMBaAFISN
+2nmUHllgPZMZ62U7mU3ZxzlXMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
+BQADggIBAFHIwyBNIVyHXUsDUdcjxfojXQsF/BCL9ehE3pgdkvDfQanaIREWn0nc
+oCFDFkYMRqaXOGC5TKq4OCjXOLsdfODt8HQ3F9J1B0ghQ5tfOdw7xDugNAszqP/Q
+h7kpvqLTycjrqOeZ5KjxEEYtP/KlUmALgOKcTcSH+XhWyxhjF4j24T9F2yJRr3/A
+r1NGU/djH953bHKC8OpJ2teUpDLA4TxVp/EhslH2eVigF80c/w74QPLEWkD9zv/4
+YeRg/R5N83zHs99NtlWMIeHfK6fUbzMyaSZtvm+jK20tkByQb/OQRed+drk25MtL
+68IRvxqri367qRScdpTZbu0ByLO4X8gFdubRUWr+tcO4pZX+DJRVriExbOkU2xhS
+Vtslq23V/hwTuUNm1CXjR70mPS13BTmHrIQDqLoIw/WTQlGh+vxnlAFRIHM3KB2c
+OdzUBu+NcB4aZEd0KKtct600A0DKPr1MQPb5jDq9wEtPSQYwMF0nRFNnXltbrXMd
+4hhwnhKr74fVMUmb+7eQP56XE/Nk4D+npMO54vv1pav+DI2/nxCND9BOLBweY38p
+Tvd2RjesMok0zXuVXiCIu4GEpwo7WkSnv25xrb0Ey2M8QWnGNnCcX7Kv6ip3RdWy
+HiN0G8RJrs/yNEVSDRx8ZhtwTpXVPQxbARbmhNF4/fnolElkmrMP
+-----END CERTIFICATE-----
diff --git a/apex/sdkext/framework/Android.bp b/apex/sdkext/framework/Android.bp
new file mode 100644
index 0000000..b17f0f8
--- /dev/null
+++ b/apex/sdkext/framework/Android.bp
@@ -0,0 +1,30 @@
+// 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.
+
+filegroup {
+ name: "framework-sdkext-sources",
+ srcs: [
+ "java/**/*.java",
+ ],
+ path: "java",
+}
+
+java_library {
+ name: "framework-sdkext",
+ srcs: [ ":framework-sdkext-sources" ],
+ sdk_version: "system_current",
+ libs: [ "framework-annotations-lib" ],
+ permitted_packages: [ "android.os.ext" ],
+ installable: true,
+}
diff --git a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java b/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
new file mode 100644
index 0000000..c039a82
--- /dev/null
+++ b/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
@@ -0,0 +1,53 @@
+/*
+ * 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.ext;
+
+import android.annotation.IntDef;
+import android.os.Build.VERSION_CODES;
+import android.os.SystemProperties;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** @hide */
+public class SdkExtensions {
+
+ private static final int R_EXTENSION_INT;
+ static {
+ R_EXTENSION_INT = SystemProperties.getInt("persist.com.android.sdkext.sdk_info", 0);
+ }
+
+ /** Values suitable as parameters for {@link #getExtensionVersion(int)}. */
+ @IntDef(value = { VERSION_CODES.R })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SdkVersion {}
+
+ /**
+ * Return the version of the extension to the given SDK.
+ *
+ * @param sdk the SDK version to get the extension version of.
+ * @see SdkVersion
+ * @throws IllegalArgumentException if sdk is not an sdk version with extensions
+ */
+ public static int getExtensionVersion(@SdkVersion int sdk) {
+ if (sdk < VERSION_CODES.R) {
+ throw new IllegalArgumentException();
+ }
+ return R_EXTENSION_INT;
+ }
+
+}
diff --git a/apex/sdkext/framework/java/android/os/ext/package.html b/apex/sdkext/framework/java/android/os/ext/package.html
new file mode 100644
index 0000000..34c1697
--- /dev/null
+++ b/apex/sdkext/framework/java/android/os/ext/package.html
@@ -0,0 +1,5 @@
+<HTML>
+<BODY>
+Provides APIs to interface with the SDK extensions.
+</BODY>
+</HTML>
diff --git a/apex/sdkext/framework/tests/Android.bp b/apex/sdkext/framework/tests/Android.bp
new file mode 100644
index 0000000..3d5dbb3
--- /dev/null
+++ b/apex/sdkext/framework/tests/Android.bp
@@ -0,0 +1,10 @@
+android_test {
+ name: "framework-sdkext-tests",
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.base",
+ "android.test.runner",
+ ],
+ static_libs: [ "framework-sdkext" ],
+ platform_apis: true,
+}
diff --git a/apex/sdkext/framework/tests/AndroidManifest.xml b/apex/sdkext/framework/tests/AndroidManifest.xml
new file mode 100644
index 0000000..831f132
--- /dev/null
+++ b/apex/sdkext/framework/tests/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?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.sdkext.tests">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.sdkext.tests" />
+
+</manifest>
diff --git a/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java b/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java
new file mode 100644
index 0000000..6885110
--- /dev/null
+++ b/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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.ext;
+
+import android.os.Build;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+public class SdkExtensionsTest extends TestCase {
+
+ @SmallTest
+ public void testBadArgument() throws Exception {
+ try {
+ SdkExtensions.getExtensionVersion(Build.VERSION_CODES.Q);
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException expected) { }
+
+ try {
+ SdkExtensions.getExtensionVersion(999999);
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException expected) { }
+ }
+
+ @SmallTest
+ public void testDefault() throws Exception {
+ int r = SdkExtensions.getExtensionVersion(Build.VERSION_CODES.R);
+ assertTrue(r >= 0);
+ }
+
+}
diff --git a/apex/sdkext/manifest.json b/apex/sdkext/manifest.json
new file mode 100644
index 0000000..048f5c4
--- /dev/null
+++ b/apex/sdkext/manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.sdkext",
+ "version": 1
+}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index 62c77ef..252f961 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -1163,12 +1163,12 @@
final WifiActivityEnergyInfo wifiInfo = awaitControllerInfo(wifiReceiver);
StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos,
wallClockNanos);
- e.writeLong(wifiInfo.getTimeStamp());
+ e.writeLong(wifiInfo.getTimeSinceBootMillis());
e.writeInt(wifiInfo.getStackState());
- e.writeLong(wifiInfo.getControllerTxTimeMillis());
- e.writeLong(wifiInfo.getControllerRxTimeMillis());
- e.writeLong(wifiInfo.getControllerIdleTimeMillis());
- e.writeLong(wifiInfo.getControllerEnergyUsed());
+ e.writeLong(wifiInfo.getControllerTxDurationMillis());
+ e.writeLong(wifiInfo.getControllerRxDurationMillis());
+ e.writeLong(wifiInfo.getControllerIdleDurationMillis());
+ e.writeLong(wifiInfo.getControllerEnergyUsedMicroJoules());
pulledData.add(e);
} catch (RemoteException e) {
Slog.e(TAG,
diff --git a/api/current.txt b/api/current.txt
index b66f830..b1eac59 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28928,6 +28928,7 @@
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();
@@ -28938,6 +28939,7 @@
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;
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 5a695a5..189585e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -213,6 +213,8 @@
field public static final String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS";
+ field public static final String WIFI_SET_DEVICE_MOBILITY_STATE = "android.permission.WIFI_SET_DEVICE_MOBILITY_STATE";
+ field public static final String WIFI_UPDATE_USABILITY_STATS_SCORE = "android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE";
field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
field public static final String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE";
field public static final String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS";
@@ -4441,7 +4443,6 @@
ctor public LinkProperties(@Nullable android.net.LinkProperties);
method public boolean addDnsServer(@NonNull java.net.InetAddress);
method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
- method @Nullable public android.net.IpPrefix getNat64Prefix();
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();
@@ -4455,7 +4456,6 @@
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 setNat64Prefix(@Nullable android.net.IpPrefix);
method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
method public void setPrivateDnsServerName(@Nullable String);
method public void setTcpBufferSizes(@Nullable String);
@@ -5276,18 +5276,30 @@
public final class SoftApConfiguration implements android.os.Parcelable {
method public int describeContents();
+ method public int getBand();
method @Nullable public android.net.MacAddress getBssid();
+ method public int getChannel();
+ method public int getSecurityType();
method @Nullable public String getSsid();
method @Nullable public String getWpa2Passphrase();
+ method public boolean isHiddenSsid();
method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int BAND_2GHZ = 0; // 0x0
+ field public static final int BAND_5GHZ = 1; // 0x1
+ field public static final int BAND_ANY = -1; // 0xffffffff
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApConfiguration> CREATOR;
+ field public static final int SECURITY_TYPE_OPEN = 0; // 0x0
+ field public static final int SECURITY_TYPE_WPA2_PSK = 1; // 0x1
}
public static final class SoftApConfiguration.Builder {
ctor public SoftApConfiguration.Builder();
ctor public SoftApConfiguration.Builder(@NonNull android.net.wifi.SoftApConfiguration);
method @NonNull public android.net.wifi.SoftApConfiguration build();
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBand(int);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBssid(@Nullable android.net.MacAddress);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setSsid(@Nullable String);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setWpa2Passphrase(@Nullable String);
}
@@ -5307,6 +5319,32 @@
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApInfo> CREATOR;
}
+ public final class WifiActivityEnergyInfo implements android.os.Parcelable {
+ ctor public WifiActivityEnergyInfo(long, int, long, long, long, long, long);
+ method public int describeContents();
+ method public long getControllerEnergyUsedMicroJoules();
+ method public long getControllerIdleDurationMillis();
+ method public long getControllerRxDurationMillis();
+ method public long getControllerScanDurationMillis();
+ method public long getControllerTxDurationMillis();
+ method public int getStackState();
+ method public long getTimeSinceBootMillis();
+ method public boolean isValid();
+ method public void setControllerEnergyUsedMicroJoules(long);
+ method public void setControllerIdleDurationMillis(long);
+ method public void setControllerRxDurationMillis(long);
+ method public void setControllerScanDurationMillis(long);
+ method public void setControllerTxDurationMillis(long);
+ method public void setStackState(int);
+ method public void setTimeSinceBootMillis(long);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.WifiActivityEnergyInfo> CREATOR;
+ field public static final int STACK_STATE_INVALID = 0; // 0x0
+ field public static final int STACK_STATE_STATE_ACTIVE = 1; // 0x1
+ field public static final int STACK_STATE_STATE_IDLE = 3; // 0x3
+ field public static final int STACK_STATE_STATE_SCANNING = 2; // 0x2
+ }
+
public final class WifiClient implements android.os.Parcelable {
method public int describeContents();
method @NonNull public android.net.MacAddress getMacAddress();
@@ -5425,7 +5463,7 @@
}
public class WifiManager {
- method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
+ method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoin(int, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener);
@@ -5441,8 +5479,9 @@
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(@Nullable java.util.List<android.net.wifi.ScanResult>);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(@NonNull java.util.Set<android.net.wifi.hotspot2.OsuProvider>);
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.SoftApConfiguration getSoftApConfiguration();
method public int getVerboseLoggingLevel();
- method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState();
method public boolean isApMacRandomizationSupported();
method public boolean isConnectedMacRandomizationSupported();
@@ -5458,26 +5497,29 @@
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerSoftApCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull android.net.wifi.WifiManager.TrafficStateCallback);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.TrafficStateCallback);
- method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
+ method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreBackupData(@NonNull byte[]);
+ method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreSoftApBackupData(@NonNull byte[]);
method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreSupplicantBackupData(@NonNull byte[], @NonNull byte[]);
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveBackupData();
+ method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveSoftApBackupData();
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
- method @RequiresPermission("android.permission.WIFI_SET_DEVICE_MOBILITY_STATE") public void setDeviceMobilityState(int);
- method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
+ method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeInitiator(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startLocalOnlyHotspot(@NonNull android.net.wifi.SoftApConfiguration, @Nullable java.util.concurrent.Executor, @Nullable android.net.wifi.WifiManager.LocalOnlyHotspotCallback);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public boolean startScan(android.os.WorkSource);
- method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean startSoftAp(@Nullable android.net.wifi.WifiConfiguration);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startSubscriptionProvisioning(@NonNull android.net.wifi.hotspot2.OsuProvider, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.hotspot2.ProvisioningCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean startTetheredHotspot(@Nullable android.net.wifi.SoftApConfiguration);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void stopEasyConnectSession();
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean stopSoftAp();
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterNetworkRequestMatchCallback(@NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterSoftApCallback(@NonNull android.net.wifi.WifiManager.SoftApCallback);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterTrafficStateCallback(@NonNull android.net.wifi.WifiManager.TrafficStateCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void updateInterfaceIpState(@Nullable String, int);
- method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void updateWifiUsabilityScore(int, int, int);
+ method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void updateWifiUsabilityScore(int, int, int);
field public static final String ACTION_LINK_CONFIGURATION_CHANGED = "android.net.wifi.LINK_CONFIGURATION_CHANGED";
field public static final String ACTION_PASSPOINT_LAUNCH_OSU_VIEW = "android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW";
field public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
@@ -8022,6 +8064,10 @@
field public static final int PROPERTY_REMOTELY_HOSTED = 2048; // 0x800
}
+ public final class ConnectionRequest implements android.os.Parcelable {
+ method @Nullable public String getTelecomCallId();
+ }
+
public abstract class ConnectionService extends android.app.Service {
method public final void addExistingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.Connection, @NonNull android.telecom.Conference);
}
@@ -8229,6 +8275,7 @@
method public java.util.List<android.telecom.PhoneAccountHandle> getAllPhoneAccountHandles();
method public java.util.List<android.telecom.PhoneAccount> getAllPhoneAccounts();
method public int getAllPhoneAccountsCount();
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean);
method public int getCallState();
method public android.telecom.PhoneAccountHandle getConnectionManager();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCurrentTtyMode();
diff --git a/api/test-current.txt b/api/test-current.txt
index 9445322..9ac789e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1466,7 +1466,6 @@
ctor public LinkProperties(@Nullable android.net.LinkProperties);
method public boolean addDnsServer(@NonNull java.net.InetAddress);
method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
- method @Nullable public android.net.IpPrefix getNat64Prefix();
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();
@@ -1480,7 +1479,6 @@
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 setNat64Prefix(@Nullable android.net.IpPrefix);
method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
method public void setPrivateDnsServerName(@Nullable String);
method public void setTcpBufferSizes(@Nullable String);
@@ -2974,6 +2972,23 @@
field public static final int PROPERTY_REMOTELY_HOSTED = 2048; // 0x800
}
+ public final class ConnectionRequest implements android.os.Parcelable {
+ method @Nullable public String getTelecomCallId();
+ }
+
+ public static final class ConnectionRequest.Builder {
+ ctor public ConnectionRequest.Builder();
+ method @NonNull public android.telecom.ConnectionRequest build();
+ method @NonNull public android.telecom.ConnectionRequest.Builder setAccountHandle(@NonNull android.telecom.PhoneAccountHandle);
+ method @NonNull public android.telecom.ConnectionRequest.Builder setAddress(@NonNull android.net.Uri);
+ method @NonNull public android.telecom.ConnectionRequest.Builder setExtras(@NonNull android.os.Bundle);
+ method @NonNull public android.telecom.ConnectionRequest.Builder setRttPipeFromInCall(@NonNull android.os.ParcelFileDescriptor);
+ method @NonNull public android.telecom.ConnectionRequest.Builder setRttPipeToInCall(@NonNull android.os.ParcelFileDescriptor);
+ method @NonNull public android.telecom.ConnectionRequest.Builder setShouldShowIncomingCallUi(boolean);
+ method @NonNull public android.telecom.ConnectionRequest.Builder setTelecomCallId(@NonNull String);
+ method @NonNull public android.telecom.ConnectionRequest.Builder setVideoState(int);
+ }
+
public static class PhoneAccount.Builder {
method @NonNull public android.telecom.PhoneAccount.Builder setGroupId(@NonNull String);
}
@@ -2987,6 +3002,7 @@
}
public class TelecomManager {
+ method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean);
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCurrentTtyMode();
method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDefaultDialerPackage(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
@@ -4274,6 +4290,7 @@
field public static final String PERSIST_PREFIX = "persist.sys.fflag.override.";
field public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
field public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer";
+ field public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
field public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 49cc3c4..2f22b49 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -6362,7 +6362,8 @@
optional bool is_preinstalled = 3;
// True if the package is privileged.
- optional bool is_priv_app = 4;
+ // Starting from Android 11, this boolean is not set and will always be false.
+ optional bool is_priv_app = 4 [deprecated = true];
}
/**
diff --git a/core/TEST_MAPPING b/core/TEST_MAPPING
new file mode 100644
index 0000000..fd571c9
--- /dev/null
+++ b/core/TEST_MAPPING
@@ -0,0 +1,24 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "android.view.inputmethod"
+ },
+ {
+ "include-filter": "com.android.internal.inputmethod"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ],
+ "file_patterns": [
+ "core/java/com/android/internal/inputmethod/.*",
+ "core/java/android/view/inputmethod/.*",
+ "core/tests/coretests/src/android/view/inputmethod/.*",
+ "core/tests/coretests/src/com/android/internal/inputmethod/.*"
+ ]
+ }
+ ]
+}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 0706e75..8e18341 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -762,10 +762,7 @@
* Returns the NAT64 prefix in use on this link, if any.
*
* @return the NAT64 prefix or {@code null}.
- * @hide
*/
- @SystemApi
- @TestApi
public @Nullable IpPrefix getNat64Prefix() {
return mNat64Prefix;
}
@@ -777,10 +774,7 @@
* 128-bit IPv6 address) are supported or {@code null} for no prefix.
*
* @param prefix the NAT64 prefix.
- * @hide
*/
- @SystemApi
- @TestApi
public void setNat64Prefix(@Nullable IpPrefix prefix) {
if (prefix != null && prefix.getPrefixLength() != 96) {
throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix);
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index ec39199..15ff69e 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -505,6 +505,19 @@
public static final native void restoreCallingWorkSource(long token);
/**
+ * Mark as being built with VINTF-level stability promise. This API should
+ * only ever be invoked by the build system. It means that the interface
+ * represented by this binder is guaranteed to be kept stable for several
+ * years, and the build system also keeps snapshots of these APIs and
+ * invokes the AIDL compiler to make sure that these snapshots are
+ * backwards compatible. Instead of using this API, use an @VintfStability
+ * interface.
+ *
+ * @hide
+ */
+ public final native void markVintfStability();
+
+ /**
* Flush any Binder commands pending in the current thread to the kernel
* driver. This can be
* useful to call before performing an operation that may block for a long
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
index 4d9ebc2..5b715c0 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -32,7 +32,7 @@
/**
* Monitors files (using <a href="http://en.wikipedia.org/wiki/Inotify">inotify</a>)
- * to fire an event after files are accessed or changed by by any process on
+ * to fire an event after files are accessed or changed by any process on
* the device (including this one). FileObserver is an abstract class;
* subclasses must implement the event handler {@link #onEvent(int, String)}.
*
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index ce91c50..74340f0 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -46,6 +46,7 @@
import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.location.LocationManager;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.view.WindowManager.LayoutParams;
@@ -486,13 +487,13 @@
*
* <p>This user restriction is different from {@link #DISALLOW_SHARE_LOCATION},
* as the device owner or profile owner can still enable or disable location mode via
- * {@link DevicePolicyManager#setSecureSetting} when this restriction is on.
+ * {@link DevicePolicyManager#setLocationEnabled} when this restriction is on.
*
* <p>The default value is <code>false</code>.
*
* <p>Key for user restrictions.
* <p>Type: Boolean
- * @see android.location.LocationManager#isProviderEnabled(String)
+ * @see LocationManager#isLocationEnabled()
* @see DevicePolicyManager#addUserRestriction(ComponentName, String)
* @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
* @see #getUserRestrictions()
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 7e09740..236e5ae 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -41,6 +41,7 @@
public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
+ public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
private static final Map<String, String> DEFAULT_FLAGS;
@@ -48,6 +49,7 @@
DEFAULT_FLAGS = new HashMap<>();
DEFAULT_FLAGS.put("settings_audio_switcher", "true");
DEFAULT_FLAGS.put("settings_systemui_theme", "true");
+ DEFAULT_FLAGS.put(SETTINGS_FUSE_FLAG, "false");
DEFAULT_FLAGS.put(DYNAMIC_SYSTEM, "false");
DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 6458737..1855a26 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -161,6 +161,8 @@
private static native boolean nativeSetAllowedDisplayConfigs(IBinder displayToken,
int[] allowedConfigs);
private static native int[] nativeGetAllowedDisplayConfigs(IBinder displayToken);
+ private static native boolean nativeSetDesiredDisplayConfigSpecs(IBinder displayToken,
+ int defaultModeId, float minRefreshRate, float maxRefreshRate);
private static native int[] nativeGetDisplayColorModes(IBinder displayToken);
private static native SurfaceControl.DisplayPrimaries nativeGetDisplayNativePrimaries(
IBinder displayToken);
@@ -1492,6 +1494,19 @@
/**
* @hide
*/
+ public static boolean setDesiredDisplayConfigSpecs(IBinder displayToken,
+ int defaultModeId, float minRefreshRate, float maxRefreshRate) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+
+ return nativeSetDesiredDisplayConfigSpecs(displayToken, defaultModeId, minRefreshRate,
+ maxRefreshRate);
+ }
+
+ /**
+ * @hide
+ */
public static int[] getDisplayColorModes(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 75a5804..b350028 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1870,6 +1870,7 @@
mCount = computeCurrentCountLocked();
mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = 0;
mUnpluggedReportedCount = mCurrentReportedCount = 0;
+ mTrackingReportedValues = false;
}
public void setUpdateVersion(int version) {
@@ -10800,10 +10801,10 @@
mHasWifiReporting = true;
// Measured in mAms
- final long txTimeMs = info.getControllerTxTimeMillis();
- final long rxTimeMs = info.getControllerRxTimeMillis();
- final long scanTimeMs = info.getControllerScanTimeMillis();
- final long idleTimeMs = info.getControllerIdleTimeMillis();
+ final long txTimeMs = info.getControllerTxDurationMillis();
+ final long rxTimeMs = info.getControllerRxDurationMillis();
+ final long scanTimeMs = info.getControllerScanDurationMillis();
+ final long idleTimeMs = info.getControllerIdleDurationMillis();
final long totalTimeMs = txTimeMs + rxTimeMs + idleTimeMs;
long leftOverRxTimeMs = rxTimeMs;
@@ -10946,13 +10947,14 @@
// Update WiFi controller stats.
- mWifiActivity.getRxTimeCounter().addCountLocked(info.getControllerRxTimeMillis());
+ mWifiActivity.getRxTimeCounter().addCountLocked(
+ info.getControllerRxDurationMillis());
mWifiActivity.getTxTimeCounters()[0].addCountLocked(
- info.getControllerTxTimeMillis());
+ info.getControllerTxDurationMillis());
mWifiActivity.getScanTimeCounter().addCountLocked(
- info.getControllerScanTimeMillis());
+ info.getControllerScanDurationMillis());
mWifiActivity.getIdleTimeCounter().addCountLocked(
- info.getControllerIdleTimeMillis());
+ info.getControllerIdleDurationMillis());
// POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
final double opVolt = mPowerProfile.getAveragePower(
@@ -10960,7 +10962,7 @@
if (opVolt != 0) {
// We store the power drain as mAms.
mWifiActivity.getPowerCounter().addCountLocked(
- (long) (info.getControllerEnergyUsed() / opVolt));
+ (long) (info.getControllerEnergyUsedMicroJoules() / opVolt));
}
// Converting uWs to mAms.
// Conversion: (uWs * (1000ms / 1s) * (1mW / 1000uW)) / mV = mAms
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 51f8fcc..148b0a2 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -110,6 +110,7 @@
"android_view_InputEventReceiver.cpp",
"android_view_InputEventSender.cpp",
"android_view_InputQueue.cpp",
+ "android_view_FrameMetricsObserver.cpp",
"android_view_KeyCharacterMap.cpp",
"android_view_KeyEvent.cpp",
"android_view_MotionEvent.cpp",
@@ -424,9 +425,9 @@
android: {
srcs: [ // sources that depend on android only libraries
"android/graphics/apex/android_canvas.cpp",
+ "android/graphics/apex/renderthread.cpp",
"android/graphics/apex/jni_runtime.cpp",
- "android_view_FrameMetricsObserver.cpp",
"android_view_TextureLayer.cpp",
"android_view_ThreadedRenderer.cpp",
"android/graphics/BitmapRegionDecoder.cpp",
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 2dec4b3..984f93c 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -12,7 +12,6 @@
#include "SkWebpEncoder.h"
#include "android_os_Parcel.h"
-#include "android_util_Binder.h"
#include "android_nio_utils.h"
#include "CreateJavaOutputStreamAdaptor.h"
#include <hwui/Paint.h>
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 6ffa72a..f18632d 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -25,18 +25,13 @@
#include "SkBitmapRegionDecoder.h"
#include "SkCodec.h"
#include "SkData.h"
-#include "SkUtils.h"
-#include "SkPixelRef.h"
#include "SkStream.h"
-#include "android_nio_utils.h"
-#include "android_util_Binder.h"
#include "core_jni_helpers.h"
#include <HardwareBitmapUploader.h>
#include <nativehelper/JNIHelp.h>
#include <androidfw/Asset.h>
-#include <binder/Parcel.h>
#include <jni.h>
#include <sys/stat.h>
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index 7a9fea7..4de6c86 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -7,6 +7,7 @@
#include "Utils.h"
#include <nativehelper/JNIHelp.h>
+#include <log/log.h>
#include <memory>
static jmethodID gInputStream_readMethodID;
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 9603a10..4ce56ba 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -22,8 +22,6 @@
#include <nativehelper/ScopedPrimitiveArray.h>
#include <nativehelper/ScopedUtfChars.h>
#include "SkTypeface.h"
-#include <android_runtime/android_util_AssetManager.h>
-#include <androidfw/AssetManager.h>
#include <hwui/Typeface.h>
#include <minikin/FontFamily.h>
#include <minikin/SystemFonts.h>
diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp
index 462d052..17c194d 100644
--- a/core/jni/android/graphics/Utils.cpp
+++ b/core/jni/android/graphics/Utils.cpp
@@ -18,6 +18,8 @@
#include "SkUtils.h"
#include "SkData.h"
+#include <log/log.h>
+
using namespace android;
AssetStreamAdaptor::AssetStreamAdaptor(Asset* asset)
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
index ac291ea..8925517 100644
--- a/core/jni/android/graphics/Utils.h
+++ b/core/jni/android/graphics/Utils.h
@@ -19,8 +19,6 @@
#include "SkStream.h"
-#include "android_util_Binder.h"
-
#include <jni.h>
#include <androidfw/Asset.h>
diff --git a/core/jni/android/graphics/apex/include/android/graphics/renderthread.h b/core/jni/android/graphics/apex/include/android/graphics/renderthread.h
new file mode 100644
index 0000000..0a790af
--- /dev/null
+++ b/core/jni/android/graphics/apex/include/android/graphics/renderthread.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_GRAPHICS_RENDERTHREAD_H
+#define ANDROID_GRAPHICS_RENDERTHREAD_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * Dumps a textual representation of the graphics stats for this process.
+ * @param fd The file descriptor that the available graphics stats will be appended to. The
+ * function requires a valid fd, but does not persist or assume ownership of the fd
+ * outside the scope of this function.
+ */
+void ARenderThread_dumpGraphicsMemory(int fd);
+
+__END_DECLS
+
+#endif // ANDROID_GRAPHICS_RENDERTHREAD_H
diff --git a/core/jni/android/graphics/apex/renderthread.cpp b/core/jni/android/graphics/apex/renderthread.cpp
new file mode 100644
index 0000000..5d26afe
--- /dev/null
+++ b/core/jni/android/graphics/apex/renderthread.cpp
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+#include "android/graphics/renderthread.h"
+
+#include <renderthread/RenderProxy.h>
+
+using namespace android;
+
+void ARenderThread_dumpGraphicsMemory(int fd) {
+ uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
+}
diff --git a/core/jni/android_app_ActivityThread.cpp b/core/jni/android_app_ActivityThread.cpp
index ca8b8de..5aa684d 100644
--- a/core/jni/android_app_ActivityThread.cpp
+++ b/core/jni/android_app_ActivityThread.cpp
@@ -17,13 +17,11 @@
#include "jni.h"
#include <nativehelper/JNIHelp.h>
-#include <minikin/Layout.h>
-#include <renderthread/RenderProxy.h>
-
#include "core_jni_helpers.h"
#include <unistd.h>
#include <bionic/malloc.h>
+#include <android/graphics/renderthread.h>
namespace android {
@@ -35,7 +33,7 @@
static void
android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
- android::uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
+ ARenderThread_dumpGraphicsMemory(fd);
}
static void android_app_ActivityThread_initZygoteChildHeapProfiling(JNIEnv* env, jobject clazz) {
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index cb7f0dd..f2a51ad 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -396,9 +396,8 @@
}
static sp<ANativeWindow> getSurfaceTextureNativeWindow(JNIEnv* env, jobject thiz) {
- sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, thiz));
- sp<Surface> surfaceTextureClient(surfaceTexture != NULL ? new Surface(producer) : NULL);
+ sp<Surface> surfaceTextureClient(producer != NULL ? new Surface(producer) : NULL);
return surfaceTextureClient;
}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 2232393..0992beb 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -30,12 +30,13 @@
#include <unistd.h>
#include <android-base/stringprintf.h>
-#include <binder/IInterface.h>
-#include <binder/IServiceManager.h>
-#include <binder/IPCThreadState.h>
-#include <binder/Parcel.h>
#include <binder/BpBinder.h>
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
#include <binder/ProcessState.h>
+#include <binder/Stability.h>
#include <cutils/atomic.h>
#include <log/log.h>
#include <utils/KeyedVector.h>
@@ -459,6 +460,9 @@
sp<JavaBBinder> b = mBinder.promote();
if (b == NULL) {
b = new JavaBBinder(env, obj);
+ if (mVintf) {
+ ::android::internal::Stability::markVintf(b.get());
+ }
mBinder = b;
ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%" PRId32 "\n",
b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());
@@ -473,9 +477,18 @@
return mBinder.promote();
}
+ void markVintf() {
+ mVintf = true;
+ }
+
private:
Mutex mLock;
wp<JavaBBinder> mBinder;
+
+ // in the future, we might condense this into int32_t stability, or if there
+ // is too much binder state here, we can think about making JavaBBinder an
+ // sp here (avoid recreating it)
+ bool mVintf = false;
};
// ----------------------------------------------------------------------------
@@ -965,6 +978,12 @@
IPCThreadState::self()->restoreCallingWorkSource(token);
}
+static void android_os_Binder_markVintfStability(JNIEnv* env, jobject clazz) {
+ JavaBBinderHolder* jbh =
+ (JavaBBinderHolder*) env->GetLongField(clazz, gBinderOffsets.mObject);
+ jbh->markVintf();
+}
+
static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz)
{
IPCThreadState::self()->flushCommands();
@@ -1041,6 +1060,7 @@
// @CriticalNative
{ "clearCallingWorkSource", "()J", (void*)android_os_Binder_clearCallingWorkSource },
{ "restoreCallingWorkSource", "(J)V", (void*)android_os_Binder_restoreCallingWorkSource },
+ { "markVintfStability", "()V", (void*)android_os_Binder_markVintfStability},
{ "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },
{ "getNativeBBinderHolder", "()J", (void*)android_os_Binder_getNativeBBinderHolder },
{ "getNativeFinalizer", "()J", (void*)android_os_Binder_getNativeFinalizer },
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 9f20388..bd202c1 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -810,6 +810,16 @@
return allowedConfigsArray;
}
+static jboolean nativeSetDesiredDisplayConfigSpecs(JNIEnv* env, jclass clazz,
+ jobject tokenObj, jint displayModeId, jfloat minRefreshRate, jfloat maxRefreshRate) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+ if (token == nullptr) return JNI_FALSE;
+
+ size_t result = SurfaceComposerClient::setDesiredDisplayConfigSpecs(
+ token, displayModeId, minRefreshRate, maxRefreshRate);
+ return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
+}
+
static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return -1;
@@ -1366,6 +1376,8 @@
(void*)nativeSetAllowedDisplayConfigs },
{"nativeGetAllowedDisplayConfigs", "(Landroid/os/IBinder;)[I",
(void*)nativeGetAllowedDisplayConfigs },
+ {"nativeSetDesiredDisplayConfigSpecs", "(Landroid/os/IBinder;IFF)Z",
+ (void*)nativeSetDesiredDisplayConfigSpecs },
{"nativeGetDisplayColorModes", "(Landroid/os/IBinder;)[I",
(void*)nativeGetDisplayColorModes},
{"nativeGetDisplayNativePrimaries", "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayPrimaries;",
diff --git a/core/jni/android_view_TextureLayer.cpp b/core/jni/android_view_TextureLayer.cpp
index 6475151..5491a33 100644
--- a/core/jni/android_view_TextureLayer.cpp
+++ b/core/jni/android_view_TextureLayer.cpp
@@ -17,7 +17,6 @@
#define LOG_TAG "OpenGLRenderer"
#include "jni.h"
-#include "GraphicsJNI.h"
#include <nativehelper/JNIHelp.h>
#include "core_jni_helpers.h"
@@ -27,12 +26,8 @@
#include <gui/surfacetexture/surface_texture_platform.h>
#include <gui/surfacetexture/SurfaceTexture.h>
#include <hwui/Paint.h>
-
#include <SkMatrix.h>
-
#include <DeferredLayerUpdater.h>
-#include <Rect.h>
-#include <RenderNode.h>
namespace android {
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index d181436..ab97fdd 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -693,6 +693,12 @@
// CATEGORY: SETTINGS
// OS: R
ACTION_CONTROLLER_UPDATE_STATE = 1728;
+
+ // Custom tag to evaluate the consuming time from onAttach to
+ // DashboardFragment.updatePreferenceStates.
+ // CATEGORY: SETTINGS
+ // OS: R
+ ACTION_DASHBOARD_VISIBLE_TIME = 1729;
}
/**
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 936099f..b83294c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1673,13 +1673,13 @@
<permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"
android:protectionLevel="signature" />
- <!-- #SystemApi @hide Allows device mobility state to be set so that Wifi scan interval can be increased
- when the device is stationary in order to save power.
+ <!-- @SystemApi @hide Allows device mobility state to be set so that Wifi scan interval can
+ be increased when the device is stationary in order to save power.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.WIFI_SET_DEVICE_MOBILITY_STATE"
android:protectionLevel="signature|privileged" />
- <!-- #SystemApi @hide Allows privileged system APK to update Wifi usability stats and score.
+ <!-- @SystemApi @hide Allows privileged system APK to update Wifi usability stats and score.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE"
android:protectionLevel="signature|privileged" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index d095690..4acdeeb 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Dien in"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Bestuurprogram werk tans"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tik om die bestuurprogram te verlaat."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Verbinding of Wi-Fi-warmkol aktief"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Tik om op te stel."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Verbinding is gedeaktiveer"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Kontak jou administrateur vir besonderhede"</string>
<string name="back_button_label" msgid="4078224038025043387">"Terug"</string>
<string name="next_button_label" msgid="6040209156399907780">"Volgende"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Slaan oor"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 75444ea..c6e55c3 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"አስረክብ"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"የመንዳት መተግበሪያ እያሄደ ነው"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ከመንዳት መተግበሪያ ለመውጣት መታ ያድርጉ።"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"መሰካት ወይም ገባሪ ድረስ ነጥብ"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"ለማዋቀር መታ ያድርጉ።"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"እንደ ሞደም መሰካት ተሰናክሏል"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ"</string>
<string name="back_button_label" msgid="4078224038025043387">"ተመለስ"</string>
<string name="next_button_label" msgid="6040209156399907780">"ቀጥሎ"</string>
<string name="skip_button_label" msgid="3566599811326688389">"ዝለል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 9928436..609b77e 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1509,10 +1509,6 @@
<string name="submit" msgid="862795280643405865">"إرسال"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"تطبيق القيادة قيد التشغيل"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"انقر للخروج من تطبيق القيادة."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"النطاق أو نقطة الاتصال نشطة"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"انقر للإعداد."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"تم إيقاف التوصيل"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"اتصل بالمشرف للحصول على التفاصيل"</string>
<string name="back_button_label" msgid="4078224038025043387">"رجوع"</string>
<string name="next_button_label" msgid="6040209156399907780">"التالي"</string>
<string name="skip_button_label" msgid="3566599811326688389">"التخطي"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index cfd6239..091b563 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"দাখিল কৰক"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ড্ৰাইভিং এপ্ চলি আছে"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ড্ৰাইভিং এপৰ পৰা বাহিৰ হ\'বলৈ টিপক।"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"টেডাৰিং বা হটস্প\'ট সক্ৰিয় অৱস্থাত আছে"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"ছেট আপ কৰিবলৈ টিপক।"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"টেডাৰিং অক্ষম কৰি থোৱা হৈছে"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক"</string>
<string name="back_button_label" msgid="4078224038025043387">"উভতি যাওক"</string>
<string name="next_button_label" msgid="6040209156399907780">"পৰৱৰ্তী"</string>
<string name="skip_button_label" msgid="3566599811326688389">"এৰি যাওক"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index a26d49d..359dfb7 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Göndər"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Sürücülük tətbiqi işləyir"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Sürücülük tətbiqindən çıxmaq üçün klikləyin."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Tezerinq və ya hotspot aktivdir"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Quraşdırmaq üçün tıklayın."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Birləşmə deaktivdir"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Məlumat üçün adminlə əlaqə saxlayın"</string>
<string name="back_button_label" msgid="4078224038025043387">"Geri"</string>
<string name="next_button_label" msgid="6040209156399907780">"Növbəti"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Keç"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 6d0ae6b..a27d359 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1449,10 +1449,6 @@
<string name="submit" msgid="862795280643405865">"Pošalji"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplikacija za vožnju je pokrenuta"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Dodirnite da biste izašli iz aplikacije za vožnju."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Aktivno povezivanje sa internetom preko mobilnog uređaja ili hotspot"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Dodirnite da biste podesili."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Privezivanje je onemogućeno"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Potražite detalje od administratora"</string>
<string name="back_button_label" msgid="4078224038025043387">"Nazad"</string>
<string name="next_button_label" msgid="6040209156399907780">"Next"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Preskoči"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 390e8b1..fb0fa33 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1469,10 +1469,6 @@
<string name="submit" msgid="862795280643405865">"Перадаць"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Праграма для ваджэння ўключана"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Націсніце, каб выйсці з праграмы для ваджэння."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"USB-мадэм або хот-спот Wi-Fi актыўныя"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Дакраніцеся, каб наладзіць."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Рэжым мадэма адключаны"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Звярніцеся да адміністратара па падрабязную інфармацыю"</string>
<string name="back_button_label" msgid="4078224038025043387">"Назад"</string>
<string name="next_button_label" msgid="6040209156399907780">"Далей"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Прапусціць"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index d47229df..69c998d 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Изпращане"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Приложението за шофиране е включено"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Докоснете, за да излезете от приложението за шофиране."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Има активна споделена връзка или безжична точка за достъп"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Докоснете, за да настроите."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Функцията за тетъринг е деактивирана"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Свържете се с администратора си за подробности"</string>
<string name="back_button_label" msgid="4078224038025043387">"Назад"</string>
<string name="next_button_label" msgid="6040209156399907780">"Напред"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Пропускане"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index a767a71..e335396 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"জমা দিন"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ড্রাইভিং অ্যাপ চালু আছে"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ড্রাইভিং অ্যাপ বন্ধ করতে ট্যাপ করুন।"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"টিথারিং বা হটস্পট সক্রিয় আছে"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"সেট-আপ করার জন্য আলতো চাপুন৷"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"টিথারিং অক্ষম করা আছে"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"বিশদ বিবরণের জন্য প্রশাসকের সাথে যোগাযোগ করুন"</string>
<string name="back_button_label" msgid="4078224038025043387">"ফিরুন"</string>
<string name="next_button_label" msgid="6040209156399907780">"পরবর্তী"</string>
<string name="skip_button_label" msgid="3566599811326688389">"এড়িয়ে যান"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index f1c1500..d7bd7a1 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1451,10 +1451,6 @@
<string name="submit" msgid="862795280643405865">"Potvrdi"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplikacija za vožnju je pokrenuta"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Dodirnite za izlaz iz aplikacije za vožnju."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Uređaj dijeli vezu ili djeluje kao pristupna tačka"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Dodirnite za postavke"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Povezivanje putem mobitela je onemogućeno"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Kontaktirajte svog administratora za dodatne detalje"</string>
<string name="back_button_label" msgid="4078224038025043387">"Nazad"</string>
<string name="next_button_label" msgid="6040209156399907780">"Naprijed"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Preskoči"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 4b19405..1f7d82e 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Envia"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"S\'està executant l\'aplicació de conducció"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Toca per sortir de l\'aplicació de conducció."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Compartició de xarxa o punt d\'accés Wi-Fi activat"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Toca per configurar."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"La compartició de xarxa està desactivada"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Contacta amb el teu administrador per obtenir més informació"</string>
<string name="back_button_label" msgid="4078224038025043387">"Enrere"</string>
<string name="next_button_label" msgid="6040209156399907780">"Següent"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Omet"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 22fd4c6..e05f299 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1469,10 +1469,6 @@
<string name="submit" msgid="862795280643405865">"Odeslat"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Jízdní aplikace je spuštěna"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Jízdní aplikaci zavřete klepnutím."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Sdílené připojení nebo hotspot je aktivní."</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Klepnutím zahájíte nastavení."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering je zakázán"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"O podrobnosti požádejte administrátora"</string>
<string name="back_button_label" msgid="4078224038025043387">"Zpět"</string>
<string name="next_button_label" msgid="6040209156399907780">"Další"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Přeskočit"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 4475a1b..772b7b0 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Send"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Bilkørselsappen er aktiv"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tryk for at lukke bilkørselsappen."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Netdeling eller hotspot er aktivt"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Tryk for at konfigurere"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Netdeling er deaktiveret"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Kontakt din administrator for at få oplysninger"</string>
<string name="back_button_label" msgid="4078224038025043387">"Tilbage"</string>
<string name="next_button_label" msgid="6040209156399907780">"Næste"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Spring over"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 2489fca..bb29a0e 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Senden"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Fahr-App wird ausgeführt"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tippen, um die Fahr-App zu beenden."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering oder Hotspot aktiv"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Zum Einrichten tippen."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering ist deaktiviert"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Bitte wende dich für weitere Informationen an den Administrator"</string>
<string name="back_button_label" msgid="4078224038025043387">"Zurück"</string>
<string name="next_button_label" msgid="6040209156399907780">"Weiter"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Überspringen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 6c76a1f..807c4c2 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Υποβολή"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Η εφαρμογή οδήγησης εκτελείται"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Πατήστε για να εξέλθετε από την εφαρμογή οδήγησης."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Πατήστε για ρύθμιση."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Η σύνδεση είναι απενεργοποιημένη"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες"</string>
<string name="back_button_label" msgid="4078224038025043387">"Πίσω"</string>
<string name="next_button_label" msgid="6040209156399907780">"Επόμενο"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Παράλειψη"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index e5f610b..8d2f805 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Submit"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Driving app is running"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tap to exit driving app."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering or hotspot active"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Tap to set up."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering is disabled"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Contact your admin for details"</string>
<string name="back_button_label" msgid="4078224038025043387">"Back"</string>
<string name="next_button_label" msgid="6040209156399907780">"Next"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Skip"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 2cff16f..e538587 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Submit"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Driving app is running"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tap to exit driving app."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering or hotspot active"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Tap to set up."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering is disabled"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Contact your admin for details"</string>
<string name="back_button_label" msgid="4078224038025043387">"Back"</string>
<string name="next_button_label" msgid="6040209156399907780">"Next"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Skip"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index e5f610b..8d2f805 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Submit"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Driving app is running"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tap to exit driving app."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering or hotspot active"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Tap to set up."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering is disabled"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Contact your admin for details"</string>
<string name="back_button_label" msgid="4078224038025043387">"Back"</string>
<string name="next_button_label" msgid="6040209156399907780">"Next"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Skip"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index e5f610b..8d2f805 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Submit"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Driving app is running"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tap to exit driving app."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering or hotspot active"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Tap to set up."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering is disabled"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Contact your admin for details"</string>
<string name="back_button_label" msgid="4078224038025043387">"Back"</string>
<string name="next_button_label" msgid="6040209156399907780">"Next"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Skip"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 6d536e4..1436692 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Submit"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Driving app is running"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tap to exit driving app."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering or hotspot active"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Tap to set up."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering is disabled"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Contact your admin for details"</string>
<string name="back_button_label" msgid="4078224038025043387">"Back"</string>
<string name="next_button_label" msgid="6040209156399907780">"Next"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Skip"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 3b9c7ad..b04882a 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Enviar"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Se está ejecutando la app de conducción"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Presiona para salir de la app de conducción."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Anclaje a red o zona activa conectados"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Presiona para configurar."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Se inhabilitó la conexión mediante dispositivo portátil"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Para obtener más información, comunícate con el administrador"</string>
<string name="back_button_label" msgid="4078224038025043387">"Atrás"</string>
<string name="next_button_label" msgid="6040209156399907780">"Siguiente"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Omitir"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 2e74904..81f210b 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Enviar"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplicación de conducción en uso"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Toca para salir de la aplicación de conducción."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Compartir conexión/Zona Wi-Fi activada"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Toca para configurar."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"La conexión compartida está inhabilitada"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Ponte en contacto con el administrador para obtener más información"</string>
<string name="back_button_label" msgid="4078224038025043387">"Atrás"</string>
<string name="next_button_label" msgid="6040209156399907780">"Siguiente"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Saltar"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 8561254..61b18bb 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Saada"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Sõidurakendus töötab"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Puudutage sõidurakendusest väljumiseks."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Jagamine või kuumkoht on aktiivne"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Puudutage seadistamiseks."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Jagamine on keelatud"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Lisateabe saamiseks võtke ühendust oma administraatoriga"</string>
<string name="back_button_label" msgid="4078224038025043387">"Tagasi"</string>
<string name="next_button_label" msgid="6040209156399907780">"Järgmine"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Jäta vahele"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 263b5ed..fda8565 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Bidali"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Abian da gidatzeko aplikazioa"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Sakatu gidatzeko aplikaziotik irteteko."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Konexioa partekatzea edo sare publikoa aktibo"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Sakatu konfiguratzeko."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Desgaituta dago konexioa partekatzeko aukera"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Xehetasunak lortzeko, jarri administratzailearekin harremanetan"</string>
<string name="back_button_label" msgid="4078224038025043387">"Atzera"</string>
<string name="next_button_label" msgid="6040209156399907780">"Hurrengoa"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Saltatu"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 997b6af..433d4f3 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"ارسال"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"برنامه رانندگی درحال اجرا است"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"برای خروج از برنامه رانندگی ضربه بزنید."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"اشتراکگذاری اینترنت یا نقطه اتصال فعال"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"برای راهاندازی ضربه بزنید."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"اشتراکگذاری اینترنت غیرفعال است"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"برای جزئیات، با سرپرستتان تماس بگیرید"</string>
<string name="back_button_label" msgid="4078224038025043387">"برگشت"</string>
<string name="next_button_label" msgid="6040209156399907780">"بعدی"</string>
<string name="skip_button_label" msgid="3566599811326688389">"رد شدن"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 86badf6..0c7bd77 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Lähetä"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Ajosovellus on käynnissä"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Poistu ajosovelluksesta napauttamalla."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Internetin jakaminen tai yhteyspiste käytössä"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Määritä napauttamalla."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Yhteyden jakaminen poistettu käytöstä"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Kysy lisätietoja järjestelmänvalvojalta."</string>
<string name="back_button_label" msgid="4078224038025043387">"Takaisin"</string>
<string name="next_button_label" msgid="6040209156399907780">"Seuraava"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Ohita"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 2b89065..3c8f75f 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Envoyer"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"L\'application de conduite est en cours d\'exécution"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Touchez pour quitter l\'application de conduite."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Partage de connexion ou point d\'accès sans fil activé"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Touchez pour configurer."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Le partage de connexion est désactivé"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Communiquez avec votre administrateur pour obtenir plus de détails"</string>
<string name="back_button_label" msgid="4078224038025043387">"Précédent"</string>
<string name="next_button_label" msgid="6040209156399907780">"Suivante"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Passer"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 7522b5aa..1b53bd9 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Envoyer"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"L\'application de conduite est en cours d\'exécution"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Appuyez ici pour quitter l\'application de conduite."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Partage de connexion ou point d\'accès sans fil activé"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Appuyez ici pour configurer."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Le partage de connexion est désactivé"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Pour en savoir plus, contactez votre administrateur"</string>
<string name="back_button_label" msgid="4078224038025043387">"Retour"</string>
<string name="next_button_label" msgid="6040209156399907780">"Suivant"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Ignorer"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 4d40e21..4572db7 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Enviar"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Estase executando a aplicación de condución"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Toca para saír da aplicación de condución."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Conexión compartida ou zona wifi activada"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Tocar para configurar."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"A conexión compartida está desactivada"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Contacta co administrador para obter información"</string>
<string name="back_button_label" msgid="4078224038025043387">"Volver"</string>
<string name="next_button_label" msgid="6040209156399907780">"Seguinte"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Omitir"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index ea3a573..5e4f753 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"સબમિટ કરો"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ડ્રાઇવિંગ ઍપ ચાલી રહી છે"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ડ્રાઇવિંગ ઍપથી બહાર નીકળવા માટે ટૅપ કરો."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"ટિથરિંગ અથવા હૉટસ્પૉટ સક્રિય"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"સેટ કરવા માટે ટૅપ કરો."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"ટિથરિંગ અક્ષમ કરેલ છે"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો"</string>
<string name="back_button_label" msgid="4078224038025043387">"પાછળ"</string>
<string name="next_button_label" msgid="6040209156399907780">"આગલું"</string>
<string name="skip_button_label" msgid="3566599811326688389">"છોડો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index e12fa08..eecfd5b 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"सबमिट करें"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ड्राइविंग ऐप्लिकेशन चल रहा है"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ड्राइविंग ऐप्लिकेशन से निकलने के लिए टैप करें."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"टेदरिंग या हॉटस्पॉट सक्रिय"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"सेट करने के लिए टैप करें."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"टेदरिंग अक्षम है"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"जानकारी के लिए अपने एडमिन से संपर्क करें"</string>
<string name="back_button_label" msgid="4078224038025043387">"वापस जाएं"</string>
<string name="next_button_label" msgid="6040209156399907780">"आगे बढ़ें"</string>
<string name="skip_button_label" msgid="3566599811326688389">"अभी नहीं"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 0871d06..e8f02b2 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1449,10 +1449,6 @@
<string name="submit" msgid="862795280643405865">"Pošalji"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Pokrenuta je aplikacija za vožnju"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Dodirnite za zatvaranje aplikacije za vožnju."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Ograničenje ili aktivan hotspot"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Dodirnite da biste postavili."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Modemsko je povezivanje onemogućeno"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Obratite se administratoru da biste saznali pojedinosti"</string>
<string name="back_button_label" msgid="4078224038025043387">"Natrag"</string>
<string name="next_button_label" msgid="6040209156399907780">"Dalje"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Preskoči"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index ce11fc6..1d1b994 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Elküldés"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Az autós alkalmazás fut"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Koppintson ide az autós alkalmazásból való kilépéshez."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Megosztás vagy aktív hotspot"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Koppintson a beállításhoz."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Az internetmegosztás le van tiltva"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"A részletekért forduljon rendszergazdájához"</string>
<string name="back_button_label" msgid="4078224038025043387">"Vissza"</string>
<string name="next_button_label" msgid="6040209156399907780">"Tovább"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Kihagyás"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 629b225..599ce86 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Ուղարկել"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Հավելվածն աշխատում է"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Հպեք՝ հավելվածը փակելու համար:"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Մոդեմի ռեժիմը միացված է"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Հպեք՝ կարգավորելու համար:"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Մոդեմի ռեժիմն անջատված է"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Մանրամասների համար դիմեք ձեր ադմինիստրատորին"</string>
<string name="back_button_label" msgid="4078224038025043387">"Հետ"</string>
<string name="next_button_label" msgid="6040209156399907780">"Հաջորդը"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Բաց թողնել"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index f99c107..1f81eb5 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Kirim"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplikasi mengemudi sedang berjalan"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Ketuk untuk keluar dari aplikasi mengemudi."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering (Penambatan) atau hotspot aktif"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Ketuk untuk menyiapkan."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering dinonaktifkan"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Hubungi admin untuk mengetahui detailnya"</string>
<string name="back_button_label" msgid="4078224038025043387">"Kembali"</string>
<string name="next_button_label" msgid="6040209156399907780">"Selanjutnya"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Lewati"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 0f4d6de..d23cf5f 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Senda"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Akstursforrit er í gangi"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Ýttu til að loka akstursforritinu."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Kveikt á tjóðrun eða aðgangsstað"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Ýttu til að setja upp."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Slökkt er á tjóðrun"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Hafðu samband við kerfisstjórann til að fá upplýsingar"</string>
<string name="back_button_label" msgid="4078224038025043387">"Til baka"</string>
<string name="next_button_label" msgid="6040209156399907780">"Áfram"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Sleppa"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index f14e858..8ebcb0e 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Invia"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"App di guida in esecuzione"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tocca per uscire dall\'app di guida."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering oppure hotspot attivo"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Tocca per impostare."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering disattivato"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Contatta il tuo amministratore per avere informazioni dettagliate"</string>
<string name="back_button_label" msgid="4078224038025043387">"Indietro"</string>
<string name="next_button_label" msgid="6040209156399907780">"Avanti"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Ignora"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 375d7d1..85d0f3b 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1469,10 +1469,6 @@
<string name="submit" msgid="862795280643405865">"שלח"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"אפליקציית הנהיגה פועלת"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"יש להקיש כדי לצאת מאפליקציית הנהיגה."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"שיתוף אינטרנט פעיל"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"הקש כדי להגדיר."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"שיתוף האינטרנט בין ניידים מושבת"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"לפרטים, יש לפנות למנהל המערכת"</string>
<string name="back_button_label" msgid="4078224038025043387">"הקודם"</string>
<string name="next_button_label" msgid="6040209156399907780">"הבא"</string>
<string name="skip_button_label" msgid="3566599811326688389">"דילוג"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index eb990ec..e21035f 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"送信"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"運転アプリを実行しています"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"運転アプリを終了するにはタップしてください。"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"テザリングまたはアクセスポイントが有効です"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"タップしてセットアップします。"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"テザリングは無効に設定されています"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"詳しくは、管理者にお問い合わせください"</string>
<string name="back_button_label" msgid="4078224038025043387">"戻る"</string>
<string name="next_button_label" msgid="6040209156399907780">"次へ"</string>
<string name="skip_button_label" msgid="3566599811326688389">"スキップ"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index d2d1fed..941dbbd 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"გაგზავნა"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"მართვის აპი გაშვებულია"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"შეეხეთ მართვის აპიდან გასასვლელად."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"ტეტერინგი ან უსადენო ქსელი აქტიურია"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"შეეხეთ დასაყენებლად."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"ტეტერინგი გათიშულია"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს"</string>
<string name="back_button_label" msgid="4078224038025043387">"უკან"</string>
<string name="next_button_label" msgid="6040209156399907780">"მომდევნო"</string>
<string name="skip_button_label" msgid="3566599811326688389">"გამოტოვება"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index a1002f7..b142e58 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Жіберу"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Көлік жүргізу қолданбасы қосулы"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Көлік жүргізу қолданбасынан шығу үшін түртіңіз."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Тетеринг немесе хотспот қосулы"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Реттеу үшін түртіңіз."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Тетеринг өшірілді"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Мәліметтерді әкімшіден алыңыз"</string>
<string name="back_button_label" msgid="4078224038025043387">"Артқа"</string>
<string name="next_button_label" msgid="6040209156399907780">"Келесі"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Өткізіп жіберу"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 61a3ec6..43289eb 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1431,10 +1431,6 @@
<string name="submit" msgid="862795280643405865">"ដាក់ស្នើ"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"កម្មវិធីបើកបរកំពុងដំណើរការ"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ចុចដើម្បីចាកចេញពីកម្មវិធីបើកបរ។"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"ភ្ជាប់ ឬហតស្ពតសកម្ម"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"ប៉ះដើម្បីកំណត់"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"ការភ្ជាប់ត្រូវបានបិទ"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"ទាក់ទងអ្នកគ្រប់គ្រងរបស់អ្នកសម្រាប់ព័ត៌មានលម្អិត"</string>
<string name="back_button_label" msgid="4078224038025043387">"ថយក្រោយ"</string>
<string name="next_button_label" msgid="6040209156399907780">"បន្ទាប់"</string>
<string name="skip_button_label" msgid="3566599811326688389">"រំលង"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 5524d40..6ebe7b4 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"ಸಲ್ಲಿಸು"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ಡ್ರೈವಿಂಗ್ ಅಪ್ಲಿಕೇಶನ್ ಚಾಲನೆಯಲ್ಲಿದೆ"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ಡ್ರೈವಿಂಗ್ ಅಪ್ಲಿಕೇಶನ್ ನಿರ್ಗಮಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ"</string>
<string name="back_button_label" msgid="4078224038025043387">"ಹಿಂದೆ"</string>
<string name="next_button_label" msgid="6040209156399907780">"ಮುಂದಿನದು"</string>
<string name="skip_button_label" msgid="3566599811326688389">"ಸ್ಕಿಪ್"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 423dbd6..c6caedf 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"제출"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"운전 앱 실행 중"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"운전 앱을 종료하려면 탭하세요."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"테더링 또는 핫스팟 사용"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"설정하려면 탭하세요."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"테더링이 사용 중지됨"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"자세한 정보는 관리자에게 문의하세요."</string>
<string name="back_button_label" msgid="4078224038025043387">"뒤로"</string>
<string name="next_button_label" msgid="6040209156399907780">"다음"</string>
<string name="skip_button_label" msgid="3566599811326688389">"건너뛰기"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index d1d773c..341c996 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Тапшыруу"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Унаа айдоо колдонмосу иштеп жатат"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Унаа айдоо колдонмосунан чыгуу үчүн таптаңыз."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Жалгаштыруу же хотспот жандырылган"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Жөндөө үчүн таптап коюңуз."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Жалгаштыруу функциясы өчүрүлгөн"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Кеңири маалымат үчүн администраторуңузга кайрылыңыз"</string>
<string name="back_button_label" msgid="4078224038025043387">"Артка"</string>
<string name="next_button_label" msgid="6040209156399907780">"Кийинки"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Өткөрүп жиберүү"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index ded2a4f..e0da206 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"ສົ່ງຂໍ້ມູນ"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ແອັບຂັບລົດກຳລັງເຮັດວຽກຢູ່"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ແຕະເພື່ອອອກຈາກແອັບຂັບລົດ."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"ເປີດການປ່ອຍສັນຍານ ຫຼືຮັອດສະປອດແລ້ວ"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"ແຕະເພື່ອຕັ້ງຄ່າ."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"ການປ່ອຍສັນຍານຖືກປິດໄວ້"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ"</string>
<string name="back_button_label" msgid="4078224038025043387">"ກັບຄືນ"</string>
<string name="next_button_label" msgid="6040209156399907780">"ຕໍ່ໄປ"</string>
<string name="skip_button_label" msgid="3566599811326688389">"ຂ້າມ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index eac535c..1212aa4 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1469,10 +1469,6 @@
<string name="submit" msgid="862795280643405865">"Pateikti"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Veikia vairavimo programa"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Palieskite, kad išeitumėte iš vairavimo programos."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Susietas ar aktyvus"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Palieskite, kad nustatytumėte."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Įrenginio kaip modemo naudojimas išjungtas"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Jei reikia išsamios informacijos, susisiekite su administratoriumi"</string>
<string name="back_button_label" msgid="4078224038025043387">"Atgal"</string>
<string name="next_button_label" msgid="6040209156399907780">"Kitas"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Praleisti"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index f586212..547b6c9 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1449,10 +1449,6 @@
<string name="submit" msgid="862795280643405865">"Iesniegt"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Autovadīšanas lietotne darbojas"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Pieskarieties, lai izietu no autovadīšanas lietotnes"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Piesaiste vai tīklājs ir aktīvs."</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Pieskarieties, lai iestatītu."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Piesaiste ir atspējota"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru."</string>
<string name="back_button_label" msgid="4078224038025043387">"Atpakaļ"</string>
<string name="next_button_label" msgid="6040209156399907780">"Tālāk"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Izlaist"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 0d308a1..93f2da1 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Поднеси"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Апликацијата за возење работи"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Допрете за да излезете од апликацијата за возење."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Поврзувањето или точката на пристап се активни"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Допрете за поставување."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Врзувањето е оневозможено"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Контактирајте со администраторот за детали"</string>
<string name="back_button_label" msgid="4078224038025043387">"Назад"</string>
<string name="next_button_label" msgid="6040209156399907780">"Следно"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Прескокни"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 63a7194..c220cdd 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"സമർപ്പിക്കുക"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ഡ്രൈവിംഗ് ആപ്പ് റൺ ചെയ്യുകയാണ്"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ഡ്രൈവിംഗ് ആപ്പിൽ നിന്ന് പുറത്തുകടക്കാൻ ടാപ്പ് ചെയ്യുക."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്പോട്ട് സജീവമാണ്"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"സജ്ജമാക്കാൻ ടാപ്പുചെയ്യുക."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"വിശദവിവരങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക"</string>
<string name="back_button_label" msgid="4078224038025043387">"മടങ്ങുക"</string>
<string name="next_button_label" msgid="6040209156399907780">"അടുത്തത്"</string>
<string name="skip_button_label" msgid="3566599811326688389">"ഒഴിവാക്കുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index b3cf5ce..8c26113 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Илгээх"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Жолоо барих апп ажиллаж байна"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Жолооны аппаас гарахын тулд товшино уу."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Модем болгох эсвэл идэвхтэй цэг болгох"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Тохируулахын тулд товшино уу."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Модем болгох боломжгүй байна"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу"</string>
<string name="back_button_label" msgid="4078224038025043387">"Буцах"</string>
<string name="next_button_label" msgid="6040209156399907780">"Дараах"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Алгасах"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 22b1dcc..2782caf 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"सबमिट करा"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ड्रायव्हिंग अॅप चालू आहे"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ड्रायव्हिंग ॲपमधून बाहेर पाडण्यासाठी टॅप करा."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"टेदरिंग किंवा हॉटस्पॉट सक्रिय"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"सेट करण्यासाठी टॅप करा."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"टेदरिंग बंद आहे"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"तपशीलांसाठी तुमच्या प्रशासकाशी संपर्क साधा"</string>
<string name="back_button_label" msgid="4078224038025043387">"मागे"</string>
<string name="next_button_label" msgid="6040209156399907780">"पुढील"</string>
<string name="skip_button_label" msgid="3566599811326688389">"वगळा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 88c12b6..a40eca0 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Serah"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Apl memandu sedang berjalan"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Ketik untuk keluar daripada apl memandu."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Penambatan atau titik panas aktif"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Ketik untuk membuat persediaan."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Penambatan dilumpuhkan"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Hubungi pentadbir anda untuk maklumat lanjut"</string>
<string name="back_button_label" msgid="4078224038025043387">"Kembali"</string>
<string name="next_button_label" msgid="6040209156399907780">"Seterusnya"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Langkau"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index cdf68cd..64e2376 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"ပေးပို့ရန်"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ကားမောင်းသည့်အက်ပ် ပွင့်နေပါသည်"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ကားမောင်းသည့်အက်ပ်မှ ထွက်ရန် တို့ပါ။"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"တဆင့်ပြန်လည်လွှင့်ခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"စနစ်ထည့်သွင်းရန် တို့ပါ။"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"မိုဘိုင်းဖုန်းကို မိုဒမ်အဖြစ်သုံးခြင်းအား ပိတ်ထားသည်"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"အသေးစိတ်အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ"</string>
<string name="back_button_label" msgid="4078224038025043387">"နောက်သို့"</string>
<string name="next_button_label" msgid="6040209156399907780">"ရှေ့သို့"</string>
<string name="skip_button_label" msgid="3566599811326688389">"ကျော်ရန်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index b129c3c..69e341e 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Send inn"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Kjøreappen kjører"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Trykk for å lukke kjøreappen."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Internettdeling eller trådløs sone er aktiv"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Trykk for å konfigurere."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Internettdeling er slått av"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Ta kontakt med administratoren din for å få mer informasjon"</string>
<string name="back_button_label" msgid="4078224038025043387">"Tilbake"</string>
<string name="next_button_label" msgid="6040209156399907780">"Neste"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Hopp over"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 648f47c..0fb2213 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1435,10 +1435,6 @@
<string name="submit" msgid="862795280643405865">"पेस गर्नुहोस्"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ड्राइभिङ अनुप्रयोग चलिरहेको छ"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ड्राइभिङ अनुप्रयोगबाट बाहिर निस्कन ट्याप गर्नुहोस्।"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"टेथर गर्ने वा हटस्पट सक्रिय"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"सेटअप गर्न ट्याप गर्नुहोस्।"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"टेदरिङलाई असक्षम पारिएको छ"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्"</string>
<string name="back_button_label" msgid="4078224038025043387">"पछाडि"</string>
<string name="next_button_label" msgid="6040209156399907780">"अर्को"</string>
<string name="skip_button_label" msgid="3566599811326688389">"छोड्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index e248ca1..363c3c3 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Verzenden"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Auto-app wordt uitgevoerd"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tik om de auto-app te sluiten."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering of hotspot actief"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Tik om in te stellen."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering is uitgeschakeld"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Neem contact op met je beheerder voor meer informatie"</string>
<string name="back_button_label" msgid="4078224038025043387">"Vorige"</string>
<string name="next_button_label" msgid="6040209156399907780">"Volgende"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Overslaan"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 7a73cc6..566d778 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"ଦାଖଲ କରନ୍ତୁ"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ଡ୍ରାଇଭିଙ୍ଗ ଆପ୍ ଚାଲୁଛି"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ଡ୍ରାଇଭିଙ୍ଗ ଆପ୍ରୁ ବାହାରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"ଟିଥରିଙ୍ଗ କିମ୍ୱା ହଟସ୍ପଟ୍ ସକ୍ରିୟ ଅଛି"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"ସେଟଅପ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"ଟିଥରିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"ବିବରଣୀ ପାଇଁ ନିଜ ଆଡମିନ୍ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ"</string>
<string name="back_button_label" msgid="4078224038025043387">"ଫେରନ୍ତୁ"</string>
<string name="next_button_label" msgid="6040209156399907780">"ପରବର୍ତ୍ତୀ"</string>
<string name="skip_button_label" msgid="3566599811326688389">"ଛାଡ଼ିଦିଅନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 3a245e3..7760db0 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"ਪ੍ਰਸਤੁਤ ਕਰੋ"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ਗੱਡੀ ਚਲਾਉਣ ਸੰਬੰਧੀ ਐਪ ਚੱਲ ਰਹੀ ਹੈ"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ਗੱਡੀ ਚਲਾਉਣ ਸੰਬੰਧੀ ਐਪ ਤੋਂ ਬਾਹਰ ਜਾਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"ਸਥਾਪਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"ਟੈਦਰਿੰਗ ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ"</string>
<string name="back_button_label" msgid="4078224038025043387">"ਪਿੱਛੇ"</string>
<string name="next_button_label" msgid="6040209156399907780">"ਅੱਗੇ"</string>
<string name="skip_button_label" msgid="3566599811326688389">"ਛੱਡੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 7a86bd5..4ff7cc4 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1469,10 +1469,6 @@
<string name="submit" msgid="862795280643405865">"Prześlij"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Tryb samochodowy jest włączony"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Kliknij, by zakończyć tryb samochodowy."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Aktywny tethering lub punkt dostępu"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Kliknij, by skonfigurować."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering został wyłączony"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem"</string>
<string name="back_button_label" msgid="4078224038025043387">"Wróć"</string>
<string name="next_button_label" msgid="6040209156399907780">"Dalej"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Pomiń"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 3f82a80..1750d2a 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Enviar"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"O app para carro está sendo usado"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Toque para sair do app para carro."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Ponto de acesso ou tethering ativo"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Toque para configurar."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering desativado"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Fale com seu administrador para saber detalhes"</string>
<string name="back_button_label" msgid="4078224038025043387">"Voltar"</string>
<string name="next_button_label" msgid="6040209156399907780">"Avançar"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Pular"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index f67c96f..5c21c0d 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Enviar"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"A aplicação de condução está em execução."</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Toque para sair da aplicação de condução."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Ligação ponto a ponto ou hotspot activos"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Toque para configurar."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"A ligação (à Internet) via telemóvel está desativada."</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Contacte o gestor para obter detalhes."</string>
<string name="back_button_label" msgid="4078224038025043387">"Anterior"</string>
<string name="next_button_label" msgid="6040209156399907780">"Seguinte"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Ignorar"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 3f82a80..1750d2a 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Enviar"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"O app para carro está sendo usado"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Toque para sair do app para carro."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Ponto de acesso ou tethering ativo"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Toque para configurar."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering desativado"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Fale com seu administrador para saber detalhes"</string>
<string name="back_button_label" msgid="4078224038025043387">"Voltar"</string>
<string name="next_button_label" msgid="6040209156399907780">"Avançar"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Pular"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 846b982..397525a 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1449,10 +1449,6 @@
<string name="submit" msgid="862795280643405865">"Trimiteți"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplicația pentru condus rulează"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Atingeți ca să ieșiți din aplicația pentru condus."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering sau hotspot activ"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Atingeți ca să configurați."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tetheringul este dezactivat"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Contactați administratorul pentru detalii"</string>
<string name="back_button_label" msgid="4078224038025043387">"Înapoi"</string>
<string name="next_button_label" msgid="6040209156399907780">"Înainte"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Omiteți"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 19fde9f..a7abbff 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1469,10 +1469,6 @@
<string name="submit" msgid="862795280643405865">"Отправить"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Приложение для вождения включено"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Нажмите, чтобы выйти из приложения для вождения."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Включен режим модема"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Нажмите, чтобы настроить."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Включить режим модема нельзя"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Обратитесь к администратору, чтобы узнать подробности."</string>
<string name="back_button_label" msgid="4078224038025043387">"Назад"</string>
<string name="next_button_label" msgid="6040209156399907780">"Далее"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Пропустить"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 676b48f..7d3f80d 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1431,10 +1431,6 @@
<string name="submit" msgid="862795280643405865">"යොමු කරන්න"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"රියදුරු යෙදුම ධාවනය වේ."</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"රියදුරු යෙදුමෙන් පිටවීම සඳහා තට්ටු කරන්න."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"ටෙදරින් හෝ හොට්ස්පොට් සක්රීයයි"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"පිහිටුවීමට තට්ටු කරන්න."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"ටෙදරින් අබල කර ඇත"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න"</string>
<string name="back_button_label" msgid="4078224038025043387">"ආපසු"</string>
<string name="next_button_label" msgid="6040209156399907780">"මීලඟ"</string>
<string name="skip_button_label" msgid="3566599811326688389">"මඟ හරින්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index cde5466..3a81468c 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1469,10 +1469,6 @@
<string name="submit" msgid="862795280643405865">"Odoslať"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplikácia na šoférovanie je spustená"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Klepnutím ukončíte aplikáciu na šoférovanie"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering alebo prístupový bod je aktívny"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Klepnutím prejdete na nastavenie."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering je deaktivovaný"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"O podrobnosti požiadajte svojho správcu"</string>
<string name="back_button_label" msgid="4078224038025043387">"Späť"</string>
<string name="next_button_label" msgid="6040209156399907780">"Ďalej"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Preskočiť"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 0494068..c28384c 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1469,10 +1469,6 @@
<string name="submit" msgid="862795280643405865">"Pošlji"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplikacija za vožnjo se izvaja"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Dotaknite se, če želite zapreti aplikacijo za vožnjo."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Aktivna povezava z internetom ali dostopna točka sta aktivni"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Dotaknite se, če želite nastaviti."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Povezava z internetom prek mobilnega telefona je onemogočena"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Za podrobnosti se obrnite na skrbnika"</string>
<string name="back_button_label" msgid="4078224038025043387">"Nazaj"</string>
<string name="next_button_label" msgid="6040209156399907780">"Naprej"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Preskoči"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 20e6ae5..39f7377 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Dërgo"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplikacioni i drejtimit të makinës është në ekzekutim"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Trokit për të dalë nga aplikacioni i drejtimit të makinës."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Lidhja e çiftimit ose ajo e qasjes në zona publike interneti është aktive"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Trokit për ta konfiguruar."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Lidhja e çiftimit është çaktivizuar"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Kontakto me administratorin për detaje"</string>
<string name="back_button_label" msgid="4078224038025043387">"Prapa"</string>
<string name="next_button_label" msgid="6040209156399907780">"Përpara"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Kapërce"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index db53b23..e93c852 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1449,10 +1449,6 @@
<string name="submit" msgid="862795280643405865">"Пошаљи"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Апликација за вожњу је покренута"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Додирните да бисте изашли из апликације за вожњу."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Активно повезивање са интернетом преко мобилног уређаја или хотспот"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Додирните да бисте подесили."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Привезивање је онемогућено"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Потражите детаље од администратора"</string>
<string name="back_button_label" msgid="4078224038025043387">"Назад"</string>
<string name="next_button_label" msgid="6040209156399907780">"Next"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Прескочи"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 9e99aec..cf0e0bb 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Skicka"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Bilkörningsappen körs"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Tryck här om du vill avsluta bilkörningsappen."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Internetdelning eller surfzon aktiverad"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Tryck om du vill konfigurera."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Internetdelning har inaktiverats"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Kontakta administratören om du vill veta mer"</string>
<string name="back_button_label" msgid="4078224038025043387">"Tillbaka"</string>
<string name="next_button_label" msgid="6040209156399907780">"Nästa"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Hoppa över"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index d7b3555..f8cd19c 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Wasilisha"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Umewasha programu ya kuendesha gari"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Gusa ili ufunge programu ya kuendesha gari."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Kushiriki au kusambaza intaneti kumewashwa"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Gusa ili uweke mipangilio."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Umezima kipengele cha kusambaza mtandao"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Wasiliana na msimamizi wako ili upate maelezo zaidi"</string>
<string name="back_button_label" msgid="4078224038025043387">"Nyuma"</string>
<string name="next_button_label" msgid="6040209156399907780">"Endelea"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Ruka"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 569977c..ac284d3 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"சமர்ப்பி"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"\'வாகனம் ஓட்டும் பயன்முறை’ ஆனில் உள்ளது"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"வாகனம் ஓட்டும் பயன்முறையிலிருந்து வெளியேற, தட்டவும்."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"டெதெரிங்/ஹாட்ஸ்பாட் இயங்குகிறது"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"அமைக்க, தட்டவும்."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"இணைப்பு முறை முடக்கப்பட்டுள்ளது"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"விவரங்களுக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்"</string>
<string name="back_button_label" msgid="4078224038025043387">"முந்தையது"</string>
<string name="next_button_label" msgid="6040209156399907780">"அடுத்து"</string>
<string name="skip_button_label" msgid="3566599811326688389">"தவிர்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 9600172..6641c41 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"సమర్పించు"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"డ్రైవింగ్ యాప్ అమలవుతోంది"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"డ్రైవింగ్ యాప్ నుండి నిష్క్రమించడం కోసం నొక్కండి."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"టీథర్ చేయబడినది లేదా హాట్స్పాట్ సక్రియంగా ఉండేది"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"సెటప్ చేయడానికి నొక్కండి."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"టెథెరింగ్ నిలిపివేయబడింది"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"వివరాల కోసం మీ నిర్వాహకులను సంప్రదించండి"</string>
<string name="back_button_label" msgid="4078224038025043387">"వెనుకకు"</string>
<string name="next_button_label" msgid="6040209156399907780">"తర్వాత"</string>
<string name="skip_button_label" msgid="3566599811326688389">"దాటవేయి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 4dd0d0f..bc4b79e 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"ส่ง"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"แอปสำหรับการขับขี่ทำงานอยู่"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"แตะเพื่อออกจากแอปสำหรับการขับขี่"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"การปล่อยสัญญาณหรือฮอตสปอตทำงานอยู่"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"แตะเพื่อตั้งค่า"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด"</string>
<string name="back_button_label" msgid="4078224038025043387">"กลับ"</string>
<string name="next_button_label" msgid="6040209156399907780">"ถัดไป"</string>
<string name="skip_button_label" msgid="3566599811326688389">"ข้าม"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index bde4027..b24e95a 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Isumite"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Tumatakbo ang driving app"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Mag-tap para lumabas sa app sa pagmamaneho."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Pagsasama o aktibong hotspot"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"I-tap upang i-set up."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Naka-disable ang pag-tether"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Makipag-ugnayan sa iyong admin para sa mga detalye"</string>
<string name="back_button_label" msgid="4078224038025043387">"Bumalik"</string>
<string name="next_button_label" msgid="6040209156399907780">"Susunod"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Laktawan"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 0168ba0..326ace9 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Gönder"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Sürüş uygulaması çalışıyor"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Sürüş uygulamasından çıkmak için dokunun."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Tethering veya hotspot etkin"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Ayarlamak için dokunun."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Tethering devre dışı bırakıldı"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Ayrıntılı bilgi için yöneticinize başvurun"</string>
<string name="back_button_label" msgid="4078224038025043387">"Geri"</string>
<string name="next_button_label" msgid="6040209156399907780">"İleri"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Atla"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 32042ef..8007f9e 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1469,10 +1469,6 @@
<string name="submit" msgid="862795280643405865">"Надіслати"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Працює додаток для автомобілів"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Торкніться, щоб вийти з додатка для автомобілів."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Прив\'язка чи точка дост. активна"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Торкніться, щоб налаштувати."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Використання телефона в режимі модема вимкнено"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Щоб дізнатися більше, зв’яжіться з адміністратором"</string>
<string name="back_button_label" msgid="4078224038025043387">"Назад"</string>
<string name="next_button_label" msgid="6040209156399907780">"Далі"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Пропустити"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 1dd8911..312aed7d 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"جمع کرائیں"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ڈرائیونگ ایپ چل رہی ہے"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ڈرائیونگ ایپ سے باہر نکلنے کے لئے تھپتھپائيں۔"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"ٹیدرنگ یا ہاٹ اسپاٹ فعال"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"سیٹ اپ کرنے کیلئے تھپتھپائیں۔"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"ٹیدرنگ غیر فعال ہے"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"تفصیلات کے لئے اپنے منتظم سے رابطہ کریں"</string>
<string name="back_button_label" msgid="4078224038025043387">"واپس جائیں"</string>
<string name="next_button_label" msgid="6040209156399907780">"اگلا"</string>
<string name="skip_button_label" msgid="3566599811326688389">"نظر انداز کریں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 4b7847d..c7987d1 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Yuborish"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Avtomobil ilovasi ishlayapti"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Avtomobil ilovasidan chiqish uchun bosing"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Modem rejimi yoniq"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Sozlash uchun bosing."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Modem rejimi faolsizlantirildi"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Tafsilotlari uchun administratoringizga murojaat qiling"</string>
<string name="back_button_label" msgid="4078224038025043387">"Orqaga"</string>
<string name="next_button_label" msgid="6040209156399907780">"Keyingisi"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Tashlab o‘tish"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 971cf34..13c75f6 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Gửi"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Ứng dụng lái xe đang chạy"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Nhấn để thoát khỏi ứng dụng lái xe."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Chức năng điểm truy cập Internet hoặc điểm phát sóng đang hoạt động"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Nhấn để thiết lập."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Đã tắt tính năng chia sẻ kết nối"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Hãy liên hệ với quản trị viên của bạn để biết chi tiết"</string>
<string name="back_button_label" msgid="4078224038025043387">"Quay lại"</string>
<string name="next_button_label" msgid="6040209156399907780">"Tiếp theo"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Bỏ qua"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index d7dd8b1..1df2a40 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"提交"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"驾驶应用正在运行"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"点按即可退出驾驶应用。"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"网络共享或热点已启用"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"点按即可进行设置。"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"网络共享已停用"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"请与您的管理员联系以了解详情"</string>
<string name="back_button_label" msgid="4078224038025043387">"上一步"</string>
<string name="next_button_label" msgid="6040209156399907780">"下一步"</string>
<string name="skip_button_label" msgid="3566599811326688389">"跳过"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 1a37844..d4d1f7c 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"提交"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"駕駛應用程式執行中"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"輕按即可退出駕駛應用程式。"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"已啟用網絡共享或熱點"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"輕按即可設定。"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"網絡共享已停用"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"請聯絡您的管理員以瞭解詳情"</string>
<string name="back_button_label" msgid="4078224038025043387">"返回"</string>
<string name="next_button_label" msgid="6040209156399907780">"繼續"</string>
<string name="skip_button_label" msgid="3566599811326688389">"略過"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 5e655ac..9997b68 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"提交"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"行車應用程式執行中"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"輕觸即可結束行車應用程式。"</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"網路共用或無線基地台已啟用"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"輕觸即可進行設定。"</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"數據連線已停用"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"詳情請洽你的管理員"</string>
<string name="back_button_label" msgid="4078224038025043387">"返回"</string>
<string name="next_button_label" msgid="6040209156399907780">"繼續"</string>
<string name="skip_button_label" msgid="3566599811326688389">"略過"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 5f8d61e..5838a93 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1429,10 +1429,6 @@
<string name="submit" msgid="862795280643405865">"Hambisa"</string>
<string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Uhlelo lokusebenza lokushayela luyasebenza"</string>
<string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Thepha ukuze uphume kuhlelo lokusebenza lokushayela."</string>
- <string name="tethered_notification_title" msgid="2700523927485687353">"Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe"</string>
- <string name="tethered_notification_message" msgid="6228080755828019453">"Thepha ukuze usethe."</string>
- <string name="disable_tether_notification_title" msgid="7158047514545848391">"Ukusebenzisa ifoni njengemodemu kukhutshaziwe"</string>
- <string name="disable_tether_notification_message" msgid="98281313984014775">"Xhumana nomphathi wakho ukuze uthole imininingwane"</string>
<string name="back_button_label" msgid="4078224038025043387">"Emuva"</string>
<string name="next_button_label" msgid="6040209156399907780">"Okulandelayo"</string>
<string name="skip_button_label" msgid="3566599811326688389">"Yeqa"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6741fea..76d9561 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2363,9 +2363,11 @@
1 (0b001) - enforce (only install system packages if they are whitelisted)
2 (0b010) - log (log when a non-whitelisted package is run)
4 (0b100) - treat any package not mentioned in the whitelist file as implicitly whitelisted
+ 8 (0b1000) - ignore OTAs (don't install system packages during OTAs)
Note: This list must be kept current with PACKAGE_WHITELIST_MODE_PROP in
frameworks/base/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java -->
- <integer name="config_userTypePackageWhitelistMode">5</integer> <!-- 0b101 -->
+ <integer name="config_userTypePackageWhitelistMode">13</integer> <!-- 0b1101 -->
+ <!-- TODO(b/143200798): Change to value 5, i.e. 0b0101, when b/143200798 is resolved. -->
<!-- Whether UI for multi user should be shown -->
<bool name="config_enableMultiUserUI">false</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2d31f49..dcf7379 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3838,18 +3838,6 @@
<string name="car_mode_disable_notification_title">Driving app is running</string>
<string name="car_mode_disable_notification_message">Tap to exit driving app.</string>
- <!-- Strings for tethered notification -->
- <!-- Shown when the device is tethered -->
- <string name="tethered_notification_title">Tethering or hotspot active</string>
- <string name="tethered_notification_message">Tap to set up.</string>
-
- <!-- Strings for tether disabling notification -->
- <!-- This notification is shown when tethering has been disabled on a user's device.
- The device is managed by the user's employer. Tethering can't be turned on unless the
- IT administrator allows it. The noun "admin" is another reference for "IT administrator." -->
- <string name="disable_tether_notification_title">Tethering is disabled</string>
- <string name="disable_tether_notification_message">Contact your admin for details</string>
-
<!-- Strings for possible PreferenceActivity Back/Next buttons -->
<string name="back_button_label">Back</string>
<string name="next_button_label">Next</string>
@@ -5336,5 +5324,5 @@
<string name="accessibility_system_action_screenshot_label">Screenshot</string>
<!-- Accessibility description of caption view -->
- <string name="accessibility_freeform_caption"><xliff:g id="app_name">%1$s</xliff:g> app in Pop-up window.</string>
+ <string name="accessibility_freeform_caption">Caption bar of <xliff:g id="app_name">%1$s</xliff:g>.</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 130b31f..d15d4d6 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1893,9 +1893,6 @@
<java-symbol type="drawable" name="stat_sys_battery_charge" />
<java-symbol type="drawable" name="stat_sys_battery_unknown" />
<java-symbol type="drawable" name="stat_sys_data_usb" />
- <java-symbol type="drawable" name="stat_sys_tether_bluetooth" />
- <java-symbol type="drawable" name="stat_sys_tether_general" />
- <java-symbol type="drawable" name="stat_sys_tether_usb" />
<java-symbol type="drawable" name="stat_sys_throttled" />
<java-symbol type="drawable" name="vpn_connected" />
<java-symbol type="drawable" name="vpn_disconnected" />
@@ -2071,10 +2068,6 @@
<java-symbol type="string" name="select_keyboard_layout_notification_message" />
<java-symbol type="string" name="smv_application" />
<java-symbol type="string" name="smv_process" />
- <java-symbol type="string" name="tethered_notification_message" />
- <java-symbol type="string" name="tethered_notification_title" />
- <java-symbol type="string" name="disable_tether_notification_message" />
- <java-symbol type="string" name="disable_tether_notification_title" />
<java-symbol type="string" name="adb_debugging_notification_channel_tv" />
<java-symbol type="string" name="usb_accessory_notification_title" />
<java-symbol type="string" name="usb_mtp_notification_title" />
diff --git a/media/java/android/media/IMediaRoute2ProviderClient.aidl b/media/java/android/media/IMediaRoute2ProviderClient.aidl
index 6f44d45..f4fb7f4 100644
--- a/media/java/android/media/IMediaRoute2ProviderClient.aidl
+++ b/media/java/android/media/IMediaRoute2ProviderClient.aidl
@@ -17,10 +17,13 @@
package android.media;
import android.media.MediaRoute2ProviderInfo;
+import android.media.MediaRoute2Info;
+import android.os.Bundle;
/**
* @hide
*/
oneway interface IMediaRoute2ProviderClient {
void updateProviderInfo(in MediaRoute2ProviderInfo info);
+ void notifyRouteSelected(String packageName, String routeId, in Bundle controlHints, int seq);
}
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 386d2dc..1b6183e 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -18,14 +18,19 @@
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Service;
import android.content.Intent;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
+import java.util.Objects;
+
/**
* @hide
*/
@@ -44,7 +49,7 @@
}
@Override
- public IBinder onBind(Intent intent) {
+ public IBinder onBind(@NonNull Intent intent) {
//TODO: Allow binding from media router service only?
if (SERVICE_INTERFACE.equals(intent.getAction())) {
if (mStub == null) {
@@ -57,11 +62,17 @@
/**
* Called when selectRoute is called on a route of the provider.
+ * Once the route is ready to be used , call {@link #notifyRouteSelected(SelectToken, Bundle)}
+ * to notify that.
*
* @param packageName the package name of the application that selected the route
* @param routeId the id of the route being selected
+ * @param token token that contains select info
+ *
+ * @see #notifyRouteSelected
*/
- public abstract void onSelectRoute(String packageName, String routeId);
+ public abstract void onSelectRoute(@NonNull String packageName, @NonNull String routeId,
+ @NonNull SelectToken token);
/**
* Called when unselectRoute is called on a route of the provider.
@@ -69,7 +80,7 @@
* @param packageName the package name of the application that has selected the route.
* @param routeId the id of the route being unselected
*/
- public abstract void onUnselectRoute(String packageName, String routeId);
+ public abstract void onUnselectRoute(@NonNull String packageName, @NonNull String routeId);
/**
* Called when sendControlRequest is called on a route of the provider
@@ -78,21 +89,21 @@
* @param request the media control request intent
*/
//TODO: Discuss what to use for request (e.g., Intent? Request class?)
- public abstract void onControlRequest(String routeId, Intent request);
+ public abstract void onControlRequest(@NonNull String routeId, @NonNull Intent request);
/**
* Called when requestSetVolume is called on a route of the provider
* @param routeId the id of the route
* @param volume the target volume
*/
- public abstract void onSetVolume(String routeId, int volume);
+ public abstract void onSetVolume(@NonNull String routeId, int volume);
/**
* Called when requestUpdateVolume is called on a route of the provider
* @param routeId id of the route
* @param delta the delta to add to the current volume
*/
- public abstract void onUpdateVolume(String routeId, int delta);
+ public abstract void onUpdateVolume(@NonNull String routeId, int delta);
/**
* Updates provider info and publishes routes
@@ -102,6 +113,29 @@
publishState();
}
+ /**
+ * Notifies the client of that the selected route is ready for use. If the selected route can be
+ * controlled, pass a {@link Bundle} that contains how to control it.
+ *
+ * @param token token passed in {@link #onSelectRoute}
+ * @param controlHints a {@link Bundle} that contains how to control the given route.
+ * Pass {@code null} if the route is not available.
+ */
+ public final void notifyRouteSelected(@NonNull SelectToken token,
+ @Nullable Bundle controlHints) {
+ Objects.requireNonNull(token, "token must not be null");
+
+ if (mClient == null) {
+ return;
+ }
+ try {
+ mClient.notifyRouteSelected(token.mPackageName, token.mRouteId,
+ controlHints, token.mSeq);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Failed to notify route selected");
+ }
+ }
+
void setClient(IMediaRoute2ProviderClient client) {
mClient = client;
publishState();
@@ -118,6 +152,23 @@
}
}
+ /**
+ * Route selection information.
+ *
+ * @see #notifyRouteSelected
+ */
+ public final class SelectToken {
+ final String mPackageName;
+ final String mRouteId;
+ final int mSeq;
+
+ SelectToken(String packageName, String routeId, int seq) {
+ mPackageName = packageName;
+ mRouteId = routeId;
+ mSeq = seq;
+ }
+ }
+
final class ProviderStub extends IMediaRoute2Provider.Stub {
ProviderStub() { }
@@ -129,10 +180,10 @@
@Override
public void requestSelectRoute(String packageName, String id, int seq) {
- // TODO: When introducing MediaRoute2ProviderService#sendConnectionHints(),
- // use the sequence number here properly.
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelectRoute,
- MediaRoute2ProviderService.this, packageName, id));
+ MediaRoute2ProviderService.this, packageName, id,
+ new SelectToken(packageName, id, seq)));
+
}
@Override
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 9cb7869..7b15d95 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -1318,6 +1318,7 @@
sStatic.rebindAsUser(userId);
}
+ //TODO: remove this and Client1Record in MediaRouter2ServiceImpl.
/**
* Sets the control categories of the application.
* Routes that support at least one of the given control categories only exists and are handled
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 94ac77a..35cb066 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -57,7 +57,8 @@
@IntDef(value = {
SELECT_REASON_UNKNOWN,
SELECT_REASON_USER_SELECTED,
- SELECT_REASON_FALLBACK})
+ SELECT_REASON_FALLBACK,
+ SELECT_REASON_SYSTEM_SELECTED})
public @interface SelectReason {}
/**
@@ -80,6 +81,13 @@
*/
public static final int SELECT_REASON_FALLBACK = 2;
+ /**
+ * This is passed from {@link com.android.server.media.MediaRouterService} when the route
+ * is selected in response to a request from other apps (e.g. System UI).
+ * @hide
+ */
+ public static final int SELECT_REASON_SYSTEM_SELECTED = 3;
+
private static final String TAG = "MR2";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final Object sLock = new Object();
@@ -485,6 +493,9 @@
}
mSelectingRoute = null;
}
+ if (reason == SELECT_REASON_SYSTEM_SELECTED) {
+ reason = SELECT_REASON_USER_SELECTED;
+ }
mSelectedRoute = route;
notifyRouteSelected(route, reason, controlHints);
}
diff --git a/media/jni/android_media_MediaDataSource.h b/media/jni/android_media_MediaDataSource.h
index 378baf4..b65039d3 100644
--- a/media/jni/android_media_MediaDataSource.h
+++ b/media/jni/android_media_MediaDataSource.h
@@ -19,7 +19,7 @@
#include "jni.h"
-#include <media/IDataSource.h>
+#include <android/IDataSource.h>
#include <media/stagefright/foundation/ABase.h>
#include <utils/Errors.h>
#include <utils/Mutex.h>
diff --git a/media/jni/android_media_Streams.cpp b/media/jni/android_media_Streams.cpp
index b7cbd97..4fd5153 100644
--- a/media/jni/android_media_Streams.cpp
+++ b/media/jni/android_media_Streams.cpp
@@ -28,67 +28,6 @@
namespace android {
-AssetStream::AssetStream(SkStream* stream)
- : mStream(stream), mPosition(0) {
-}
-
-AssetStream::~AssetStream() {
-}
-
-piex::Error AssetStream::GetData(
- const size_t offset, const size_t length, std::uint8_t* data) {
- // Seek first.
- if (mPosition != offset) {
- if (!mStream->seek(offset)) {
- return piex::Error::kFail;
- }
- }
-
- // Read bytes.
- size_t size = mStream->read((void*)data, length);
- mPosition = offset + size;
-
- return size == length ? piex::Error::kOk : piex::Error::kFail;
-}
-
-BufferedStream::BufferedStream(SkStream* stream)
- : mStream(stream) {
-}
-
-BufferedStream::~BufferedStream() {
-}
-
-piex::Error BufferedStream::GetData(
- const size_t offset, const size_t length, std::uint8_t* data) {
- // Seek first.
- if (offset + length > mStreamBuffer.bytesWritten()) {
- size_t sizeToRead = offset + length - mStreamBuffer.bytesWritten();
- if (sizeToRead <= kMinSizeToRead) {
- sizeToRead = kMinSizeToRead;
- }
-
- void* tempBuffer = malloc(sizeToRead);
- if (tempBuffer == NULL) {
- return piex::Error::kFail;
- }
-
- size_t bytesRead = mStream->read(tempBuffer, sizeToRead);
- if (bytesRead != sizeToRead) {
- free(tempBuffer);
- return piex::Error::kFail;
- }
- mStreamBuffer.write(tempBuffer, bytesRead);
- free(tempBuffer);
- }
-
- // Read bytes.
- if (mStreamBuffer.read((void*)data, offset, length)) {
- return piex::Error::kOk;
- } else {
- return piex::Error::kFail;
- }
-}
-
FileStream::FileStream(const int fd)
: mPosition(0) {
mFile = fdopen(fd, "r");
diff --git a/media/jni/android_media_Streams.h b/media/jni/android_media_Streams.h
index d174f9a..800591c 100644
--- a/media/jni/android_media_Streams.h
+++ b/media/jni/android_media_Streams.h
@@ -25,53 +25,9 @@
#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/StrongPointer.h>
-#include <SkStream.h>
-
namespace android {
-class AssetStream : public piex::StreamInterface {
-private:
- SkStream *mStream;
- size_t mPosition;
-
-public:
- explicit AssetStream(SkStream* stream);
- ~AssetStream();
-
- // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
- // provided by the caller, guaranteed to be at least "length" bytes long.
- // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
- // 'offset' bytes from the start of the stream.
- // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
- // change the contents of 'data'.
- piex::Error GetData(
- const size_t offset, const size_t length, std::uint8_t* data) override;
-};
-
-class BufferedStream : public piex::StreamInterface {
-private:
- SkStream *mStream;
- // Growable memory stream
- SkDynamicMemoryWStream mStreamBuffer;
-
- // Minimum size to read on filling the buffer.
- const size_t kMinSizeToRead = 8192;
-
-public:
- explicit BufferedStream(SkStream* stream);
- ~BufferedStream();
-
- // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
- // provided by the caller, guaranteed to be at least "length" bytes long.
- // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
- // 'offset' bytes from the start of the stream.
- // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
- // change the contents of 'data'.
- piex::Error GetData(
- const size_t offset, const size_t length, std::uint8_t* data) override;
-};
-
class FileStream : public piex::StreamInterface {
private:
FILE *mFile;
diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
index f4f8d0b..6650f96 100644
--- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
@@ -20,6 +20,7 @@
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
import android.media.MediaRoute2ProviderService;
+import android.os.Bundle;
import android.os.IBinder;
import java.util.HashMap;
@@ -95,7 +96,7 @@
}
@Override
- public void onSelectRoute(String packageName, String routeId) {
+ public void onSelectRoute(String packageName, String routeId, SelectToken token) {
MediaRoute2Info route = mRoutes.get(routeId);
if (route == null) {
return;
@@ -104,6 +105,7 @@
.setClientPackageName(packageName)
.build());
publishRoutes();
+ notifyRouteSelected(token, Bundle.EMPTY);
}
@Override
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index d0f7c78..c70ad8d 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -23,23 +23,19 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.Intent;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2;
import android.media.MediaRouter2Manager;
+import android.os.Bundle;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.TextUtils;
-import org.junit.Assert;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -95,9 +91,14 @@
private Executor mExecutor;
private String mPackageName;
+ private final List<MediaRouter2Manager.Callback> mManagerCallbacks = new ArrayList<>();
+ private final List<MediaRouter2.Callback> mRouterCallbacks = new ArrayList<>();
+ private Map<String, MediaRoute2Info> mRoutes;
+
private static final List<String> CATEGORIES_ALL = new ArrayList();
private static final List<String> CATEGORIES_SPECIAL = new ArrayList();
private static final List<String> CATEGORIES_LIVE_AUDIO = new ArrayList<>();
+
static {
CATEGORIES_ALL.add(CATEGORY_SAMPLE);
CATEGORIES_ALL.add(CATEGORY_SPECIAL);
@@ -108,6 +109,7 @@
CATEGORIES_LIVE_AUDIO.add(CATEGORY_LIVE_AUDIO);
}
+
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
@@ -116,6 +118,16 @@
//TODO: If we need to support thread pool executors, change this to thread pool executor.
mExecutor = Executors.newSingleThreadExecutor();
mPackageName = mContext.getPackageName();
+
+ // ensure media router 2 client
+ addRouterCallback(new MediaRouter2.Callback());
+ mRoutes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ }
+
+ @After
+ public void tearDown() {
+ // unregister callbacks
+ clearCallbacks();
}
//TODO: Move to a separate file
@@ -132,10 +144,13 @@
assertNotEquals(routeInfo1, routeInfo3);
}
+ /**
+ * Tests if routes are added correctly when a new callback is registered.
+ */
@Test
public void testOnRoutesAdded() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
- MediaRouter2Manager.Callback callback = new MediaRouter2Manager.Callback() {
+ addManagerCallback(new MediaRouter2Manager.Callback() {
@Override
public void onRoutesAdded(List<MediaRoute2Info> routes) {
assertTrue(routes.size() > 0);
@@ -145,27 +160,15 @@
}
}
}
- };
- mManager.registerCallback(mExecutor, callback);
+ });
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
- mManager.unregisterCallback(callback);
}
@Test
public void testOnRoutesRemoved() throws Exception {
- MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
- mManager.registerCallback(mExecutor, mockCallback);
-
- MediaRouter2.Callback routerCallback = new MediaRouter2.Callback();
- mRouter2.registerCallback(mExecutor, routerCallback);
-
- Map<String, MediaRoute2Info> routes =
- waitAndGetRoutesWithManager(CATEGORIES_ALL);
-
CountDownLatch latch = new CountDownLatch(1);
- MediaRouter2Manager.Callback callback = new MediaRouter2Manager.Callback() {
+ addManagerCallback(new MediaRouter2Manager.Callback() {
@Override
public void onRoutesRemoved(List<MediaRoute2Info> routes) {
assertTrue(routes.size() > 0);
@@ -175,16 +178,12 @@
}
}
}
- };
- mManager.registerCallback(mExecutor, callback);
+ });
//TODO: Figure out a more proper way to test.
// (Control requests shouldn't be used in this way.)
- mRouter2.sendControlRequest(routes.get(ROUTE_ID2), new Intent(ACTION_REMOVE_ROUTE));
+ mRouter2.sendControlRequest(mRoutes.get(ROUTE_ID2), new Intent(ACTION_REMOVE_ROUTE));
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
- mRouter2.unregisterCallback(routerCallback);
- mManager.unregisterCallback(mockCallback);
}
/**
@@ -192,16 +191,10 @@
*/
@Test
public void testControlCategory() throws Exception {
- MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
- mManager.registerCallback(mExecutor, mockCallback);
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_SPECIAL);
- Map<String, MediaRoute2Info> routes =
- waitAndGetRoutesWithManager(CATEGORIES_SPECIAL);
-
- Assert.assertEquals(1, routes.size());
- Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
-
- mManager.unregisterCallback(mockCallback);
+ assertEquals(1, routes.size());
+ assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
}
/**
@@ -209,37 +202,60 @@
*/
@Test
public void testGetRoutes() throws Exception {
- MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
- mRouter2.registerCallback(mExecutor, mockCallback);
-
Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_SPECIAL);
- Assert.assertEquals(1, routes.size());
- Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
-
- mRouter2.unregisterCallback(mockCallback);
+ assertEquals(1, routes.size());
+ assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
}
+ /**
+ * Tests if MR2.Callback.onRouteSelected is called when a route is selected from MR2Manager.
+ */
@Test
- public void testOnRouteSelected() throws Exception {
- MediaRouter2.Callback routerCallback = new MediaRouter2.Callback();
- MediaRouter2Manager.Callback managerCallback = mock(MediaRouter2Manager.Callback.class);
+ public void testRouterOnRouteSelected() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
- mManager.registerCallback(mExecutor, managerCallback);
- mRouter2.registerCallback(mExecutor, routerCallback);
+ addRouterCallback(new MediaRouter2.Callback() {
+ @Override
+ public void onRouteSelected(MediaRoute2Info route, int reason, Bundle controlHints) {
+ if (route != null && TextUtils.equals(route.getId(), ROUTE_ID1)) {
+ latch.countDown();
+ }
+ }
+ });
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
-
- MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1);
+ MediaRoute2Info routeToSelect = mRoutes.get(ROUTE_ID1);
assertNotNull(routeToSelect);
mManager.selectRoute(mPackageName, routeToSelect);
- verify(managerCallback, timeout(TIMEOUT_MS))
- .onRouteSelected(eq(mPackageName),
- argThat(route -> route != null && route.equals(routeToSelect)));
- mRouter2.unregisterCallback(routerCallback);
- mManager.unregisterCallback(managerCallback);
+ assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ }
+
+ /**
+ * Tests if MR2Manager.Callback.onRouteSelected is called
+ * when a route is selected by MR2Manager.
+ */
+ @Test
+ public void testManagerOnRouteSelected() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+
+ addManagerCallback(new MediaRouter2Manager.Callback() {
+ @Override
+ public void onRouteSelected(String packageName, MediaRoute2Info route) {
+ if (TextUtils.equals(mPackageName, packageName)
+ && route != null && TextUtils.equals(route.getId(), ROUTE_ID1)) {
+ latch.countDown();
+ }
+ }
+ });
+
+ MediaRoute2Info routeToSelect = mRoutes.get(ROUTE_ID1);
+ assertNotNull(routeToSelect);
+
+ mManager.selectRoute(mPackageName, routeToSelect);
+
+ assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
}
/**
@@ -247,19 +263,13 @@
*/
@Test
public void testSingleProviderSelect() throws Exception {
- MediaRouter2.Callback routerCallback = mock(MediaRouter2.Callback.class);
-
- mRouter2.registerCallback(mExecutor, routerCallback);
-
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
-
awaitOnRouteChangedManager(
- () -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1)),
+ () -> mManager.selectRoute(mPackageName, mRoutes.get(ROUTE_ID1)),
ROUTE_ID1,
route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
awaitOnRouteChangedManager(
- () -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID2)),
+ () -> mManager.selectRoute(mPackageName, mRoutes.get(ROUTE_ID2)),
ROUTE_ID2,
route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
@@ -267,8 +277,6 @@
() -> mManager.unselectRoute(mPackageName),
ROUTE_ID2,
route -> TextUtils.equals(route.getClientPackageName(), null));
-
- mRouter2.unregisterCallback(routerCallback);
}
@Test
@@ -292,12 +300,7 @@
@Test
public void testControlVolumeWithManager() throws Exception {
- MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
-
- mRouter2.registerCallback(mExecutor, mockCallback);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
-
- MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
+ MediaRoute2Info volRoute = mRoutes.get(ROUTE_ID_VARIABLE_VOLUME);
int originalVolume = volRoute.getVolume();
int deltaVolume = (originalVolume == volRoute.getVolumeMax() ? -1 : 1);
@@ -310,24 +313,16 @@
() -> mManager.requestSetVolume(volRoute, originalVolume),
ROUTE_ID_VARIABLE_VOLUME,
(route -> route.getVolume() == originalVolume));
-
- mRouter2.unregisterCallback(mockCallback);
}
@Test
public void testVolumeHandling() throws Exception {
- MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
- mRouter2.registerCallback(mExecutor, mockCallback);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_ALL);
-
- MediaRoute2Info fixedVolumeRoute = routes.get(ROUTE_ID_FIXED_VOLUME);
- MediaRoute2Info variableVolumeRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
+ MediaRoute2Info fixedVolumeRoute = mRoutes.get(ROUTE_ID_FIXED_VOLUME);
+ MediaRoute2Info variableVolumeRoute = mRoutes.get(ROUTE_ID_VARIABLE_VOLUME);
assertEquals(PLAYBACK_VOLUME_FIXED, fixedVolumeRoute.getVolumeHandling());
assertEquals(PLAYBACK_VOLUME_VARIABLE, variableVolumeRoute.getVolumeHandling());
assertEquals(VOLUME_MAX, variableVolumeRoute.getVolumeMax());
-
- mRouter2.unregisterCallback(mockCallback);
}
@Test
@@ -368,6 +363,7 @@
latch.countDown();
}
}
+
@Override
public void onControlCategoriesChanged(String packageName) {
if (TextUtils.equals(mPackageName, packageName)) {
@@ -401,7 +397,7 @@
};
mRouter2.registerCallback(mExecutor, callback);
try {
- new Thread(task).start();
+ task.run();
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
} finally {
mRouter2.unregisterCallback(callback);
@@ -422,7 +418,7 @@
};
mManager.registerCallback(mExecutor, callback);
try {
- new Thread(task).start();
+ task.run();
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
} finally {
mManager.unregisterCallback(callback);
@@ -433,9 +429,31 @@
static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
Map<String, MediaRoute2Info> routeMap = new HashMap<>();
for (MediaRoute2Info route : routes) {
- // intentionally not route.getUniqueId() for convenience.
+ // intentionally not using route.getUniqueId() for convenience.
routeMap.put(route.getId(), route);
}
return routeMap;
}
+
+ private void addManagerCallback(MediaRouter2Manager.Callback callback) {
+ mManagerCallbacks.add(callback);
+ mManager.registerCallback(mExecutor, callback);
+ }
+
+ private void addRouterCallback(MediaRouter2.Callback callback) {
+ mRouterCallbacks.add(callback);
+ mRouter2.registerCallback(mExecutor, callback);
+ }
+
+ private void clearCallbacks() {
+ for (MediaRouter2Manager.Callback callback : mManagerCallbacks) {
+ mManager.unregisterCallback(callback);
+ }
+ mManagerCallbacks.clear();
+
+ for (MediaRouter2.Callback callback : mRouterCallbacks) {
+ mRouter2.unregisterCallback(callback);
+ }
+ mRouterCallbacks.clear();
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
index 1c62879..0a1a122 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
@@ -76,6 +76,19 @@
}
/**
+ * Logs the elapsed time from onAttach to calling {@link #writeElapsedTimeMetric(int, String)}.
+ * @param action : The value of the Action Enums.
+ * @param key : The value of special key string.
+ */
+ public void writeElapsedTimeMetric(int action, String key) {
+ if (mMetricsFeature == null || mMetricsCategory == METRICS_CATEGORY_UNKNOWN) {
+ return;
+ }
+ final int elapse = (int) (SystemClock.elapsedRealtime() - mTimestamp);
+ mMetricsFeature.action(METRICS_CATEGORY_UNKNOWN, action, mMetricsCategory, key, elapse);
+ }
+
+ /**
* Sets source metrics category for this logger. Source is the caller that opened this UI.
*/
public void setSourceMetricsCategory(Activity activity) {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 7d06e6c..7b1c382 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -120,7 +120,7 @@
private OsuProvider createOsuProvider() {
Map<String, String> friendlyNames = new HashMap<>();
friendlyNames.put("en", OSU_FRIENDLY_NAME);
- return new OsuProvider((WifiSsid) null, friendlyNames, null, null, null, null, null);
+ return new OsuProvider((WifiSsid) null, friendlyNames, null, null, null, null);
}
@Before
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 94fbc54..81cf118 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -336,7 +336,7 @@
private static OsuProvider buildOsuProvider(String friendlyName) {
Map<String, String> friendlyNames = new HashMap<>();
friendlyNames.put("en", friendlyName);
- return new OsuProvider((WifiSsid) null, friendlyNames, null, null, null, null, null);
+ return new OsuProvider((WifiSsid) null, friendlyNames, null, null, null, null);
}
private WifiTracker createTrackerWithImmediateBroadcastsAndInjectInitialScanResults(
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/AccessibilityShortcutTargetListValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/AccessibilityShortcutTargetListValidator.java
new file mode 100644
index 0000000..5f3d7f1
--- /dev/null
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/AccessibilityShortcutTargetListValidator.java
@@ -0,0 +1,46 @@
+/*
+ * 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.provider.settings.validators;
+
+import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR;
+
+import android.text.TextUtils;
+
+/**
+ * Ensure a restored value is a string in the format the accessibility shortcut system handles
+ *
+ * @hide
+ */
+public final class AccessibilityShortcutTargetListValidator extends ListValidator {
+ public AccessibilityShortcutTargetListValidator() {
+ super(":");
+ }
+
+ @Override
+ protected boolean isEntryValid(String entry) {
+ return !TextUtils.isEmpty(entry);
+ }
+
+ @Override
+ protected boolean isItemValid(String item) {
+ if (TextUtils.isEmpty(item)) {
+ return false;
+ }
+ return (COMPONENT_NAME_VALIDATOR.validate(item) || PACKAGE_NAME_VALIDATOR.validate(item));
+ }
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/ListValidator.java b/packages/SettingsProvider/src/android/provider/settings/validators/ListValidator.java
index a6001d2..104fa11 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/ListValidator.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/ListValidator.java
@@ -35,7 +35,7 @@
if (!isEntryValid(value)) {
return false;
}
- String[] items = value.split(",");
+ String[] items = value.split(mListSplitRegex);
for (String item : items) {
if (!isItemValid(item)) {
return false;
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 9460d27f..090af98 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -16,6 +16,7 @@
package android.provider.settings.validators;
+import static android.provider.settings.validators.SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.COLON_SEPARATED_COMPONENT_LIST_VALIDATOR;
@@ -71,10 +72,13 @@
VALIDATORS.put(Secure.TOUCH_EXPLORATION_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(
- Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, NULLABLE_COMPONENT_NAME_VALIDATOR);
+ Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+ ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
// technically either ComponentName or class name, but there's proper value
// validation at callsites, so allow any non-null string
- VALIDATORS.put(Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, value -> value != null);
+ VALIDATORS.put(
+ Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
+ ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
index 224042c..71c7544 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
@@ -204,4 +204,7 @@
new InclusiveIntegerRangeValidator(0, 100);
static final Validator VIBRATION_INTENSITY_VALIDATOR = new InclusiveIntegerRangeValidator(0, 3);
+
+ static final Validator ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR =
+ new AccessibilityShortcutTargetListValidator();
}
diff --git a/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java b/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
index a3b0835..bb9e6f6 100644
--- a/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
@@ -297,6 +297,18 @@
}
@Test
+ public void testAccessibilityShortcutTargetValidator() {
+ assertTrue(SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR.validate(
+ "com.google.android/.AccessibilityShortcutTarget"));
+ assertTrue(SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR.validate(
+ "com.google.android"));
+ assertTrue(SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR.validate(
+ "com.google.android/.AccessibilityShortcutTarget:com.google.android"));
+ assertFalse(SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR.validate(
+ "com.google.android/.AccessibilityShortcutTarget:com.google.@android"));
+ }
+
+ @Test
public void ensureAllBackedUpGlobalSettingsHaveValidators() {
String offenders = getOffenders(concat(GlobalSettings.SETTINGS_TO_BACKUP,
Settings.Global.LEGACY_RESTORE_SETTINGS), GlobalSettingsValidators.VALIDATORS);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 2068f7c..dfd9941 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -40,6 +40,7 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -125,6 +126,7 @@
assertTrue(mHeadsUpManager.canRemoveImmediately(mEntry.getKey()));
}
+ @Ignore("b/141538055")
@Test
public void testCanRemoveImmediately_notTopEntry() {
NotificationEntry laterEntry = new NotificationEntryBuilder()
diff --git a/packages/Tethering/apex/Android.bp b/packages/Tethering/apex/Android.bp
new file mode 100644
index 0000000..bca01ebd
--- /dev/null
+++ b/packages/Tethering/apex/Android.bp
@@ -0,0 +1,35 @@
+//
+// 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.
+//
+
+apex {
+ name: "com.android.tethering.apex",
+ apps: ["Tethering"],
+ manifest: "manifest.json",
+ key: "com.android.tethering.apex.key",
+
+ androidManifest: "AndroidManifest.xml",
+}
+
+apex_key {
+ name: "com.android.tethering.apex.key",
+ public_key: "com.android.tethering.apex.avbpubkey",
+ private_key: "com.android.tethering.apex.pem",
+}
+
+android_app_certificate {
+ name: "com.android.tethering.apex.certificate",
+ certificate: "com.android.tethering.apex",
+}
diff --git a/packages/Tethering/apex/AndroidManifest.xml b/packages/Tethering/apex/AndroidManifest.xml
new file mode 100644
index 0000000..7769b79
--- /dev/null
+++ b/packages/Tethering/apex/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?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.tethering.apex">
+ <!-- APEX does not have classes.dex -->
+ <application android:hasCode="false" />
+ <!-- b/145383354: Current minSdk is locked to Q for development cycle, lock it to next version
+ before ship. -->
+ <uses-sdk
+ android:minSdkVersion="29"
+ android:targetSdkVersion="29"
+ />
+</manifest>
diff --git a/packages/Tethering/apex/com.android.tethering.apex.avbpubkey b/packages/Tethering/apex/com.android.tethering.apex.avbpubkey
new file mode 100644
index 0000000..9c87111
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.apex.avbpubkey
Binary files differ
diff --git a/packages/Tethering/apex/com.android.tethering.apex.pem b/packages/Tethering/apex/com.android.tethering.apex.pem
new file mode 100644
index 0000000..a8cd12e
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.apex.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAwloHpMmwszNBEgUVion141BTvF/oJ5g5DlQIYBtmht4tSpc3
+6elWXd+dhMzFxf/RkxSNRsU+dhD11cPKGp9nUYQQGrHEf3xEKwAHJKRMq26TkJ3o
+1TwOO70TaRKKA4ThNiM3VFDX2vy1ijArhZDIBTGVJCUl9HOHiO+ZJG5DKCx3KXbO
+QWz3c+Lbprr1L76dwIsl5kuoAFwgG0J+9BZhHEzIG1lVpGG7RRLxc8eDIxNN/oKT
+gPYBcOxFYqOECKGBBvElf6MxdRv6xG7gooALY2/HDMYUjAJSOosfwzeymugCzMhK
+e+6CSTAaEfUzuVZvMc2qnd1ly7zpLo9x+TOdH5LEVZpSwqmu2n5bqrUnSEAJUvMz
+SSw0YbsLWJZuTiTV7lecSITgqsmwuZyDexDmUkDQChzrTixsQV6S8vsh/FanjWoi
+zBlPneX8Q7/LME3hxHyLbrabxX0zWiyj8iM9h/8Y4mpO/MjEmmavglTAP4J8zrKD
+FBsntCoch9I49IpYBuO6NfKw1h7AUpLf8gARAjFjRxiJVcSgGY/Wt4/pBzJ57T5g
+xPvqxfpPQP0OA2CT8LqqzZIR8jXs8/TquvwLkkY2kRRPXx+azd5oU2A0uonrUY31
+Bc1obfmWPuEMz9bO/i06ETHuWPd4RiUNaB8qEmjYuKJfhv72YNcRwhrAYJECAwEA
+AQKCAgAaQn3b5yCH5fn5zFQPxvpBP35A6ph8mRXEeNg03B7rRCPMe0gjw9JWlrs6
+0Uw7p4gSnmlEUaxR2ZLN0kmBdV5JZlWitbg+HXU8diGA8u4lD6jCloN6JEYsDi0M
+OmQJe6/OV83HB7FStmh1BnMq9dgA06U6IAbT07RRbUY85OUQDYoAQTw3HNkGgHV7
+PrGYROIdvO9fAYPuoIP6Cu8KXee7Iii7gUOQFWBvQdL7+M4gNCCKrevuNc8WCeaK
+IFvbqq67WGPfrhYlo6UrW2vgqPpg8h5r/GuUS0/+9wNQpjrssUKHltxxiFV0PBqZ
+qI7XkPUvPoG6GMsDT0AWeW1F5ZJqEGPN67Xek0BCD0cpUli+nHD0yWGVHtkpHU2D
+qUOZdB2COfBuXRdW1LsYNPg8YjTCPsmGhISLTwiTNcZJeTxoK1y0CcVW9d7Af2aD
+lYzCegscQlXkSZiFj9s90Vd3KdD2XKrH/ADxzsOxQJ89ka004efdQa5/MKs9aChG
+/5XrwBEfN4O92OjY7KqXUAwB7CcVzNymOjD6r07LM24zbkRpwwXlkP0wmjsHBXkh
+8p0ISmY9QRdvhBgYmFmoPWZncM0zym9LI8atBs4CijQ7JjuOQ8HgHg+Se2eppWfe
+t8r6TVkDB8JeNAMxjX9q0G7icf3JjlIrgERZfyXLmpduR9NdkQKCAQEA5rp2fSKh
+RwihHNtJhNktFJuLR9OA++vyfjqhWnB8CrLPo3//LGWW/+WBr8EwXi/76hQpeKlf
+u8SmkTtxIHlTP2Brh2koh1Qf8HKzPHGjZeDFOoVPKHPqe3nV+cv3srd1mS0Eq3BA
+ZFQq+l61f2iiTZKxDroCahNEa8VMzirW6nKb5xhyMPHXgncCUdphHbwAGatas6be
+RUFg4ChH8BwX6jYw7leRUy2K6OqEl0fckT4Laitlb/ezKtwmD4PPE95q5hH0v3SO
+wetHWafiNrOXPn2wQqBrI2y+AfbTjNmQiaIPgcFKAQ7V3n+c3XfGZ9Xfv4L8m/wo
+RZ4ika1zur021QKCAQEA16OUBPA7BnWd+RJFri2kJBG5JZElaV9chO2ZHcXUbFR9
+HIPkWN19bJbki8Ca0w8FUQuS/M7JeeFjoZ194NlczbR899GVmb0X2AUKXilMacs3
+IONxIDczx3KFtsge8ewXRAjQvgE7M3NpmmJfPLPog7spMCbUIxbc3jzjiZgB/J1s
+WytlUTUY/Zy4V1wujkoydgK2KcHcEWG2oIy7EP0RwnL1NhTksXOtBH6+MoRMAT+H
+fcBK6yfJBNBRQzJ0PdkCCLdQPN1VtwRlWjPXZ3ey4fWvZ399wSLUkM2V1jB4GcOZ
++DAgtwFKs9+HfOdV42GgFWFcjP+bkM3bcdrQFnmYzQKCAQAQnf1KpePXqddwrJpu
+5vVINquhUKpJeoTMcoyMZu2IF7i8nctS9z4Yz/63GcLSBcKu6STTe99ZNqCIdS+A
+lzxXpCoaZoh0tqpWNuyRvd12yOlrfY5l63NH0U6H3xjH1k6x6XwcnMkGcMlnnsqT
+koWd8KKv3NWvrhOPb3ZIou03lWmFC02uGLzcuJWCL6gu7AtVzfGKXspDUqIXgs8r
+i9ptE9oSUFw3EWCfxcQm4RYRn9ZSny1/EufkflZ/Z47Sb4Jjb4ehAlQFw1wwKNcx
++V07MvIu2j7dHkfQ/GXgDwtJ3lIfljwuN1NP4wD5Mlcnw0+KC3UGBvMfkHQM6eEb
+4eTBAoIBAQDWfZsqHlpX3n431XkB+9wdFJP5ThrMaVJ51mxLNRBKgO/BgV+NFSNA
+9AZ5DCf0cCh1qPGYDYhSd2LGywT+trac1j7Hse0AcxpYgQsDBkk/oic/y3wm80HJ
+zZw7Z2uAb7nkrnATzt24G8CbE+ZvVvScs3oQr06raH5hgGdD4bN4No4lUVECKbKl
+8VFbdBHK7vqqb6AKgQ4JLAygPduE1nTn2bkXBklESS98HSXK0dVYGH0JFFBw/63v
+39Y05ObC7iwbx1tEb1RnKzQ1OQO1o1aHc/35ENNhXOfa8ONtneCYn/ty50xjPCG2
+MU1vbBv+hIjbO3D3vvhaXKk+4svAz0qxAoIBAQC84FJEjKHJHx17jLeoTuDfuxwX
+6bOQrI3nHbtnFRvPrMryWRDtHLv89Zma3o68/n4vTn5+AnvgYMZifOYlTlIPxinH
+tlE+qCD8KBXUlZdrc+5GGM18lp5tF3Ro4LireH+OhiOAWawaSzDIDYdiR6Kz9NU+
+SjcHKjDObeM6iMEukoaRsufMedpUSrnbzMraAJgBZGay1NZs/o8Icl3OySYPZWEK
+MJxVBMXU9QcUp2GEioYd/eNuP9rwyjq/EIUDJbP2vESAe6+FdGbIgvyYTV/gnKaH
+GcvyMNVZbCMp/wCYNonjlu+18m2w+pVs2uuZLqORkrKYhisK83TKxh4YOWJh
+-----END RSA PRIVATE KEY-----
diff --git a/packages/Tethering/apex/com.android.tethering.apex.pk8 b/packages/Tethering/apex/com.android.tethering.apex.pk8
new file mode 100644
index 0000000..5663246
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.apex.pk8
Binary files differ
diff --git a/packages/Tethering/apex/com.android.tethering.apex.x509.pem b/packages/Tethering/apex/com.android.tethering.apex.x509.pem
new file mode 100644
index 0000000..a5e9401
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.apex.x509.pem
@@ -0,0 +1,36 @@
+-----BEGIN CERTIFICATE-----
+MIIGMzCCBBugAwIBAgIUXVtoDaXanhs7ma8VIICambMkj5UwDQYJKoZIhvcNAQEL
+BQAwgacxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMSMwIQYDVQQDDBpjb20uYW5kcm9pZC50ZXRoZXJpbmcuYXBleDEiMCAGCSqG
+SIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAgFw0xOTExMjgwNjU4MTRaGA80
+NzU3MTAyNDA2NTgxNFowgacxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9y
+bmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAw
+DgYDVQQLDAdBbmRyb2lkMSMwIQYDVQQDDBpjb20uYW5kcm9pZC50ZXRoZXJpbmcu
+YXBleDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCAiIwDQYJ
+KoZIhvcNAQEBBQADggIPADCCAgoCggIBANwzufMBdOj9XlNwiX+bXl/94G0DklWW
+nzob0jPlubCFfRqYkjCf2eOd28Mu/O1pOBcvobnrs9OTpGzcHkz2h58L5/0UMVTS
+tBugwCE49XF5FHawqVHNZE+s5tDmnp2cufhNc5HXHY4oZKh80/WVdbcKxiLjSY2T
+PgRAfB6E6XByKD3t1cSsc3liRVKADoJOVDvmF+xnyvSV/SN38bvTQk9aVs95mj0W
+yov6gzXBnqN7iQlvkhcijZBnFWxvoNbJ5KFy1abYOrm+ueXje4BcNhVOeRMb4E9N
+eo7+9k1GEI7TYG7laNNcp7UJ1IXCJzv/wBFKRg3f1HB3unKfx2rtKerDnVsr3o7V
+KProkgRNKNhhQ6opNguiH1YMzKpWMaC988n4AQPryPdIOmVIxIC5jJrixdxgzDXT
+qeiwFiXis291uyls08B03PQFlY9oWaY9P8s+4hIUjB6rLl+XZXsLDtDFxXeJ97NB
+8XZN1gBJoBoLknFs0C4LKpmJZB/EBao9tXV9dL/5lydRo6HzQDpjW8QX06CTUM6z
+Lr3LVelhqbsuZsV42yBKl+/LfrvNjBLEPdSevt2oMrlJW7m4iSNaMtDtJ2Oy8fA5
+WSIgLWuMbkaFDza3JzwiMzxbtbJHYiy6rY7aVywo3Vqwr1+KO3cq4eLQq62zUjRY
+e6KJwvgE2YmpAgMBAAGjUzBRMB0GA1UdDgQWBBQ8h1oF5JfKFmJCN8nfimbUK+IR
+wjAfBgNVHSMEGDAWgBQ8h1oF5JfKFmJCN8nfimbUK+IRwjAPBgNVHRMBAf8EBTAD
+AQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAP5hIkAxSyt9hRafMKiFlmXcL277bgoxNd
+qGZYbdcCFjfvM2r0QQcM/K7x2ZslFe7mJSzcyMifpm4YQTEo2yYbzKItXQV+eV1K
+9RNksRGFG9umsdWaSHhfQmcmxtr2nu9rGAgxy5OQFtyXmJPUPEM2cb/YeILwYhuQ
+Ux3kaj/fxGltX1JBag7HnMzCTZK++fRo5nqFVOJQgJH8ZpuzGeM9kZvP1+b55046
+PhSnlqmZoKhG4i5POPvvZvaakh/lM3x/N7lIlSaQpCGf7jmldni4L0/GenULVKzH
+iN73aBfh4GEvE0HRcOoH3L7V6kc3WMMLve0chZBHpoVYbzUJEJOUL4yrmwEehqtf
+xm4vlYg3vqtcE3UnU/UGdMb16t77Nz88LlpBY5ierIt0jZMU0M81ppRhr1uiD2Lj
+091sEA0Bxcw/6Q8QNF2eR7SG7Qwipnms+lw6Vcxve+7DdTrdEA0k3XgpdXp8Ya+2
+PAp9SLVp1UHiGq3qD9Jvm34QmlUWAIUTHZs3DSgs1y3K5eyw/cnzTvUUOljc/n2y
+VF0FFZtJ1dVLrzQ80Ik7apEXpBqkgBGV04/L3QYk4C0/sP+1yk6zjeeeAvDtUcHS
+gLtjAfacQl/kwfVQWfrF7VByLcivApC6EUdvT3cURM5DfZRQ4RcKr1D61VYPnNRH
++/NVbMObwQ==
+-----END CERTIFICATE-----
diff --git a/packages/Tethering/apex/manifest.json b/packages/Tethering/apex/manifest.json
new file mode 100644
index 0000000..3fb62f3
--- /dev/null
+++ b/packages/Tethering/apex/manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.tethering.apex",
+ "version": 290000000
+}
diff --git a/core/res/res/drawable-hdpi/stat_sys_tether_bluetooth.png b/packages/Tethering/res/drawable-hdpi/stat_sys_tether_bluetooth.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_tether_bluetooth.png
rename to packages/Tethering/res/drawable-hdpi/stat_sys_tether_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_tether_general.png b/packages/Tethering/res/drawable-hdpi/stat_sys_tether_general.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_tether_general.png
rename to packages/Tethering/res/drawable-hdpi/stat_sys_tether_general.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_tether_usb.png b/packages/Tethering/res/drawable-hdpi/stat_sys_tether_usb.png
similarity index 100%
rename from core/res/res/drawable-hdpi/stat_sys_tether_usb.png
rename to packages/Tethering/res/drawable-hdpi/stat_sys_tether_usb.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_tether_bluetooth.png b/packages/Tethering/res/drawable-ldpi/stat_sys_tether_bluetooth.png
similarity index 100%
rename from core/res/res/drawable-ldpi/stat_sys_tether_bluetooth.png
rename to packages/Tethering/res/drawable-ldpi/stat_sys_tether_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_tether_general.png b/packages/Tethering/res/drawable-ldpi/stat_sys_tether_general.png
similarity index 100%
rename from core/res/res/drawable-ldpi/stat_sys_tether_general.png
rename to packages/Tethering/res/drawable-ldpi/stat_sys_tether_general.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_tether_usb.png b/packages/Tethering/res/drawable-ldpi/stat_sys_tether_usb.png
similarity index 100%
rename from core/res/res/drawable-ldpi/stat_sys_tether_usb.png
rename to packages/Tethering/res/drawable-ldpi/stat_sys_tether_usb.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_tether_bluetooth.png b/packages/Tethering/res/drawable-mdpi/stat_sys_tether_bluetooth.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_tether_bluetooth.png
rename to packages/Tethering/res/drawable-mdpi/stat_sys_tether_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_tether_general.png b/packages/Tethering/res/drawable-mdpi/stat_sys_tether_general.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_tether_general.png
rename to packages/Tethering/res/drawable-mdpi/stat_sys_tether_general.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_tether_usb.png b/packages/Tethering/res/drawable-mdpi/stat_sys_tether_usb.png
similarity index 100%
rename from core/res/res/drawable-mdpi/stat_sys_tether_usb.png
rename to packages/Tethering/res/drawable-mdpi/stat_sys_tether_usb.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_tether_bluetooth.png b/packages/Tethering/res/drawable-xhdpi/stat_sys_tether_bluetooth.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/stat_sys_tether_bluetooth.png
rename to packages/Tethering/res/drawable-xhdpi/stat_sys_tether_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_tether_general.png b/packages/Tethering/res/drawable-xhdpi/stat_sys_tether_general.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/stat_sys_tether_general.png
rename to packages/Tethering/res/drawable-xhdpi/stat_sys_tether_general.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_tether_usb.png b/packages/Tethering/res/drawable-xhdpi/stat_sys_tether_usb.png
similarity index 100%
rename from core/res/res/drawable-xhdpi/stat_sys_tether_usb.png
rename to packages/Tethering/res/drawable-xhdpi/stat_sys_tether_usb.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_tether_bluetooth.png b/packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_bluetooth.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/stat_sys_tether_bluetooth.png
rename to packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_bluetooth.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_tether_general.png b/packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_general.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/stat_sys_tether_general.png
rename to packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_general.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_tether_usb.png b/packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_usb.png
similarity index 100%
rename from core/res/res/drawable-xxhdpi/stat_sys_tether_usb.png
rename to packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_usb.png
Binary files differ
diff --git a/packages/Tethering/res/values-af/strings.xml b/packages/Tethering/res/values-af/strings.xml
new file mode 100644
index 0000000..1258805
--- /dev/null
+++ b/packages/Tethering/res/values-af/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Verbinding of Wi-Fi-warmkol aktief"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Tik om op te stel."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Verbinding is gedeaktiveer"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Kontak jou administrateur vir besonderhede"</string>
+</resources>
diff --git a/packages/Tethering/res/values-am/strings.xml b/packages/Tethering/res/values-am/strings.xml
new file mode 100644
index 0000000..9c36192
--- /dev/null
+++ b/packages/Tethering/res/values-am/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"መሰካት ወይም ገባሪ ድረስ ነጥብ"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"ለማዋቀር መታ ያድርጉ።"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"እንደ ሞደም መሰካት ተሰናክሏል"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ar/strings.xml b/packages/Tethering/res/values-ar/strings.xml
new file mode 100644
index 0000000..9f84ce4
--- /dev/null
+++ b/packages/Tethering/res/values-ar/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"النطاق أو نقطة الاتصال نشطة"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"انقر للإعداد."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"تم إيقاف التوصيل"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"اتصل بالمشرف للحصول على التفاصيل"</string>
+</resources>
diff --git a/packages/Tethering/res/values-as/strings.xml b/packages/Tethering/res/values-as/strings.xml
new file mode 100644
index 0000000..8855822
--- /dev/null
+++ b/packages/Tethering/res/values-as/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"টেডাৰিং বা হটস্প\'ট সক্ৰিয় অৱস্থাত আছে"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"ছেট আপ কৰিবলৈ টিপক।"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"টেডাৰিং অক্ষম কৰি থোৱা হৈছে"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক"</string>
+</resources>
diff --git a/packages/Tethering/res/values-az/strings.xml b/packages/Tethering/res/values-az/strings.xml
new file mode 100644
index 0000000..eba50eb
--- /dev/null
+++ b/packages/Tethering/res/values-az/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Tezerinq və ya hotspot aktivdir"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Quraşdırmaq üçün tıklayın."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Birləşmə deaktivdir"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Məlumat üçün adminlə əlaqə saxlayın"</string>
+</resources>
diff --git a/packages/Tethering/res/values-b+sr+Latn/strings.xml b/packages/Tethering/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..5b0e488
--- /dev/null
+++ b/packages/Tethering/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Aktivno povezivanje sa internetom preko mobilnog uređaja ili hotspot"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Dodirnite da biste podesili."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Privezivanje je onemogućeno"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Potražite detalje od administratora"</string>
+</resources>
diff --git a/packages/Tethering/res/values-be/strings.xml b/packages/Tethering/res/values-be/strings.xml
new file mode 100644
index 0000000..5966c71
--- /dev/null
+++ b/packages/Tethering/res/values-be/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"USB-мадэм або хот-спот Wi-Fi актыўныя"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Дакраніцеся, каб наладзіць."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Рэжым мадэма адключаны"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Звярніцеся да адміністратара па падрабязную інфармацыю"</string>
+</resources>
diff --git a/packages/Tethering/res/values-bg/strings.xml b/packages/Tethering/res/values-bg/strings.xml
new file mode 100644
index 0000000..ed58d73
--- /dev/null
+++ b/packages/Tethering/res/values-bg/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Има активна споделена връзка или безжична точка за достъп"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Докоснете, за да настроите."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Функцията за тетъринг е деактивирана"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Свържете се с администратора си за подробности"</string>
+</resources>
diff --git a/packages/Tethering/res/values-bn/strings.xml b/packages/Tethering/res/values-bn/strings.xml
new file mode 100644
index 0000000..8d9880a
--- /dev/null
+++ b/packages/Tethering/res/values-bn/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"টিথারিং বা হটস্পট সক্রিয় আছে"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"সেট-আপ করার জন্য আলতো চাপুন৷"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"টিথারিং অক্ষম করা আছে"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"বিশদ বিবরণের জন্য প্রশাসকের সাথে যোগাযোগ করুন"</string>
+</resources>
diff --git a/packages/Tethering/res/values-bs/strings.xml b/packages/Tethering/res/values-bs/strings.xml
new file mode 100644
index 0000000..2361b9d
--- /dev/null
+++ b/packages/Tethering/res/values-bs/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Uređaj dijeli vezu ili djeluje kao pristupna tačka"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Dodirnite za postavke"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Povezivanje putem mobitela je onemogućeno"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Kontaktirajte svog administratora za dodatne detalje"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ca/strings.xml b/packages/Tethering/res/values-ca/strings.xml
new file mode 100644
index 0000000..6752b51
--- /dev/null
+++ b/packages/Tethering/res/values-ca/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Compartició de xarxa o punt d\'accés Wi-Fi activat"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Toca per configurar."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"La compartició de xarxa està desactivada"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contacta amb el teu administrador per obtenir més informació"</string>
+</resources>
diff --git a/packages/Tethering/res/values-cs/strings.xml b/packages/Tethering/res/values-cs/strings.xml
new file mode 100644
index 0000000..5fdd53a
--- /dev/null
+++ b/packages/Tethering/res/values-cs/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Sdílené připojení nebo hotspot je aktivní."</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Klepnutím zahájíte nastavení."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering je zakázán"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"O podrobnosti požádejte administrátora"</string>
+</resources>
diff --git a/packages/Tethering/res/values-da/strings.xml b/packages/Tethering/res/values-da/strings.xml
new file mode 100644
index 0000000..2775dfa
--- /dev/null
+++ b/packages/Tethering/res/values-da/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Netdeling eller hotspot er aktivt"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Tryk for at konfigurere"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Netdeling er deaktiveret"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Kontakt din administrator for at få oplysninger"</string>
+</resources>
diff --git a/packages/Tethering/res/values-de/strings.xml b/packages/Tethering/res/values-de/strings.xml
new file mode 100644
index 0000000..9046cd5
--- /dev/null
+++ b/packages/Tethering/res/values-de/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering oder Hotspot aktiv"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Zum Einrichten tippen."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering ist deaktiviert"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Bitte wende dich für weitere Informationen an den Administrator"</string>
+</resources>
diff --git a/packages/Tethering/res/values-el/strings.xml b/packages/Tethering/res/values-el/strings.xml
new file mode 100644
index 0000000..3b9f537
--- /dev/null
+++ b/packages/Tethering/res/values-el/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Πατήστε για ρύθμιση."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Η σύνδεση είναι απενεργοποιημένη"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες"</string>
+</resources>
diff --git a/packages/Tethering/res/values-en-rAU/strings.xml b/packages/Tethering/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..56b88a5
--- /dev/null
+++ b/packages/Tethering/res/values-en-rAU/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering or hotspot active"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Tap to set up."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering is disabled"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contact your admin for details"</string>
+</resources>
diff --git a/packages/Tethering/res/values-en-rCA/strings.xml b/packages/Tethering/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..56b88a5
--- /dev/null
+++ b/packages/Tethering/res/values-en-rCA/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering or hotspot active"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Tap to set up."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering is disabled"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contact your admin for details"</string>
+</resources>
diff --git a/packages/Tethering/res/values-en-rGB/strings.xml b/packages/Tethering/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..56b88a5
--- /dev/null
+++ b/packages/Tethering/res/values-en-rGB/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering or hotspot active"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Tap to set up."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering is disabled"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contact your admin for details"</string>
+</resources>
diff --git a/packages/Tethering/res/values-en-rIN/strings.xml b/packages/Tethering/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..56b88a5
--- /dev/null
+++ b/packages/Tethering/res/values-en-rIN/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering or hotspot active"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Tap to set up."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering is disabled"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contact your admin for details"</string>
+</resources>
diff --git a/packages/Tethering/res/values-en-rXC/strings.xml b/packages/Tethering/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..7f47fc8
--- /dev/null
+++ b/packages/Tethering/res/values-en-rXC/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering or hotspot active"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Tap to set up."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering is disabled"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contact your admin for details"</string>
+</resources>
diff --git a/packages/Tethering/res/values-es-rUS/strings.xml b/packages/Tethering/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..e4618b8
--- /dev/null
+++ b/packages/Tethering/res/values-es-rUS/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Anclaje a red o zona activa conectados"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Presiona para configurar."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Se inhabilitó la conexión mediante dispositivo portátil"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Para obtener más información, comunícate con el administrador"</string>
+</resources>
diff --git a/packages/Tethering/res/values-es/strings.xml b/packages/Tethering/res/values-es/strings.xml
new file mode 100644
index 0000000..8dc1575
--- /dev/null
+++ b/packages/Tethering/res/values-es/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Compartir conexión/Zona Wi-Fi activada"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Toca para configurar."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"La conexión compartida está inhabilitada"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Ponte en contacto con el administrador para obtener más información"</string>
+</resources>
diff --git a/packages/Tethering/res/values-et/strings.xml b/packages/Tethering/res/values-et/strings.xml
new file mode 100644
index 0000000..872c8a7
--- /dev/null
+++ b/packages/Tethering/res/values-et/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Jagamine või kuumkoht on aktiivne"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Puudutage seadistamiseks."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Jagamine on keelatud"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Lisateabe saamiseks võtke ühendust oma administraatoriga"</string>
+</resources>
diff --git a/packages/Tethering/res/values-eu/strings.xml b/packages/Tethering/res/values-eu/strings.xml
new file mode 100644
index 0000000..6c4605e
--- /dev/null
+++ b/packages/Tethering/res/values-eu/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Konexioa partekatzea edo sare publikoa aktibo"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Sakatu konfiguratzeko."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Desgaituta dago konexioa partekatzeko aukera"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Xehetasunak lortzeko, jarri administratzailearekin harremanetan"</string>
+</resources>
diff --git a/packages/Tethering/res/values-fa/strings.xml b/packages/Tethering/res/values-fa/strings.xml
new file mode 100644
index 0000000..bc2ee23
--- /dev/null
+++ b/packages/Tethering/res/values-fa/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"اشتراکگذاری اینترنت یا نقطه اتصال فعال"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"برای راهاندازی ضربه بزنید."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"اشتراکگذاری اینترنت غیرفعال است"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"برای جزئیات، با سرپرستتان تماس بگیرید"</string>
+</resources>
diff --git a/packages/Tethering/res/values-fi/strings.xml b/packages/Tethering/res/values-fi/strings.xml
new file mode 100644
index 0000000..ff0fca6
--- /dev/null
+++ b/packages/Tethering/res/values-fi/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Internetin jakaminen tai yhteyspiste käytössä"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Määritä napauttamalla."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Yhteyden jakaminen poistettu käytöstä"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Kysy lisätietoja järjestelmänvalvojalta."</string>
+</resources>
diff --git a/packages/Tethering/res/values-fr-rCA/strings.xml b/packages/Tethering/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..1f5df0e
--- /dev/null
+++ b/packages/Tethering/res/values-fr-rCA/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Partage de connexion ou point d\'accès sans fil activé"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Touchez pour configurer."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Le partage de connexion est désactivé"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Communiquez avec votre administrateur pour obtenir plus de détails"</string>
+</resources>
diff --git a/packages/Tethering/res/values-fr/strings.xml b/packages/Tethering/res/values-fr/strings.xml
new file mode 100644
index 0000000..daf7c9d
--- /dev/null
+++ b/packages/Tethering/res/values-fr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Partage de connexion ou point d\'accès sans fil activé"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Appuyez ici pour configurer."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Le partage de connexion est désactivé"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Pour en savoir plus, contactez votre administrateur"</string>
+</resources>
diff --git a/packages/Tethering/res/values-gl/strings.xml b/packages/Tethering/res/values-gl/strings.xml
new file mode 100644
index 0000000..0d16a1d
--- /dev/null
+++ b/packages/Tethering/res/values-gl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Conexión compartida ou zona wifi activada"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Tocar para configurar."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"A conexión compartida está desactivada"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contacta co administrador para obter información"</string>
+</resources>
diff --git a/packages/Tethering/res/values-gu/strings.xml b/packages/Tethering/res/values-gu/strings.xml
new file mode 100644
index 0000000..9d6b02f
--- /dev/null
+++ b/packages/Tethering/res/values-gu/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"ટિથરિંગ અથવા હૉટસ્પૉટ સક્રિય"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"સેટ કરવા માટે ટૅપ કરો."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"ટિથરિંગ અક્ષમ કરેલ છે"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો"</string>
+</resources>
diff --git a/packages/Tethering/res/values-hi/strings.xml b/packages/Tethering/res/values-hi/strings.xml
new file mode 100644
index 0000000..9c29d9a
--- /dev/null
+++ b/packages/Tethering/res/values-hi/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"टेदरिंग या हॉटस्पॉट सक्रिय"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"सेट करने के लिए टैप करें."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"टेदरिंग अक्षम है"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"जानकारी के लिए अपने एडमिन से संपर्क करें"</string>
+</resources>
diff --git a/packages/Tethering/res/values-hr/strings.xml b/packages/Tethering/res/values-hr/strings.xml
new file mode 100644
index 0000000..d0d25bb
--- /dev/null
+++ b/packages/Tethering/res/values-hr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Ograničenje ili aktivan hotspot"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Dodirnite da biste postavili."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Modemsko je povezivanje onemogućeno"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Obratite se administratoru da biste saznali pojedinosti"</string>
+</resources>
diff --git a/packages/Tethering/res/values-hu/strings.xml b/packages/Tethering/res/values-hu/strings.xml
new file mode 100644
index 0000000..3129659
--- /dev/null
+++ b/packages/Tethering/res/values-hu/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Megosztás vagy aktív hotspot"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Koppintson a beállításhoz."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Az internetmegosztás le van tiltva"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"A részletekért forduljon rendszergazdájához"</string>
+</resources>
diff --git a/packages/Tethering/res/values-hy/strings.xml b/packages/Tethering/res/values-hy/strings.xml
new file mode 100644
index 0000000..8ba6435
--- /dev/null
+++ b/packages/Tethering/res/values-hy/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Մոդեմի ռեժիմը միացված է"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Հպեք՝ կարգավորելու համար:"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Մոդեմի ռեժիմն անջատված է"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Մանրամասների համար դիմեք ձեր ադմինիստրատորին"</string>
+</resources>
diff --git a/packages/Tethering/res/values-in/strings.xml b/packages/Tethering/res/values-in/strings.xml
new file mode 100644
index 0000000..1e093ab
--- /dev/null
+++ b/packages/Tethering/res/values-in/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering (Penambatan) atau hotspot aktif"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Ketuk untuk menyiapkan."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering dinonaktifkan"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Hubungi admin untuk mengetahui detailnya"</string>
+</resources>
diff --git a/packages/Tethering/res/values-is/strings.xml b/packages/Tethering/res/values-is/strings.xml
new file mode 100644
index 0000000..f5769d5
--- /dev/null
+++ b/packages/Tethering/res/values-is/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Kveikt á tjóðrun eða aðgangsstað"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Ýttu til að setja upp."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Slökkt er á tjóðrun"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Hafðu samband við kerfisstjórann til að fá upplýsingar"</string>
+</resources>
diff --git a/packages/Tethering/res/values-it/strings.xml b/packages/Tethering/res/values-it/strings.xml
new file mode 100644
index 0000000..e0b3724
--- /dev/null
+++ b/packages/Tethering/res/values-it/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering oppure hotspot attivo"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Tocca per impostare."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering disattivato"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contatta il tuo amministratore per avere informazioni dettagliate"</string>
+</resources>
diff --git a/packages/Tethering/res/values-iw/strings.xml b/packages/Tethering/res/values-iw/strings.xml
new file mode 100644
index 0000000..c002c44
--- /dev/null
+++ b/packages/Tethering/res/values-iw/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"שיתוף אינטרנט פעיל"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"הקש כדי להגדיר."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"שיתוף האינטרנט בין ניידים מושבת"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"לפרטים, יש לפנות למנהל המערכת"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ja/strings.xml b/packages/Tethering/res/values-ja/strings.xml
new file mode 100644
index 0000000..314bde0
--- /dev/null
+++ b/packages/Tethering/res/values-ja/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"テザリングまたはアクセスポイントが有効です"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"タップしてセットアップします。"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"テザリングは無効に設定されています"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"詳しくは、管理者にお問い合わせください"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ka/strings.xml b/packages/Tethering/res/values-ka/strings.xml
new file mode 100644
index 0000000..7bbd81d
--- /dev/null
+++ b/packages/Tethering/res/values-ka/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"ტეტერინგი ან უსადენო ქსელი აქტიურია"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"შეეხეთ დასაყენებლად."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"ტეტერინგი გათიშულია"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს"</string>
+</resources>
diff --git a/packages/Tethering/res/values-kk/strings.xml b/packages/Tethering/res/values-kk/strings.xml
new file mode 100644
index 0000000..7fd87a1
--- /dev/null
+++ b/packages/Tethering/res/values-kk/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Тетеринг немесе хотспот қосулы"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Реттеу үшін түртіңіз."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Тетеринг өшірілді"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Мәліметтерді әкімшіден алыңыз"</string>
+</resources>
diff --git a/packages/Tethering/res/values-km/strings.xml b/packages/Tethering/res/values-km/strings.xml
new file mode 100644
index 0000000..2f85224
--- /dev/null
+++ b/packages/Tethering/res/values-km/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"ភ្ជាប់ ឬហតស្ពតសកម្ម"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"ប៉ះដើម្បីកំណត់"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"ការភ្ជាប់ត្រូវបានបិទ"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"ទាក់ទងអ្នកគ្រប់គ្រងរបស់អ្នកសម្រាប់ព័ត៌មានលម្អិត"</string>
+</resources>
diff --git a/packages/Tethering/res/values-kn/strings.xml b/packages/Tethering/res/values-kn/strings.xml
new file mode 100644
index 0000000..f11a83ea
--- /dev/null
+++ b/packages/Tethering/res/values-kn/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"ಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ko/strings.xml b/packages/Tethering/res/values-ko/strings.xml
new file mode 100644
index 0000000..57f24f5
--- /dev/null
+++ b/packages/Tethering/res/values-ko/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"테더링 또는 핫스팟 사용"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"설정하려면 탭하세요."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"테더링이 사용 중지됨"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"자세한 정보는 관리자에게 문의하세요."</string>
+</resources>
diff --git a/packages/Tethering/res/values-ky/strings.xml b/packages/Tethering/res/values-ky/strings.xml
new file mode 100644
index 0000000..7985485
--- /dev/null
+++ b/packages/Tethering/res/values-ky/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Жалгаштыруу же хотспот жандырылган"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Жөндөө үчүн таптап коюңуз."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Жалгаштыруу функциясы өчүрүлгөн"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Кеңири маалымат үчүн администраторуңузга кайрылыңыз"</string>
+</resources>
diff --git a/packages/Tethering/res/values-lo/strings.xml b/packages/Tethering/res/values-lo/strings.xml
new file mode 100644
index 0000000..78f1585
--- /dev/null
+++ b/packages/Tethering/res/values-lo/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"ເປີດການປ່ອຍສັນຍານ ຫຼືຮັອດສະປອດແລ້ວ"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"ແຕະເພື່ອຕັ້ງຄ່າ."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"ການປ່ອຍສັນຍານຖືກປິດໄວ້"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ"</string>
+</resources>
diff --git a/packages/Tethering/res/values-lt/strings.xml b/packages/Tethering/res/values-lt/strings.xml
new file mode 100644
index 0000000..ebff8ac
--- /dev/null
+++ b/packages/Tethering/res/values-lt/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Susietas ar aktyvus"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Palieskite, kad nustatytumėte."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Įrenginio kaip modemo naudojimas išjungtas"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Jei reikia išsamios informacijos, susisiekite su administratoriumi"</string>
+</resources>
diff --git a/packages/Tethering/res/values-lv/strings.xml b/packages/Tethering/res/values-lv/strings.xml
new file mode 100644
index 0000000..54d0048
--- /dev/null
+++ b/packages/Tethering/res/values-lv/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Piesaiste vai tīklājs ir aktīvs."</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Pieskarieties, lai iestatītu."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Piesaiste ir atspējota"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru."</string>
+</resources>
diff --git a/packages/Tethering/res/values-mk/strings.xml b/packages/Tethering/res/values-mk/strings.xml
new file mode 100644
index 0000000..0fab8aa
--- /dev/null
+++ b/packages/Tethering/res/values-mk/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Поврзувањето или точката на пристап се активни"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Допрете за поставување."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Врзувањето е оневозможено"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Контактирајте со администраторот за детали"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ml/strings.xml b/packages/Tethering/res/values-ml/strings.xml
new file mode 100644
index 0000000..fd7e556
--- /dev/null
+++ b/packages/Tethering/res/values-ml/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്പോട്ട് സജീവമാണ്"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"സജ്ജമാക്കാൻ ടാപ്പുചെയ്യുക."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"വിശദവിവരങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക"</string>
+</resources>
diff --git a/packages/Tethering/res/values-mn/strings.xml b/packages/Tethering/res/values-mn/strings.xml
new file mode 100644
index 0000000..4596577
--- /dev/null
+++ b/packages/Tethering/res/values-mn/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Модем болгох эсвэл идэвхтэй цэг болгох"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Тохируулахын тулд товшино уу."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Модем болгох боломжгүй байна"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу"</string>
+</resources>
diff --git a/packages/Tethering/res/values-mr/strings.xml b/packages/Tethering/res/values-mr/strings.xml
new file mode 100644
index 0000000..85c9ade
--- /dev/null
+++ b/packages/Tethering/res/values-mr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"टेदरिंग किंवा हॉटस्पॉट सक्रिय"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"सेट करण्यासाठी टॅप करा."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"टेदरिंग बंद आहे"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"तपशीलांसाठी तुमच्या प्रशासकाशी संपर्क साधा"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ms/strings.xml b/packages/Tethering/res/values-ms/strings.xml
new file mode 100644
index 0000000..ec6bdbd
--- /dev/null
+++ b/packages/Tethering/res/values-ms/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Penambatan atau titik panas aktif"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Ketik untuk membuat persediaan."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Penambatan dilumpuhkan"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Hubungi pentadbir anda untuk maklumat lanjut"</string>
+</resources>
diff --git a/packages/Tethering/res/values-my/strings.xml b/packages/Tethering/res/values-my/strings.xml
new file mode 100644
index 0000000..83978b6
--- /dev/null
+++ b/packages/Tethering/res/values-my/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"တဆင့်ပြန်လည်လွှင့်ခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"စနစ်ထည့်သွင်းရန် တို့ပါ။"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"မိုဘိုင်းဖုန်းကို မိုဒမ်အဖြစ်သုံးခြင်းအား ပိတ်ထားသည်"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"အသေးစိတ်အချက်အလက်များအတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ"</string>
+</resources>
diff --git a/packages/Tethering/res/values-nb/strings.xml b/packages/Tethering/res/values-nb/strings.xml
new file mode 100644
index 0000000..9abf32d
--- /dev/null
+++ b/packages/Tethering/res/values-nb/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Internettdeling eller trådløs sone er aktiv"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Trykk for å konfigurere."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Internettdeling er slått av"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Ta kontakt med administratoren din for å få mer informasjon"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ne/strings.xml b/packages/Tethering/res/values-ne/strings.xml
new file mode 100644
index 0000000..c886929
--- /dev/null
+++ b/packages/Tethering/res/values-ne/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"टेथर गर्ने वा हटस्पट सक्रिय"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"सेटअप गर्न ट्याप गर्नुहोस्।"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"टेदरिङलाई असक्षम पारिएको छ"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्"</string>
+</resources>
diff --git a/packages/Tethering/res/values-nl/strings.xml b/packages/Tethering/res/values-nl/strings.xml
new file mode 100644
index 0000000..0ec4bff
--- /dev/null
+++ b/packages/Tethering/res/values-nl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering of hotspot actief"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Tik om in te stellen."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering is uitgeschakeld"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Neem contact op met je beheerder voor meer informatie"</string>
+</resources>
diff --git a/packages/Tethering/res/values-or/strings.xml b/packages/Tethering/res/values-or/strings.xml
new file mode 100644
index 0000000..4576857
--- /dev/null
+++ b/packages/Tethering/res/values-or/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"ଟିଥରିଙ୍ଗ କିମ୍ୱା ହଟସ୍ପଟ୍ ସକ୍ରିୟ ଅଛି"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"ସେଟଅପ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"ଟିଥରିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"ବିବରଣୀ ପାଇଁ ନିଜ ଆଡମିନ୍ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ"</string>
+</resources>
diff --git a/packages/Tethering/res/values-pa/strings.xml b/packages/Tethering/res/values-pa/strings.xml
new file mode 100644
index 0000000..deddf2e
--- /dev/null
+++ b/packages/Tethering/res/values-pa/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"ਸਥਾਪਤ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"ਟੈਦਰਿੰਗ ਨੂੰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ"</string>
+</resources>
diff --git a/packages/Tethering/res/values-pl/strings.xml b/packages/Tethering/res/values-pl/strings.xml
new file mode 100644
index 0000000..48d8468
--- /dev/null
+++ b/packages/Tethering/res/values-pl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Aktywny tethering lub punkt dostępu"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Kliknij, by skonfigurować."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering został wyłączony"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem"</string>
+</resources>
diff --git a/packages/Tethering/res/values-pt-rBR/strings.xml b/packages/Tethering/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..32c22b8
--- /dev/null
+++ b/packages/Tethering/res/values-pt-rBR/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Ponto de acesso ou tethering ativo"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Toque para configurar."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering desativado"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Fale com seu administrador para saber detalhes"</string>
+</resources>
diff --git a/packages/Tethering/res/values-pt-rPT/strings.xml b/packages/Tethering/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..641e22f
--- /dev/null
+++ b/packages/Tethering/res/values-pt-rPT/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Ligação ponto a ponto ou hotspot activos"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Toque para configurar."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"A ligação (à Internet) via telemóvel está desativada."</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contacte o gestor para obter detalhes."</string>
+</resources>
diff --git a/packages/Tethering/res/values-pt/strings.xml b/packages/Tethering/res/values-pt/strings.xml
new file mode 100644
index 0000000..32c22b8
--- /dev/null
+++ b/packages/Tethering/res/values-pt/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Ponto de acesso ou tethering ativo"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Toque para configurar."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering desativado"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Fale com seu administrador para saber detalhes"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ro/strings.xml b/packages/Tethering/res/values-ro/strings.xml
new file mode 100644
index 0000000..f861f73
--- /dev/null
+++ b/packages/Tethering/res/values-ro/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering sau hotspot activ"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Atingeți ca să configurați."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tetheringul este dezactivat"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Contactați administratorul pentru detalii"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ru/strings.xml b/packages/Tethering/res/values-ru/strings.xml
new file mode 100644
index 0000000..027cb41
--- /dev/null
+++ b/packages/Tethering/res/values-ru/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Включен режим модема"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Нажмите, чтобы настроить."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Включить режим модема нельзя"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Обратитесь к администратору, чтобы узнать подробности."</string>
+</resources>
diff --git a/packages/Tethering/res/values-si/strings.xml b/packages/Tethering/res/values-si/strings.xml
new file mode 100644
index 0000000..7d8599f
--- /dev/null
+++ b/packages/Tethering/res/values-si/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"ටෙදරින් හෝ හොට්ස්පොට් සක්රීයයි"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"පිහිටුවීමට තට්ටු කරන්න."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"ටෙදරින් අබල කර ඇත"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න"</string>
+</resources>
diff --git a/packages/Tethering/res/values-sk/strings.xml b/packages/Tethering/res/values-sk/strings.xml
new file mode 100644
index 0000000..a8fe297
--- /dev/null
+++ b/packages/Tethering/res/values-sk/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering alebo prístupový bod je aktívny"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Klepnutím prejdete na nastavenie."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering je deaktivovaný"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"O podrobnosti požiadajte svojho správcu"</string>
+</resources>
diff --git a/packages/Tethering/res/values-sl/strings.xml b/packages/Tethering/res/values-sl/strings.xml
new file mode 100644
index 0000000..b5e5e38
--- /dev/null
+++ b/packages/Tethering/res/values-sl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Aktivna povezava z internetom ali dostopna točka sta aktivni"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Dotaknite se, če želite nastaviti."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Povezava z internetom prek mobilnega telefona je onemogočena"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Za podrobnosti se obrnite na skrbnika"</string>
+</resources>
diff --git a/packages/Tethering/res/values-sq/strings.xml b/packages/Tethering/res/values-sq/strings.xml
new file mode 100644
index 0000000..fdd4906
--- /dev/null
+++ b/packages/Tethering/res/values-sq/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Lidhja e çiftimit ose ajo e qasjes në zona publike interneti është aktive"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Trokit për ta konfiguruar."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Lidhja e çiftimit është çaktivizuar"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Kontakto me administratorin për detaje"</string>
+</resources>
diff --git a/packages/Tethering/res/values-sr/strings.xml b/packages/Tethering/res/values-sr/strings.xml
new file mode 100644
index 0000000..9fab34589
--- /dev/null
+++ b/packages/Tethering/res/values-sr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Активно повезивање са интернетом преко мобилног уређаја или хотспот"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Додирните да бисте подесили."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Привезивање је онемогућено"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Потражите детаље од администратора"</string>
+</resources>
diff --git a/packages/Tethering/res/values-sv/strings.xml b/packages/Tethering/res/values-sv/strings.xml
new file mode 100644
index 0000000..10eeb0f
--- /dev/null
+++ b/packages/Tethering/res/values-sv/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Internetdelning eller surfzon aktiverad"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Tryck om du vill konfigurera."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Internetdelning har inaktiverats"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Kontakta administratören om du vill veta mer"</string>
+</resources>
diff --git a/packages/Tethering/res/values-sw/strings.xml b/packages/Tethering/res/values-sw/strings.xml
new file mode 100644
index 0000000..3353963
--- /dev/null
+++ b/packages/Tethering/res/values-sw/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Kushiriki au kusambaza intaneti kumewashwa"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Gusa ili uweke mipangilio."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Umezima kipengele cha kusambaza mtandao"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Wasiliana na msimamizi wako ili upate maelezo zaidi"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ta/strings.xml b/packages/Tethering/res/values-ta/strings.xml
new file mode 100644
index 0000000..b1e5cc2
--- /dev/null
+++ b/packages/Tethering/res/values-ta/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"டெதெரிங்/ஹாட்ஸ்பாட் இயங்குகிறது"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"அமைக்க, தட்டவும்."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"இணைப்பு முறை முடக்கப்பட்டுள்ளது"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"விவரங்களுக்கு, உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்"</string>
+</resources>
diff --git a/packages/Tethering/res/values-te/strings.xml b/packages/Tethering/res/values-te/strings.xml
new file mode 100644
index 0000000..aae40de
--- /dev/null
+++ b/packages/Tethering/res/values-te/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"టీథర్ చేయబడినది లేదా హాట్స్పాట్ సక్రియంగా ఉండేది"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"సెటప్ చేయడానికి నొక్కండి."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"టెథెరింగ్ నిలిపివేయబడింది"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"వివరాల కోసం మీ నిర్వాహకులను సంప్రదించండి"</string>
+</resources>
diff --git a/packages/Tethering/res/values-th/strings.xml b/packages/Tethering/res/values-th/strings.xml
new file mode 100644
index 0000000..1b80056
--- /dev/null
+++ b/packages/Tethering/res/values-th/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"การปล่อยสัญญาณหรือฮอตสปอตทำงานอยู่"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"แตะเพื่อตั้งค่า"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด"</string>
+</resources>
diff --git a/packages/Tethering/res/values-tl/strings.xml b/packages/Tethering/res/values-tl/strings.xml
new file mode 100644
index 0000000..12863f9
--- /dev/null
+++ b/packages/Tethering/res/values-tl/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Pagsasama o aktibong hotspot"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"I-tap upang i-set up."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Naka-disable ang pag-tether"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Makipag-ugnayan sa iyong admin para sa mga detalye"</string>
+</resources>
diff --git a/packages/Tethering/res/values-tr/strings.xml b/packages/Tethering/res/values-tr/strings.xml
new file mode 100644
index 0000000..bfcf1ac
--- /dev/null
+++ b/packages/Tethering/res/values-tr/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering veya hotspot etkin"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Ayarlamak için dokunun."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Tethering devre dışı bırakıldı"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Ayrıntılı bilgi için yöneticinize başvurun"</string>
+</resources>
diff --git a/packages/Tethering/res/values-uk/strings.xml b/packages/Tethering/res/values-uk/strings.xml
new file mode 100644
index 0000000..8e159c07
--- /dev/null
+++ b/packages/Tethering/res/values-uk/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Прив\'язка чи точка дост. активна"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Торкніться, щоб налаштувати."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Використання телефона в режимі модема вимкнено"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Щоб дізнатися більше, зв’яжіться з адміністратором"</string>
+</resources>
diff --git a/packages/Tethering/res/values-ur/strings.xml b/packages/Tethering/res/values-ur/strings.xml
new file mode 100644
index 0000000..89195d4
--- /dev/null
+++ b/packages/Tethering/res/values-ur/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"ٹیدرنگ یا ہاٹ اسپاٹ فعال"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"سیٹ اپ کرنے کیلئے تھپتھپائیں۔"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"ٹیدرنگ غیر فعال ہے"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"تفصیلات کے لئے اپنے منتظم سے رابطہ کریں"</string>
+</resources>
diff --git a/packages/Tethering/res/values-uz/strings.xml b/packages/Tethering/res/values-uz/strings.xml
new file mode 100644
index 0000000..0ac4d4a
--- /dev/null
+++ b/packages/Tethering/res/values-uz/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Modem rejimi yoniq"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Sozlash uchun bosing."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Modem rejimi faolsizlantirildi"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Tafsilotlari uchun administratoringizga murojaat qiling"</string>
+</resources>
diff --git a/packages/Tethering/res/values-vi/strings.xml b/packages/Tethering/res/values-vi/strings.xml
new file mode 100644
index 0000000..85a4db8
--- /dev/null
+++ b/packages/Tethering/res/values-vi/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Chức năng điểm truy cập Internet hoặc điểm phát sóng đang hoạt động"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Nhấn để thiết lập."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Đã tắt tính năng chia sẻ kết nối"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Hãy liên hệ với quản trị viên của bạn để biết chi tiết"</string>
+</resources>
diff --git a/packages/Tethering/res/values-zh-rCN/strings.xml b/packages/Tethering/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..ff1fe03
--- /dev/null
+++ b/packages/Tethering/res/values-zh-rCN/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"网络共享或热点已启用"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"点按即可进行设置。"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"网络共享已停用"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"请与您的管理员联系以了解详情"</string>
+</resources>
diff --git a/packages/Tethering/res/values-zh-rHK/strings.xml b/packages/Tethering/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..0de39fa
--- /dev/null
+++ b/packages/Tethering/res/values-zh-rHK/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"已啟用網絡共享或熱點"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"輕按即可設定。"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"網絡共享已停用"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"請聯絡您的管理員以瞭解詳情"</string>
+</resources>
diff --git a/packages/Tethering/res/values-zh-rTW/strings.xml b/packages/Tethering/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..9a117bb
--- /dev/null
+++ b/packages/Tethering/res/values-zh-rTW/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"網路共用或無線基地台已啟用"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"輕觸即可進行設定。"</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"數據連線已停用"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"詳情請洽你的管理員"</string>
+</resources>
diff --git a/packages/Tethering/res/values-zu/strings.xml b/packages/Tethering/res/values-zu/strings.xml
new file mode 100644
index 0000000..8fe10d8
--- /dev/null
+++ b/packages/Tethering/res/values-zu/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe"</string>
+ <string name="tethered_notification_message" msgid="2113628520792055377">"Thepha ukuze usethe."</string>
+ <string name="disable_tether_notification_title" msgid="7526977944111313195">"Ukusebenzisa ifoni njengemodemu kukhutshaziwe"</string>
+ <string name="disable_tether_notification_message" msgid="2913366428516852495">"Xhumana nomphathi wakho ukuze uthole imininingwane"</string>
+</resources>
diff --git a/packages/Tethering/res/values/strings.xml b/packages/Tethering/res/values/strings.xml
new file mode 100644
index 0000000..ca866a9
--- /dev/null
+++ b/packages/Tethering/res/values/strings.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- Shown when the device is tethered -->
+ <!-- Strings for tethered notification title [CHAR LIMIT=200] -->
+ <string name="tethered_notification_title">Tethering or hotspot active</string>
+ <!-- Strings for tethered notification message [CHAR LIMIT=200] -->
+ <string name="tethered_notification_message">Tap to set up.</string>
+
+ <!-- This notification is shown when tethering has been disabled on a user's device.
+ The device is managed by the user's employer. Tethering can't be turned on unless the
+ IT administrator allows it. The noun "admin" is another reference for "IT administrator." -->
+ <!-- Strings for tether disabling notification title [CHAR LIMIT=200] -->
+ <string name="disable_tether_notification_title">Tethering is disabled</string>
+ <!-- Strings for tether disabling notification message [CHAR LIMIT=200] -->
+ <string name="disable_tether_notification_message">Contact your admin for details</string>
+</resources>
\ No newline at end of file
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index f1228129..7c78ef8 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -109,6 +109,7 @@
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
+import com.android.tethering.R;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -675,14 +676,14 @@
int icon = 0;
switch(id) {
case SystemMessage.NOTE_TETHER_USB:
- icon = com.android.internal.R.drawable.stat_sys_tether_usb;
+ icon = R.drawable.stat_sys_tether_usb;
break;
case SystemMessage.NOTE_TETHER_BLUETOOTH:
- icon = com.android.internal.R.drawable.stat_sys_tether_bluetooth;
+ icon = R.drawable.stat_sys_tether_bluetooth;
break;
case SystemMessage.NOTE_TETHER_GENERAL:
default:
- icon = com.android.internal.R.drawable.stat_sys_tether_general;
+ icon = R.drawable.stat_sys_tether_general;
break;
}
@@ -702,16 +703,16 @@
PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, intent, 0,
null, UserHandle.CURRENT);
- Resources r = Resources.getSystem();
+ Resources r = mContext.getResources();
final CharSequence title;
final CharSequence message;
if (tetheringOn) {
- title = r.getText(com.android.internal.R.string.tethered_notification_title);
- message = r.getText(com.android.internal.R.string.tethered_notification_message);
+ title = r.getText(R.string.tethered_notification_title);
+ message = r.getText(R.string.tethered_notification_message);
} else {
- title = r.getText(com.android.internal.R.string.disable_tether_notification_title);
- message = r.getText(com.android.internal.R.string.disable_tether_notification_message);
+ title = r.getText(R.string.disable_tether_notification_title);
+ message = r.getText(R.string.disable_tether_notification_message);
}
if (mTetheredNotificationBuilder == null) {
@@ -909,7 +910,7 @@
if (newlyDisallowed && isTetheringActiveOnDevice) {
mWrapper.showTetheredNotification(
- com.android.internal.R.drawable.stat_sys_tether_general, false);
+ R.drawable.stat_sys_tether_general, false);
mWrapper.untetherAll();
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 652dd40..a3a6172 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -925,6 +925,10 @@
return IIpConnectivityMetrics.Stub.asInterface(
ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
}
+
+ public IBatteryStats getBatteryStatsService() {
+ return BatteryStatsService.getService();
+ }
}
public ConnectivityService(Context context, INetworkManagementService netManager,
@@ -2144,7 +2148,7 @@
opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.M);
options = opts.toBundle();
}
- final IBatteryStats bs = BatteryStatsService.getService();
+ final IBatteryStats bs = mDeps.getBatteryStatsService();
try {
bs.noteConnectivityChanged(intent.getIntExtra(
ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE),
@@ -5628,7 +5632,8 @@
// are accurate.
networkAgent.clatd.fixupLinkProperties(oldLp, newLp);
- updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities);
+ updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities,
+ networkAgent.networkInfo.getType());
// update filtering rules, need to happen after the interface update so netd knows about the
// new interface (the interface name -> index map becomes initialized)
@@ -5707,21 +5712,26 @@
}
- private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId,
- NetworkCapabilities caps) {
- CompareResult<String> interfaceDiff = new CompareResult<>(
+ private void updateInterfaces(final @Nullable LinkProperties newLp,
+ final @Nullable LinkProperties oldLp, final int netId,
+ final @Nullable NetworkCapabilities caps, final int legacyType) {
+ final CompareResult<String> interfaceDiff = new CompareResult<>(
oldLp != null ? oldLp.getAllInterfaceNames() : null,
newLp != null ? newLp.getAllInterfaceNames() : null);
- for (String iface : interfaceDiff.added) {
- try {
- if (DBG) log("Adding iface " + iface + " to network " + netId);
- mNMS.addInterfaceToNetwork(iface, netId);
- wakeupModifyInterface(iface, caps, true);
- } catch (Exception e) {
- loge("Exception adding interface: " + e);
+ if (!interfaceDiff.added.isEmpty()) {
+ final IBatteryStats bs = mDeps.getBatteryStatsService();
+ for (final String iface : interfaceDiff.added) {
+ try {
+ if (DBG) log("Adding iface " + iface + " to network " + netId);
+ mNMS.addInterfaceToNetwork(iface, netId);
+ wakeupModifyInterface(iface, caps, true);
+ bs.noteNetworkInterfaceType(iface, legacyType);
+ } catch (Exception e) {
+ loge("Exception adding interface: " + e);
+ }
}
}
- for (String iface : interfaceDiff.removed) {
+ for (final String iface : interfaceDiff.removed) {
try {
if (DBG) log("Removing iface " + iface + " from network " + netId);
wakeupModifyInterface(iface, caps, false);
@@ -6457,77 +6467,6 @@
// do this after the default net is switched, but
// before LegacyTypeTracker sends legacy broadcasts
for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri);
-
- // Linger any networks that are no longer needed. This should be done after sending the
- // available callback for newNetwork.
- for (NetworkAgentInfo nai : removedRequests) {
- updateLingerState(nai, now);
- }
- // Possibly unlinger newNetwork. Unlingering a network does not send any callbacks so it
- // does not need to be done in any particular order.
- updateLingerState(newNetwork, now);
-
- if (isNewDefault) {
- // Maintain the illusion: since the legacy API only
- // understands one network at a time, we must pretend
- // that the current default network disconnected before
- // the new one connected.
- if (oldDefaultNetwork != null) {
- mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
- oldDefaultNetwork, true);
- }
- mDefaultInetConditionPublished = newNetwork.lastValidated ? 100 : 0;
- mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
- notifyLockdownVpn(newNetwork);
- }
-
- if (reassignedRequests.containsValue(newNetwork) || newNetwork.isVPN()) {
- // Notify battery stats service about this network, both the normal
- // interface and any stacked links.
- // TODO: Avoid redoing this; this must only be done once when a network comes online.
- try {
- final IBatteryStats bs = BatteryStatsService.getService();
- final int type = newNetwork.networkInfo.getType();
-
- final String baseIface = newNetwork.linkProperties.getInterfaceName();
- bs.noteNetworkInterfaceType(baseIface, type);
- for (LinkProperties stacked : newNetwork.linkProperties.getStackedLinks()) {
- final String stackedIface = stacked.getInterfaceName();
- bs.noteNetworkInterfaceType(stackedIface, type);
- }
- } catch (RemoteException ignored) {
- }
-
- // This has to happen after the notifyNetworkCallbacks as that tickles each
- // ConnectivityManager instance 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? We send the broadcast
- // after sending the callback, but if the app can receive the
- // broadcast before the callback, it might still break.
- //
- // 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 (int i = 0; i < newNetwork.numNetworkRequests(); i++) {
- NetworkRequest nr = newNetwork.requestAt(i);
- if (nr.legacyType != TYPE_NONE && nr.isRequest()) {
- // legacy type tracker filters out repeat adds
- mLegacyTypeTracker.add(nr.legacyType, newNetwork);
- }
- }
-
- // 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 (newNetwork.isVPN()) {
- mLegacyTypeTracker.add(TYPE_VPN, newNetwork);
- }
- }
}
/**
@@ -6541,15 +6480,32 @@
// requests. Once the code has switched to a request-major iteration style, this can
// be optimized to only do the processing needed.
final long now = SystemClock.elapsedRealtime();
+ final NetworkAgentInfo oldDefaultNetwork = getDefaultNetwork();
+
final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray(
new NetworkAgentInfo[mNetworkAgentInfos.size()]);
// Rematch higher scoring networks first to prevent requests first matching a lower
// scoring network and then a higher scoring network, which could produce multiple
- // callbacks and inadvertently unlinger networks.
+ // callbacks.
Arrays.sort(nais);
- for (NetworkAgentInfo nai : nais) {
+ for (final NetworkAgentInfo nai : nais) {
rematchNetworkAndRequests(nai, now);
}
+
+ final NetworkAgentInfo newDefaultNetwork = getDefaultNetwork();
+
+ for (final NetworkAgentInfo nai : nais) {
+ // Rematching may have altered the linger state of some networks, so update all linger
+ // timers. updateLingerState 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.
+ updateLingerState(nai, now);
+ }
+
+ updateLegacyTypeTrackerAndVpnLockdownForRematch(oldDefaultNetwork, newDefaultNetwork, nais);
+
+ // Tear down all unneeded networks.
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
if (unneeded(nai, UnneededFor.TEARDOWN)) {
if (nai.getLingerExpiry() > 0) {
@@ -6569,6 +6525,70 @@
}
}
+ private void updateLegacyTypeTrackerAndVpnLockdownForRematch(
+ @Nullable final NetworkAgentInfo oldDefaultNetwork,
+ @Nullable final NetworkAgentInfo newDefaultNetwork,
+ @NonNull final NetworkAgentInfo[] nais) {
+ 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);
+ // If the legacy VPN is connected, notifyLockdownVpn may end up sending a broadcast
+ // to reflect the NetworkInfo of this new network. This broadcast has to be sent
+ // after the disconnect broadcasts above, but before the broadcasts sent by the
+ // legacy type tracker below.
+ // TODO : refactor this, it's too complex
+ notifyLockdownVpn(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) {
+ addNetworkToLegacyTypeTracker(nai);
+ }
+ }
+
+ 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;
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 9ebe896..5f562cf 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -146,8 +146,13 @@
@Override
public void onBootPhase(int phase) {
- if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
- mService.systemRunning();
+ if (phase == PHASE_SYSTEM_SERVICES_READY) {
+ // the location service must be functioning after this boot phase
+ mService.onSystemReady();
+ } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+ // some providers rely on third party code, so we wait to initialize
+ // providers until third party code is allowed to run
+ mService.onSystemThirdPartyAppsCanStart();
}
}
}
@@ -264,156 +269,159 @@
userId -> mContext.getResources().getStringArray(
com.android.internal.R.array.config_locationExtraPackageNames));
- // most startup is deferred until systemRunning()
+ // most startup is deferred until systemReady()
}
- private void systemRunning() {
+ private void onSystemReady() {
synchronized (mLock) {
- initializeLocked();
+ mPackageManager = mContext.getPackageManager();
+ mAppOps = mContext.getSystemService(AppOpsManager.class);
+ mPowerManager = mContext.getSystemService(PowerManager.class);
+ mActivityManager = mContext.getSystemService(ActivityManager.class);
+ mUserManager = mContext.getSystemService(UserManager.class);
+
+ mSettingsStore = new LocationSettingsStore(mContext, mHandler);
+ mLocationFudger = new LocationFudger(mContext, mHandler);
+ mGeofenceManager = new GeofenceManager(mContext, mSettingsStore);
+
+ PowerManagerInternal localPowerManager =
+ LocalServices.getService(PowerManagerInternal.class);
+
+ // add listeners
+ mAppOps.startWatchingMode(
+ AppOpsManager.OP_COARSE_LOCATION,
+ null,
+ AppOpsManager.WATCH_FOREGROUND_CHANGES,
+ new AppOpsManager.OnOpChangedInternalListener() {
+ public void onOpChanged(int op, String packageName) {
+ // onOpChanged invoked on ui thread, move to our thread to reduce
+ // risk of
+ // blocking ui thread
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ onAppOpChangedLocked();
+ }
+ });
+ }
+ });
+ mPackageManager.addOnPermissionsChangeListener(
+ uid -> {
+ // listener invoked on ui thread, move to our thread to reduce risk of
+ // blocking
+ // ui thread
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ onPermissionsChangedLocked();
+ }
+ });
+ });
+ mActivityManager.addOnUidImportanceListener(
+ (uid, importance) -> {
+ // listener invoked on ui thread, move to our thread to reduce risk of
+ // blocking
+ // ui thread
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ onUidImportanceChangedLocked(uid, importance);
+ }
+ });
+ },
+ FOREGROUND_IMPORTANCE_CUTOFF);
+
+ localPowerManager.registerLowPowerModeObserver(ServiceType.LOCATION,
+ state -> {
+ // listener invoked on ui thread, move to our thread to reduce risk of
+ // blocking
+ // ui thread
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ onBatterySaverModeChangedLocked(state.locationMode);
+ }
+ });
+ });
+ mBatterySaverMode = mPowerManager.getLocationPowerSaveMode();
+
+ mSettingsStore.addOnLocationEnabledChangedListener(() -> {
+ synchronized (mLock) {
+ onLocationModeChangedLocked(true);
+ }
+ });
+ mSettingsStore.addOnLocationProvidersAllowedChangedListener(() -> {
+ synchronized (mLock) {
+ onProviderAllowedChangedLocked();
+ }
+ });
+ mSettingsStore.addOnBackgroundThrottleIntervalChangedListener(() -> {
+ synchronized (mLock) {
+ onBackgroundThrottleIntervalChangedLocked();
+ }
+ });
+ mSettingsStore.addOnBackgroundThrottlePackageWhitelistChangedListener(() -> {
+ synchronized (mLock) {
+ onBackgroundThrottleWhitelistChangedLocked();
+ }
+ });
+ mSettingsStore.addOnIgnoreSettingsPackageWhitelistChangedListener(() -> {
+ synchronized (mLock) {
+ onIgnoreSettingsWhitelistChangedLocked();
+ }
+ });
+
+ new PackageMonitor() {
+ @Override
+ public void onPackageDisappeared(String packageName, int reason) {
+ synchronized (mLock) {
+ LocationManagerService.this.onPackageDisappearedLocked(packageName);
+ }
+ }
+ }.register(mContext, mHandler.getLooper(), true);
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+ intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
+ intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
+ intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
+ intentFilter.addAction(Intent.ACTION_SCREEN_ON);
+
+ mContext.registerReceiverAsUser(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (action == null) {
+ return;
+ }
+ synchronized (mLock) {
+ switch (action) {
+ case Intent.ACTION_USER_SWITCHED:
+ onUserChangedLocked(
+ intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+ break;
+ case Intent.ACTION_MANAGED_PROFILE_ADDED:
+ case Intent.ACTION_MANAGED_PROFILE_REMOVED:
+ onUserProfilesChangedLocked();
+ break;
+ case Intent.ACTION_SCREEN_ON:
+ case Intent.ACTION_SCREEN_OFF:
+ onScreenStateChangedLocked();
+ break;
+ }
+ }
+ }
+ }, UserHandle.ALL, intentFilter, null, mHandler);
+
+ // switching the user from null to system here performs the bulk of the initialization
+ // work. the user being changed will cause a reload of all user specific settings, which
+ // causes initialization, and propagates changes until a steady state is reached
+ mCurrentUserId = UserHandle.USER_NULL;
+ onUserChangedLocked(ActivityManager.getCurrentUser());
}
}
- @GuardedBy("mLock")
- private void initializeLocked() {
- mPackageManager = mContext.getPackageManager();
- mAppOps = mContext.getSystemService(AppOpsManager.class);
- mPowerManager = mContext.getSystemService(PowerManager.class);
- mActivityManager = mContext.getSystemService(ActivityManager.class);
- mUserManager = mContext.getSystemService(UserManager.class);
-
- mSettingsStore = new LocationSettingsStore(mContext, mHandler);
-
- mLocationFudger = new LocationFudger(mContext, mHandler);
- mGeofenceManager = new GeofenceManager(mContext, mSettingsStore);
-
- PowerManagerInternal localPowerManager =
- LocalServices.getService(PowerManagerInternal.class);
-
- // prepare providers
- initializeProvidersLocked();
-
- // add listeners
- mAppOps.startWatchingMode(
- AppOpsManager.OP_COARSE_LOCATION,
- null,
- AppOpsManager.WATCH_FOREGROUND_CHANGES,
- new AppOpsManager.OnOpChangedInternalListener() {
- public void onOpChanged(int op, String packageName) {
- // onOpChanged invoked on ui thread, move to our thread to reduce risk of
- // blocking ui thread
- mHandler.post(() -> {
- synchronized (mLock) {
- onAppOpChangedLocked();
- }
- });
- }
- });
- mPackageManager.addOnPermissionsChangeListener(
- uid -> {
- // listener invoked on ui thread, move to our thread to reduce risk of blocking
- // ui thread
- mHandler.post(() -> {
- synchronized (mLock) {
- onPermissionsChangedLocked();
- }
- });
- });
- mActivityManager.addOnUidImportanceListener(
- (uid, importance) -> {
- // listener invoked on ui thread, move to our thread to reduce risk of blocking
- // ui thread
- mHandler.post(() -> {
- synchronized (mLock) {
- onUidImportanceChangedLocked(uid, importance);
- }
- });
- },
- FOREGROUND_IMPORTANCE_CUTOFF);
-
- localPowerManager.registerLowPowerModeObserver(ServiceType.LOCATION,
- state -> {
- // listener invoked on ui thread, move to our thread to reduce risk of blocking
- // ui thread
- mHandler.post(() -> {
- synchronized (mLock) {
- onBatterySaverModeChangedLocked(state.locationMode);
- }
- });
- });
- mBatterySaverMode = mPowerManager.getLocationPowerSaveMode();
-
- mSettingsStore.addOnLocationEnabledChangedListener(() -> {
- synchronized (mLock) {
- onLocationModeChangedLocked(true);
- }
- });
- mSettingsStore.addOnLocationProvidersAllowedChangedListener(() -> {
- synchronized (mLock) {
- onProviderAllowedChangedLocked();
- }
- });
- mSettingsStore.addOnBackgroundThrottleIntervalChangedListener(() -> {
- synchronized (mLock) {
- onBackgroundThrottleIntervalChangedLocked();
- }
- });
- mSettingsStore.addOnBackgroundThrottlePackageWhitelistChangedListener(() -> {
- synchronized (mLock) {
- onBackgroundThrottleWhitelistChangedLocked();
- }
- });
- mSettingsStore.addOnIgnoreSettingsPackageWhitelistChangedListener(() -> {
- synchronized (mLock) {
- onIgnoreSettingsWhitelistChangedLocked();
- }
- });
-
- new PackageMonitor() {
- @Override
- public void onPackageDisappeared(String packageName, int reason) {
- synchronized (mLock) {
- LocationManagerService.this.onPackageDisappearedLocked(packageName);
- }
- }
- }.register(mContext, mHandler.getLooper(), true);
-
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
- intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
- intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
- intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
- intentFilter.addAction(Intent.ACTION_SCREEN_ON);
-
- mContext.registerReceiverAsUser(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (action == null) {
- return;
- }
- synchronized (mLock) {
- switch (action) {
- case Intent.ACTION_USER_SWITCHED:
- onUserChangedLocked(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
- break;
- case Intent.ACTION_MANAGED_PROFILE_ADDED:
- case Intent.ACTION_MANAGED_PROFILE_REMOVED:
- onUserProfilesChangedLocked();
- break;
- case Intent.ACTION_SCREEN_ON:
- case Intent.ACTION_SCREEN_OFF:
- onScreenStateChangedLocked();
- break;
- }
- }
- }
- }, UserHandle.ALL, intentFilter, null, mHandler);
-
- // switching the user from null to system here performs the bulk of the initialization work.
- // the user being changed will cause a reload of all user specific settings, which causes
- // provider initialization, and propagates changes until a steady state is reached
- mCurrentUserId = UserHandle.USER_NULL;
- onUserChangedLocked(ActivityManager.getCurrentUser());
+ private void onSystemThirdPartyAppsCanStart() {
+ synchronized (mLock) {
+ // prepare providers
+ initializeProvidersLocked();
+ }
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index a4bc3bd..9d1eb6c 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -118,6 +118,7 @@
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.DataUnit;
+import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -819,7 +820,6 @@
refreshFuseSettings();
});
refreshIsolatedStorageSettings();
- refreshFuseSettings();
}
/**
@@ -883,16 +883,25 @@
SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE, Boolean.toString(res));
}
+ /**
+ * The most recent flag change takes precedence. Change fuse Settings flag if Device Config is
+ * changed. Settings flag change will in turn change fuse system property (persist.sys.fuse)
+ * whenever the user reboots.
+ */
private void refreshFuseSettings() {
int isFuseEnabled = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
FUSE_ENABLED, 0);
if (isFuseEnabled == 1) {
- SystemProperties.set(StorageManager.PROP_FUSE, "true");
+ Slog.d(TAG, "Device Config flag for FUSE is enabled, turn Settings fuse flag on");
+ SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX
+ + FeatureFlagUtils.SETTINGS_FUSE_FLAG, "true");
} else if (isFuseEnabled == -1) {
- SystemProperties.set(StorageManager.PROP_FUSE, "false");
+ Slog.d(TAG, "Device Config flag for FUSE is disabled, turn Settings fuse flag off");
+ SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX
+ + FeatureFlagUtils.SETTINGS_FUSE_FLAG, "false");
}
// else, keep the build config.
- // This can be overridden be direct adjustment of persist.sys.prop
+ // This can be overridden by direct adjustment of persist.sys.fflag.override.settings_fuse
}
/**
@@ -1548,6 +1557,8 @@
public StorageManagerService(Context context) {
sSelf = this;
+ updateFusePropFromSettings();
+
// Snapshot feature flag used for this boot
SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString(
SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true)));
@@ -1609,6 +1620,23 @@
}
}
+ /**
+ * Checks if user changed the persistent settings_fuse flag from Settings UI
+ * and updates PROP_FUSE (reboots if changed).
+ */
+ private void updateFusePropFromSettings() {
+ Boolean settingsFuseFlag = SystemProperties.getBoolean((FeatureFlagUtils.PERSIST_PREFIX
+ + FeatureFlagUtils.SETTINGS_FUSE_FLAG), false);
+ Slog.d(TAG, "The value of Settings Fuse Flag is " + settingsFuseFlag);
+ if (SystemProperties.getBoolean(StorageManager.PROP_FUSE, false) != settingsFuseFlag) {
+ Slog.d(TAG, "Set persist.sys.fuse to " + settingsFuseFlag);
+ SystemProperties.set(StorageManager.PROP_FUSE, Boolean.toString(settingsFuseFlag));
+ // Perform hard reboot to kick policy into place
+ mContext.getSystemService(PowerManager.class).reboot("Reboot device for FUSE system"
+ + "property change to take effect");
+ }
+ }
+
private void start() {
connectStoraged();
connectVold();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e119d1e..5b8ffde 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3784,7 +3784,7 @@
}
@GuardedBy("this")
- void waitForProcKillLocked(final ProcessRecord app, final String formatString,
+ private void waitForProcKillLocked(final ProcessRecord app, final String formatString,
final long startTime) {
app.mAppDiedCallback = () -> {
synchronized (ActivityManagerService.this) {
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 0524f91..638111e 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -126,7 +126,7 @@
// Keep the last WiFi stats so we can compute a delta.
@GuardedBy("mWorkerLock")
private WifiActivityEnergyInfo mLastInfo =
- new WifiActivityEnergyInfo(0, 0, 0, new long[]{0}, 0, 0, 0, 0);
+ new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0, 0);
/**
* Timestamp at which all external stats were last collected in
@@ -548,42 +548,45 @@
@GuardedBy("mWorkerLock")
private WifiActivityEnergyInfo extractDeltaLocked(WifiActivityEnergyInfo latest) {
- final long timePeriodMs = latest.mTimestamp - mLastInfo.mTimestamp;
- final long lastScanMs = mLastInfo.mControllerScanTimeMs;
- final long lastIdleMs = mLastInfo.mControllerIdleTimeMs;
- final long lastTxMs = mLastInfo.mControllerTxTimeMs;
- final long lastRxMs = mLastInfo.mControllerRxTimeMs;
- final long lastEnergy = mLastInfo.mControllerEnergyUsed;
+ final long timePeriodMs = latest.getTimeSinceBootMillis()
+ - mLastInfo.getTimeSinceBootMillis();
+ final long lastScanMs = mLastInfo.getControllerScanDurationMillis();
+ final long lastIdleMs = mLastInfo.getControllerIdleDurationMillis();
+ final long lastTxMs = mLastInfo.getControllerTxDurationMillis();
+ final long lastRxMs = mLastInfo.getControllerRxDurationMillis();
+ final long lastEnergy = mLastInfo.getControllerEnergyUsedMicroJoules();
// We will modify the last info object to be the delta, and store the new
// WifiActivityEnergyInfo object as our last one.
final WifiActivityEnergyInfo delta = mLastInfo;
- delta.mTimestamp = latest.getTimeStamp();
- delta.mStackState = latest.getStackState();
+ delta.setTimeSinceBootMillis(latest.getTimeSinceBootMillis());
+ delta.setStackState(latest.getStackState());
- final long txTimeMs = latest.mControllerTxTimeMs - lastTxMs;
- final long rxTimeMs = latest.mControllerRxTimeMs - lastRxMs;
- final long idleTimeMs = latest.mControllerIdleTimeMs - lastIdleMs;
- final long scanTimeMs = latest.mControllerScanTimeMs - lastScanMs;
+ final long txTimeMs = latest.getControllerTxDurationMillis() - lastTxMs;
+ final long rxTimeMs = latest.getControllerRxDurationMillis() - lastRxMs;
+ final long idleTimeMs = latest.getControllerIdleDurationMillis() - lastIdleMs;
+ final long scanTimeMs = latest.getControllerScanDurationMillis() - lastScanMs;
if (txTimeMs < 0 || rxTimeMs < 0 || scanTimeMs < 0 || idleTimeMs < 0) {
// The stats were reset by the WiFi system (which is why our delta is negative).
// Returns the unaltered stats. The total on time should not exceed the time
// duartion between reports.
- final long totalOnTimeMs = latest.mControllerTxTimeMs + latest.mControllerRxTimeMs
- + latest.mControllerIdleTimeMs;
+ final long totalOnTimeMs = latest.getControllerTxDurationMillis()
+ + latest.getControllerRxDurationMillis()
+ + latest.getControllerIdleDurationMillis();
if (totalOnTimeMs <= timePeriodMs + MAX_WIFI_STATS_SAMPLE_ERROR_MILLIS) {
- delta.mControllerEnergyUsed = latest.mControllerEnergyUsed;
- delta.mControllerRxTimeMs = latest.mControllerRxTimeMs;
- delta.mControllerTxTimeMs = latest.mControllerTxTimeMs;
- delta.mControllerIdleTimeMs = latest.mControllerIdleTimeMs;
- delta.mControllerScanTimeMs = latest.mControllerScanTimeMs;
+ delta.setControllerEnergyUsedMicroJoules(
+ latest.getControllerEnergyUsedMicroJoules());
+ delta.setControllerRxDurationMillis(latest.getControllerRxDurationMillis());
+ delta.setControllerTxDurationMillis(latest.getControllerTxDurationMillis());
+ delta.setControllerIdleDurationMillis(latest.getControllerIdleDurationMillis());
+ delta.setControllerScanDurationMillis(latest.getControllerScanDurationMillis());
} else {
- delta.mControllerEnergyUsed = 0;
- delta.mControllerRxTimeMs = 0;
- delta.mControllerTxTimeMs = 0;
- delta.mControllerIdleTimeMs = 0;
- delta.mControllerScanTimeMs = 0;
+ delta.setControllerEnergyUsedMicroJoules(0);
+ delta.setControllerRxDurationMillis(0);
+ delta.setControllerTxDurationMillis(0);
+ delta.setControllerIdleDurationMillis(0);
+ delta.setControllerScanDurationMillis(0);
}
Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + delta);
} else {
@@ -608,28 +611,30 @@
sb.append(" e=").append(lastEnergy);
sb.append("\n");
sb.append("Current WiFi snapshot: ").append("idle=");
- TimeUtils.formatDuration(latest.mControllerIdleTimeMs, sb);
+ TimeUtils.formatDuration(latest.getControllerIdleDurationMillis(), sb);
sb.append(" rx=");
- TimeUtils.formatDuration(latest.mControllerRxTimeMs, sb);
+ TimeUtils.formatDuration(latest.getControllerRxDurationMillis(), sb);
sb.append(" tx=");
- TimeUtils.formatDuration(latest.mControllerTxTimeMs, sb);
- sb.append(" e=").append(latest.mControllerEnergyUsed);
+ TimeUtils.formatDuration(latest.getControllerTxDurationMillis(), sb);
+ sb.append(" e=").append(latest.getControllerEnergyUsedMicroJoules());
Slog.wtf(TAG, sb.toString());
}
} else {
maxExpectedIdleTimeMs = timePeriodMs - totalActiveTimeMs;
}
// These times seem to be the most reliable.
- delta.mControllerTxTimeMs = txTimeMs;
- delta.mControllerRxTimeMs = rxTimeMs;
- delta.mControllerScanTimeMs = scanTimeMs;
+ delta.setControllerTxDurationMillis(txTimeMs);
+ delta.setControllerRxDurationMillis(rxTimeMs);
+ delta.setControllerScanDurationMillis(scanTimeMs);
// WiFi calculates the idle time as a difference from the on time and the various
// Rx + Tx times. There seems to be some missing time there because this sometimes
// becomes negative. Just cap it at 0 and ensure that it is less than the expected idle
// time from the difference in timestamps.
// b/21613534
- delta.mControllerIdleTimeMs = Math.min(maxExpectedIdleTimeMs, Math.max(0, idleTimeMs));
- delta.mControllerEnergyUsed = Math.max(0, latest.mControllerEnergyUsed - lastEnergy);
+ delta.setControllerIdleDurationMillis(
+ Math.min(maxExpectedIdleTimeMs, Math.max(0, idleTimeMs)));
+ delta.setControllerEnergyUsedMicroJoules(
+ Math.max(0, latest.getControllerEnergyUsedMicroJoules() - lastEnergy));
}
mLastInfo = latest;
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 375da8a..2bb7035 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1421,7 +1421,7 @@
if (app.pendingStart) {
return true;
}
- long startTime = SystemClock.uptimeMillis();
+ long startTime = SystemClock.elapsedRealtime();
if (app.pid > 0 && app.pid != ActivityManagerService.MY_PID) {
checkSlow(startTime, "startProcess: removing from pids map");
mService.mPidsSelfLocked.remove(app);
@@ -1856,7 +1856,7 @@
boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
- long startTime = SystemClock.uptimeMillis();
+ long startTime = SystemClock.elapsedRealtime();
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
@@ -1917,9 +1917,10 @@
// An application record is attached to a previous process,
// clean it up now.
if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App died: " + app);
+ checkSlow(startTime, "startProcess: bad proc running, killing");
ProcessList.killProcessGroup(app.uid, app.pid);
- mService.waitForProcKillLocked(app, "startProcess: bad proc running, killing: %s",
- startTime);
+ mService.handleAppDiedLocked(app, true, true);
+ checkSlow(startTime, "startProcess: done killing old proc");
}
if (app == null) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e426c6c..4bf1de6 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -269,6 +269,7 @@
private static final int MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS = 27;
private static final int MSG_HDMI_VOLUME_CHECK = 28;
private static final int MSG_PLAYBACK_CONFIG_CHANGE = 29;
+ private static final int MSG_BROADCAST_MICROPHONE_MUTE = 30;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -2925,9 +2926,8 @@
AudioSystem.muteMicrophone(muted);
try {
if (muted != currentMute) {
- mContext.sendBroadcastAsUser(
- new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED)
- .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL);
+ sendMsg(mAudioHandler, MSG_BROADCAST_MICROPHONE_MUTE,
+ SENDMSG_NOOP, 0, 0, null, 0);
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -5236,6 +5236,13 @@
case MSG_PLAYBACK_CONFIG_CHANGE:
onPlaybackConfigChange((List<AudioPlaybackConfiguration>) msg.obj);
break;
+
+ case MSG_BROADCAST_MICROPHONE_MUTE:
+ mContext.sendBroadcastAsUser(
+ new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED)
+ .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
+ UserHandle.ALL);
+ break;
}
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 24a5b7f..bb7f862 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -580,7 +580,7 @@
// 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 it won't stop it
+ // has already been dispatched, rescheduling to some time in the future won't stop it
// from calling its callback immediately.
if (mLingerMessage != null) {
mLingerMessage.cancel();
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 9882f6c..7ce63c5 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -138,13 +138,17 @@
}
/**
- * Sets the display modes the system is allowed to switch between, roughly ordered by
- * preference.
+ * Sets the refresh ranges, and display modes that the system is allowed to switch between.
+ * Display modes are roughly ordered by preference.
*
* Not all display devices will automatically switch between modes, so it's important that the
* most-desired modes are at the beginning of the allowed array.
+ *
+ * @param defaultModeId is used, if the device does not support multiple refresh
+ * rates, and to navigate other parameters.
*/
- public void setAllowedDisplayModesLocked(int[] modes) {
+ public void setDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
+ float maxRefreshRate, int[] modes) {
}
/**
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index d24bd1a..6118df5 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -18,26 +18,22 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-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.hardware.display.DisplayManager;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
-
+import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.UserHandle;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.text.TextUtils;
@@ -47,11 +43,11 @@
import android.view.Display;
import android.view.DisplayInfo;
-import com.android.internal.os.BackgroundThread;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
import com.android.server.display.utils.AmbientFilter;
import com.android.server.display.utils.AmbientFilterFactory;
-import com.android.server.display.whitebalance.DisplayWhiteBalanceFactory;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -87,11 +83,11 @@
// A map from the display ID to the collection of votes and their priority. The latter takes
// the form of another map from the priority to the vote itself so that each priority is
// guaranteed to have exactly one vote, which is also easily and efficiently replaceable.
- private final SparseArray<SparseArray<Vote>> mVotesByDisplay;
+ private SparseArray<SparseArray<Vote>> mVotesByDisplay;
// A map from the display ID to the supported modes on that display.
- private final SparseArray<Display.Mode[]> mSupportedModesByDisplay;
+ private SparseArray<Display.Mode[]> mSupportedModesByDisplay;
// A map from the display ID to the default mode of that display.
- private final SparseArray<Display.Mode> mDefaultModeByDisplay;
+ private SparseArray<Display.Mode> mDefaultModeByDisplay;
private final AppRequestObserver mAppRequestObserver;
private final SettingsObserver mSettingsObserver;
@@ -143,17 +139,7 @@
*/
@NonNull
public int[] getAllowedModes(int displayId) {
- synchronized (mLock) {
- SparseArray<Vote> votes = getVotesLocked(displayId);
- Display.Mode[] modes = mSupportedModesByDisplay.get(displayId);
- Display.Mode defaultMode = mDefaultModeByDisplay.get(displayId);
- if (modes == null || defaultMode == null) {
- Slog.e(TAG, "Asked about unknown display, returning empty allowed set! (id="
- + displayId + ")");
- return new int[0];
- }
- return getAllowedModesLocked(votes, modes, defaultMode);
- }
+ return getDesiredDisplayConfigSpecs(displayId).allowedConfigs;
}
@NonNull
@@ -178,76 +164,101 @@
return votes;
}
+ /**
+ * Calculates the refresh rate ranges and display modes that the system is allowed to freely
+ * switch between based on global and display-specific constraints.
+ *
+ * @param displayId The display to query for.
+ * @return The ID of the default mode the system should use, and the refresh rate range the
+ * system is allowed to switch between.
+ */
@NonNull
- private int[] getAllowedModesLocked(@NonNull SparseArray<Vote> votes,
- @NonNull Display.Mode[] modes, @NonNull Display.Mode defaultMode) {
- int lowestConsideredPriority = Vote.MIN_PRIORITY;
- while (lowestConsideredPriority <= Vote.MAX_PRIORITY) {
+ public DesiredDisplayConfigSpecs getDesiredDisplayConfigSpecs(int displayId) {
+ synchronized (mLock) {
+ SparseArray<Vote> votes = getVotesLocked(displayId);
+ Display.Mode[] modes = mSupportedModesByDisplay.get(displayId);
+ Display.Mode defaultMode = mDefaultModeByDisplay.get(displayId);
+ if (modes == null || defaultMode == null) {
+ Slog.e(TAG, "Asked about unknown display, returning empty desired configs!"
+ + "(id=" + displayId + ")");
+ return new DesiredDisplayConfigSpecs(displayId, new RefreshRateRange(60, 60),
+ new int[0]);
+ }
+
+ int[] availableModes = new int[]{defaultMode.getModeId()};
float minRefreshRate = 0f;
float maxRefreshRate = Float.POSITIVE_INFINITY;
- int height = Vote.INVALID_SIZE;
- int width = Vote.INVALID_SIZE;
+ int lowestConsideredPriority = Vote.MIN_PRIORITY;
+ while (lowestConsideredPriority <= Vote.MAX_PRIORITY) {
+ int height = Vote.INVALID_SIZE;
+ int width = Vote.INVALID_SIZE;
- for (int priority = Vote.MAX_PRIORITY;
- priority >= lowestConsideredPriority;
- priority--) {
- Vote vote = votes.get(priority);
- if (vote == null) {
- continue;
+ for (int priority = Vote.MAX_PRIORITY;
+ priority >= lowestConsideredPriority; priority--) {
+ Vote vote = votes.get(priority);
+ if (vote == null) {
+ continue;
+ }
+ // For refresh rates, just use the tightest bounds of all the votes
+ minRefreshRate = Math.max(minRefreshRate, vote.refreshRateRange.min);
+ maxRefreshRate = Math.min(maxRefreshRate, vote.refreshRateRange.max);
+ // For display size, use only the first vote we come across (i.e. the highest
+ // priority vote that includes the width / height).
+ if (height == Vote.INVALID_SIZE && width == Vote.INVALID_SIZE
+ && vote.height > 0 && vote.width > 0) {
+ width = vote.width;
+ height = vote.height;
+ }
}
- // For refresh rates, just use the tightest bounds of all the votes
- minRefreshRate = Math.max(minRefreshRate, vote.minRefreshRate);
- maxRefreshRate = Math.min(maxRefreshRate, vote.maxRefreshRate);
- // For display size, use only the first vote we come across (i.e. the highest
- // priority vote that includes the width / height).
- if (height == Vote.INVALID_SIZE && width == Vote.INVALID_SIZE
- && vote.height > 0 && vote.width > 0) {
- width = vote.width;
- height = vote.height;
+
+ // If we don't have anything specifying the width / height of the display, just use
+ // the default width and height. We don't want these switching out from underneath
+ // us since it's a pretty disruptive behavior.
+ if (height == Vote.INVALID_SIZE || width == Vote.INVALID_SIZE) {
+ width = defaultMode.getPhysicalWidth();
+ height = defaultMode.getPhysicalHeight();
}
- }
- // If we don't have anything specifying the width / height of the display, just use the
- // default width and height. We don't want these switching out from underneath us since
- // it's a pretty disruptive behavior.
- if (height == Vote.INVALID_SIZE || width == Vote.INVALID_SIZE) {
- width = defaultMode.getPhysicalWidth();
- height = defaultMode.getPhysicalHeight();
- }
+ availableModes = filterModes(modes, width, height, minRefreshRate, maxRefreshRate);
+ if (availableModes.length > 0) {
+ if (DEBUG) {
+ Slog.w(TAG, "Found available modes=" + Arrays.toString(availableModes)
+ + " with lowest priority considered "
+ + Vote.priorityToString(lowestConsideredPriority)
+ + " and constraints: "
+ + "width=" + width
+ + ", height=" + height
+ + ", minRefreshRate=" + minRefreshRate
+ + ", maxRefreshRate=" + maxRefreshRate);
+ }
+ break;
+ }
- int[] availableModes =
- filterModes(modes, width, height, minRefreshRate, maxRefreshRate);
- if (availableModes.length > 0) {
if (DEBUG) {
- Slog.w(TAG, "Found available modes=" + Arrays.toString(availableModes)
- + " with lowest priority considered "
+ Slog.w(TAG, "Couldn't find available modes with lowest priority set to "
+ Vote.priorityToString(lowestConsideredPriority)
- + " and constraints: "
+ + " and with the following constraints: "
+ "width=" + width
+ ", height=" + height
+ ", minRefreshRate=" + minRefreshRate
+ ", maxRefreshRate=" + maxRefreshRate);
}
- return availableModes;
+
+ // If we haven't found anything with the current set of votes, drop the
+ // current lowest priority vote.
+ lowestConsideredPriority++;
}
- if (DEBUG) {
- Slog.w(TAG, "Couldn't find available modes with lowest priority set to "
- + Vote.priorityToString(lowestConsideredPriority)
- + " and with the following constraints: "
- + "width=" + width
- + ", height=" + height
- + ", minRefreshRate=" + minRefreshRate
- + ", maxRefreshRate=" + maxRefreshRate);
+ int defaultModeId = defaultMode.getModeId();
+ if (availableModes.length > 0) {
+ defaultModeId = availableModes[0];
}
- // If we haven't found anything with the current set of votes, drop the current lowest
- // priority vote.
- lowestConsideredPriority++;
+ // filterModes function is going to filter the modes based on the voting system. If
+ // the application requests a given mode with preferredModeId function, it will be
+ // stored as the first and only element in available modes array.
+ return new DesiredDisplayConfigSpecs(defaultModeId,
+ new RefreshRateRange(minRefreshRate, maxRefreshRate), availableModes);
}
-
- // If we still haven't found anything that matches our current set of votes, just fall back
- // to the default mode.
- return new int[] { defaultMode.getModeId() };
}
private int[] filterModes(Display.Mode[] supportedModes,
@@ -403,6 +414,21 @@
}
}
+ @VisibleForTesting
+ void injectSupportedModesByDisplay(SparseArray<Display.Mode[]> supportedModesByDisplay) {
+ mSupportedModesByDisplay = supportedModesByDisplay;
+ }
+
+ @VisibleForTesting
+ void injectDefaultModeByDisplay(SparseArray<Display.Mode> defaultModeByDisplay) {
+ mDefaultModeByDisplay = defaultModeByDisplay;
+ }
+
+ @VisibleForTesting
+ void injectVotesByDisplay(SparseArray<SparseArray<Vote>> votesByDisplay) {
+ mVotesByDisplay = votesByDisplay;
+ }
+
/**
* Listens for changes to display mode coordination.
*/
@@ -452,7 +478,129 @@
}
}
- private static final class Vote {
+ /**
+ * Information about the min and max refresh rate DM would like to set the display to.
+ */
+ public static final class RefreshRateRange {
+ /**
+ * The lowest desired refresh rate.
+ */
+ public final float min;
+ /**
+ * The highest desired refresh rate.
+ */
+ public final float max;
+
+ public RefreshRateRange(float min, float max) {
+ if (min < 0 || max < 0 || min > max) {
+ Slog.e(TAG, "Wrong values for min and max when initializing RefreshRateRange : "
+ + min + " " + max);
+ this.min = this.max = 0;
+ return;
+ }
+ this.min = min;
+ this.max = max;
+ }
+
+ /**
+ * Checks whether the two objects have the same values.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof RefreshRateRange)) {
+ return false;
+ }
+
+ RefreshRateRange refreshRateRange = (RefreshRateRange) other;
+ return (min == refreshRateRange.min && max == refreshRateRange.max);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(min, max);
+ }
+
+ @Override
+ public String toString() {
+ return "(" + min + " " + max + ")";
+ }
+ }
+
+ /**
+ * Information about the desired configuration to be set by the system. Includes the default
+ * configuration ID, refresh rate range, and the list of policy decisions that influenced the
+ * choice.
+ */
+ public static final class DesiredDisplayConfigSpecs {
+ /**
+ * Default configuration ID. This is what system defaults to for all other settings, or
+ * if the refresh rate range is not available.
+ */
+ public final int defaultModeId;
+ /**
+ * The refresh rate range.
+ */
+ public final RefreshRateRange refreshRateRange;
+ /**
+ * For legacy reasons, keep a list of allowed configs.
+ * TODO(b/142507213): Re-assess whether the list of allowed configs is still necessary.
+ */
+ public final int[] allowedConfigs;
+
+ public DesiredDisplayConfigSpecs(int defaultModeId,
+ @NonNull RefreshRateRange refreshRateRange,
+ @NonNull int[] allowedConfigs) {
+ this.defaultModeId = defaultModeId;
+ this.refreshRateRange = refreshRateRange;
+ this.allowedConfigs = allowedConfigs;
+ }
+
+ /**
+ * Returns a string representation of the object.
+ */
+ @Override
+ public String toString() {
+ return "DesiredDisplayConfigSpecs(defaultModeId=" + defaultModeId
+ + ", refreshRateRange=" + refreshRateRange.toString()
+ + ", allowedConfigs=" + Arrays.toString(allowedConfigs) + ")";
+ }
+ /**
+ * Checks whether the two objects have the same values.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof DesiredDisplayConfigSpecs)) {
+ return false;
+ }
+
+ DesiredDisplayConfigSpecs desiredDisplayConfigSpecs =
+ (DesiredDisplayConfigSpecs) other;
+
+ if (defaultModeId != desiredDisplayConfigSpecs.defaultModeId) {
+ return false;
+ }
+ if (!refreshRateRange.equals(desiredDisplayConfigSpecs.refreshRateRange)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(defaultModeId, refreshRateRange);
+ }
+ }
+
+ @VisibleForTesting
+ static final class Vote {
// LOW_BRIGHTNESS votes for a single refresh rate like [60,60], [90,90] or null.
// If the higher voters result is a range, it will fix the rate to a single choice.
// It's used to avoid rate switch in certain conditions.
@@ -499,15 +647,10 @@
* The requested height of the display in pixels, or INVALID_SIZE;
*/
public final int height;
-
/**
- * The lowest desired refresh rate.
+ * Information about the min and max refresh rate DM would like to set the display to.
*/
- public final float minRefreshRate;
- /**
- * The highest desired refresh rate.
- */
- public final float maxRefreshRate;
+ public final RefreshRateRange refreshRateRange;
public static Vote forRefreshRates(float minRefreshRate, float maxRefreshRate) {
return new Vote(INVALID_SIZE, INVALID_SIZE, minRefreshRate, maxRefreshRate);
@@ -521,8 +664,8 @@
float minRefreshRate, float maxRefreshRate) {
this.width = width;
this.height = height;
- this.minRefreshRate = minRefreshRate;
- this.maxRefreshRate = maxRefreshRate;
+ this.refreshRateRange =
+ new RefreshRateRange(minRefreshRate, maxRefreshRate);
}
public static String priorityToString(int priority) {
@@ -547,11 +690,9 @@
@Override
public String toString() {
return "Vote{"
- + "width=" + width
- + ", height=" + height
- + ", minRefreshRate=" + minRefreshRate
- + ", maxRefreshRate=" + maxRefreshRate
- + "}";
+ + "width=" + width + ", height=" + height
+ + ", minRefreshRate=" + refreshRateRange.min
+ + ", maxRefreshRate=" + refreshRateRange.max + "}";
}
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index b03dc3b..1586473 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -173,6 +173,8 @@
private int mActiveModeId;
private boolean mActiveModeInvalid;
private int[] mAllowedModeIds;
+ private float mMinRefreshRate;
+ private float mMaxRefreshRate;
private boolean mAllowedModeIdsInvalid;
private int mActivePhysIndex;
private int[] mAllowedPhysIndexes;
@@ -623,7 +625,9 @@
}
@Override
- public void setAllowedDisplayModesLocked(int[] modes) {
+ public void setDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
+ float maxRefreshRate, int[] modes) {
+ updateDesiredDisplayConfigSpecs(defaultModeId, minRefreshRate, maxRefreshRate);
updateAllowedModesLocked(modes);
}
@@ -653,6 +657,7 @@
return true;
}
+ // TODO(b/142507213): Remove once refresh rates are plummed through to kernel.
public void updateAllowedModesLocked(int[] allowedModes) {
if (Arrays.equals(allowedModes, mAllowedModeIds) && !mAllowedModeIdsInvalid) {
return;
@@ -662,6 +667,38 @@
}
}
+ public void updateDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
+ float maxRefreshRate) {
+ if (minRefreshRate == mMinRefreshRate
+ && maxRefreshRate == mMaxRefreshRate
+ && defaultModeId == mDefaultModeId) {
+ return;
+ }
+ if (updateDesiredDisplayConfigSpecsInternalLocked(defaultModeId, minRefreshRate,
+ maxRefreshRate)) {
+ updateDeviceInfoLocked();
+ }
+ }
+
+ public boolean updateDesiredDisplayConfigSpecsInternalLocked(int defaultModeId,
+ float minRefreshRate, float maxRefreshRate) {
+ if (DEBUG) {
+ Slog.w(TAG, "updateDesiredDisplayConfigSpecsInternalLocked("
+ + "defaultModeId="
+ + Integer.toString(defaultModeId)
+ + ", minRefreshRate="
+ + Float.toString(minRefreshRate)
+ + ", maxRefreshRate="
+ + Float.toString(minRefreshRate));
+ }
+
+ final IBinder token = getDisplayTokenLocked();
+ SurfaceControl.setDesiredDisplayConfigSpecs(token, defaultModeId, minRefreshRate,
+ maxRefreshRate);
+ int activePhysIndex = SurfaceControl.getActiveConfig(token);
+ return updateActiveModeLocked(activePhysIndex);
+ }
+
public boolean updateAllowedModesInternalLocked(int[] allowedModes) {
if (DEBUG) {
Slog.w(TAG, "updateAllowedModesInternalLocked(allowedModes="
@@ -735,6 +772,8 @@
pw.println("mPhysicalDisplayId=" + mPhysicalDisplayId);
pw.println("mAllowedPhysIndexes=" + Arrays.toString(mAllowedPhysIndexes));
pw.println("mAllowedModeIds=" + Arrays.toString(mAllowedModeIds));
+ pw.println("mMinRefreshRate=" + mMinRefreshRate);
+ pw.println("mMaxRefreshRate=" + mMaxRefreshRate);
pw.println("mAllowedModeIdsInvalid=" + mAllowedModeIdsInvalid);
pw.println("mActivePhysIndex=" + mActivePhysIndex);
pw.println("mActiveModeId=" + mActiveModeId);
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index dcef998..f4b2dc8 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -352,11 +352,12 @@
// Set the color mode and allowed display mode.
if (device == mPrimaryDisplayDevice) {
- device.setAllowedDisplayModesLocked(mAllowedDisplayModes);
+ // See ag/9588196 for correct values.
+ device.setDesiredDisplayConfigSpecs(0, 60, 60, mAllowedDisplayModes);
device.setRequestedColorModeLocked(mRequestedColorMode);
} else {
// Reset to default for non primary displays
- device.setAllowedDisplayModesLocked(new int[] {0});
+ device.setDesiredDisplayConfigSpecs(0, 60, 60, new int[] {0});
device.setRequestedColorModeLocked(0);
}
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 60cfbd0..739dd64 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -315,16 +315,9 @@
}
@Override
- public void setAllowedDisplayModesLocked(int[] modes) {
- final int id;
- if (modes.length > 0) {
- // The allowed modes should be ordered by preference, so just use the first mode
- // here.
- id = modes[0];
- } else {
- // If we don't have any allowed modes, just use the default mode.
- id = 0;
- }
+ public void setDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
+ float maxRefreshRate, int[] modes) {
+ final int id = defaultModeId;
int index = -1;
if (id == 0) {
// Use the default.
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index a4e7ac4..83b6215 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -181,6 +181,7 @@
private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
private static final String PREV_SYNTHETIC_PASSWORD_HANDLE_KEY = "prev-sp-handle";
private static final String SYNTHETIC_PASSWORD_UPDATE_TIME_KEY = "sp-handle-ts";
+ private static final String USER_SERIAL_NUMBER_KEY = "serial-number";
// No challenge provided
private static final int CHALLENGE_NONE = 0;
@@ -661,6 +662,34 @@
}
/**
+ * Clean up states associated with the given user, in case the userId is reused but LSS didn't
+ * get a chance to do cleanup previously during ACTION_USER_REMOVED.
+ *
+ * Internally, LSS stores serial number for each user and check it against the current user's
+ * serial number to determine if the userId is reused and invoke cleanup code.
+ */
+ private void cleanupDataForReusedUserIdIfNecessary(int userId) {
+ if (userId == UserHandle.USER_SYSTEM) {
+ // Short circuit as we never clean up user 0.
+ return;
+ }
+ // Serial number is never reusued, so we can use it as a distinguisher for user Id reuse.
+ int serialNumber = mUserManager.getUserSerialNumber(userId);
+
+ int storedSerialNumber = getIntUnchecked(USER_SERIAL_NUMBER_KEY, -1, userId);
+ if (storedSerialNumber != serialNumber) {
+ // If LockSettingsStorage does not have a copy of the serial number, it could be either
+ // this is a user created before the serial number recording logic is introduced, or
+ // the user does not exist or was removed and cleaned up properly. In either case, don't
+ // invoke removeUser().
+ if (storedSerialNumber != -1) {
+ removeUser(userId, /* unknownUser */ true);
+ }
+ setIntUnchecked(USER_SERIAL_NUMBER_KEY, serialNumber, userId);
+ }
+ }
+
+ /**
* Check if profile got unlocked but the keystore is still locked. This happens on full disk
* encryption devices since the profile may not yet be running when we consider unlocking it
* during the normal flow. In this case unlock the keystore for the profile.
@@ -684,6 +713,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
+ cleanupDataForReusedUserIdIfNecessary(userId);
ensureProfileKeystoreUnlocked(userId);
// Hide notification first, as tie managed profile lock takes time
hideEncryptionNotification(new UserHandle(userId));
@@ -729,9 +759,6 @@
if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
// Notify keystore that a new user was added.
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
- if (userHandle > UserHandle.USER_SYSTEM) {
- removeUser(userHandle, /* unknownUser= */ true);
- }
final KeyStore ks = KeyStore.getInstance();
final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
final int parentHandle = parentInfo != null ? parentInfo.id : -1;
@@ -1066,6 +1093,10 @@
setStringUnchecked(key, userId, Long.toString(value));
}
+ private void setIntUnchecked(String key, int value, int userId) {
+ setStringUnchecked(key, userId, Integer.toString(value));
+ }
+
@Override
public void setString(String key, String value, int userId) {
checkWritePermission(userId);
@@ -1104,6 +1135,11 @@
return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
}
+ private int getIntUnchecked(String key, int defaultValue, int userId) {
+ String value = getStringUnchecked(key, null, userId);
+ return TextUtils.isEmpty(value) ? defaultValue : Integer.parseInt(value);
+ }
+
@Override
public String getString(String key, String defaultValue, int userId) {
checkReadPermission(key, userId);
@@ -2171,8 +2207,8 @@
}
private void removeUser(int userId, boolean unknownUser) {
+ Slog.i(TAG, "RemoveUser: " + userId);
mSpManager.removeUser(userId);
- mStorage.removeUser(userId);
mStrongAuth.removeUser(userId);
tryRemoveUserFromSpCacheLater(userId);
@@ -2183,6 +2219,9 @@
if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
removeKeystoreProfileKey(userId);
}
+ // Clean up storage last, this is to ensure that cleanupDataForReusedUserIdIfNecessary()
+ // can make the assumption that no USER_SERIAL_NUMBER_KEY means user is fully removed.
+ mStorage.removeUser(userId);
}
private void removeKeystoreProfileKey(int targetUserId) {
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 91c9253..9a49c16 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
+import android.os.Bundle;
import java.util.Objects;
@@ -29,7 +30,7 @@
final ComponentName mComponentName;
final String mUniqueId;
- private Callback mCallback;
+ Callback mCallback;
private MediaRoute2ProviderInfo mProviderInfo;
MediaRoute2Provider(@NonNull ComponentName componentName) {
@@ -77,6 +78,9 @@
}
public interface Callback {
- void onProviderStateChanged(MediaRoute2Provider provider);
+ void onProviderStateChanged(@Nullable MediaRoute2Provider provider);
+ void onRouteSelected(@NonNull MediaRoute2ProviderProxy provider,
+ @NonNull String clientPackageName, @NonNull MediaRoute2Info route,
+ @Nullable Bundle controlHints, int seq);
}
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index 3b6580a..a5abb18 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -26,6 +26,7 @@
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
import android.media.MediaRoute2ProviderService;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
@@ -253,6 +254,20 @@
setAndNotifyProviderInfo(info);
}
+ private void onRouteSelected(Connection connection,
+ String packageName, String routeId, Bundle controlHints, int seq) {
+ if (mActiveConnection != connection) {
+ return;
+ }
+ MediaRoute2ProviderInfo providerInfo = getProviderInfo();
+ MediaRoute2Info route = (providerInfo == null) ? null : providerInfo.getRoute(routeId);
+ if (route == null) {
+ Slog.w(TAG, this + ": Unknown route " + routeId + " is selected from remove provider");
+ return;
+ }
+ mCallback.onRouteSelected(this, packageName, route, controlHints, seq);
+ }
+
private void disconnect() {
if (mActiveConnection != null) {
mConnectionReady = false;
@@ -341,6 +356,11 @@
void postProviderInfoUpdated(MediaRoute2ProviderInfo info) {
mHandler.post(() -> onProviderInfoUpdated(Connection.this, info));
}
+
+ void postRouteSelected(String packageName, String routeId, Bundle controlHints, int seq) {
+ mHandler.post(() -> onRouteSelected(Connection.this,
+ packageName, routeId, controlHints, seq));
+ }
}
private static final class ProviderClient extends IMediaRoute2ProviderClient.Stub {
@@ -361,5 +381,15 @@
connection.postProviderInfoUpdated(info);
}
}
+
+ @Override
+ public void notifyRouteSelected(String packageName, String routeId,
+ Bundle controlHints, int seq) {
+ Connection connection = mConnectionRef.get();
+ if (connection != null) {
+ connection.postRouteSelected(packageName, routeId, controlHints, seq);
+ }
+ }
+
}
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 2cf920d..2c478df 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -77,7 +77,7 @@
@GuardedBy("mLock")
private int mCurrentUserId = -1;
@GuardedBy("mLock")
- private int mSelectRouteRequestSequenceNumber = 0;
+ private int mSelectRouteRequestSequenceNumber = 1;
MediaRouter2ServiceImpl(Context context) {
mContext = context;
@@ -218,7 +218,7 @@
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- requestSelectRoute2Locked(mAllClientRecords.get(client.asBinder()), route);
+ requestSelectRoute2Locked(mAllClientRecords.get(client.asBinder()), false, route);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -399,10 +399,12 @@
}
}
- private void requestSelectRoute2Locked(ClientRecord clientRecord, MediaRoute2Info route) {
+ private void requestSelectRoute2Locked(ClientRecord clientRecord, boolean selectedByManager,
+ MediaRoute2Info route) {
if (clientRecord != null) {
MediaRoute2Info oldRoute = clientRecord.mSelectedRoute;
clientRecord.mSelectingRoute = route;
+ clientRecord.mIsManagerSelecting = selectedByManager;
UserHandler handler = clientRecord.mUserRecord.mHandler;
//TODO: Handle transfer instead of unselect and select
@@ -417,7 +419,6 @@
handler.sendMessage(obtainMessage(
UserHandler::requestSelectRoute, handler, clientRecord.mPackageName,
route, seq));
-
// Remove all previous timeout messages
for (int previousSeq : clientRecord.mSelectRouteSequenceNumbers) {
clientRecord.mUserRecord.mHandler.removeMessages(previousSeq);
@@ -543,7 +544,7 @@
Slog.w(TAG, "Ignoring route selection for unknown client.");
}
if (clientRecord != null && managerRecord.mTrusted) {
- requestSelectRoute2Locked(clientRecord, route);
+ requestSelectRoute2Locked(clientRecord, true, route);
}
}
}
@@ -656,7 +657,9 @@
public final UserRecord mUserRecord;
public final String mPackageName;
public final List<Integer> mSelectRouteSequenceNumbers;
+
public List<String> mControlCategories;
+ public boolean mIsManagerSelecting;
public MediaRoute2Info mSelectingRoute;
public MediaRoute2Info mSelectedRoute;
@@ -802,9 +805,8 @@
sendMessage(PooledLambda.obtainMessage(UserHandler::updateProvider, this, provider));
}
- // TODO: When introducing MediaRoute2ProviderService#sendControlHints(),
- // Make this method to be called.
- public void onRouteSelectionRequestHandled(@NonNull MediaRoute2ProviderProxy provider,
+ @Override
+ public void onRouteSelected(@NonNull MediaRoute2ProviderProxy provider,
String clientPackageName, MediaRoute2Info route, Bundle controlHints, int seq) {
sendMessage(PooledLambda.obtainMessage(
UserHandler::updateSelectedRoute, this, provider, clientPackageName, route,
@@ -917,6 +919,8 @@
return;
}
+ //TODO: handle a case such that controlHints is null. (How should we notify MR2?)
+
if (clientRecord.mSelectingRoute == null || !TextUtils.equals(
clientRecord.mSelectingRoute.getUniqueId(), selectedRoute.getUniqueId())) {
Log.w(TAG, "Ignoring invalid updateSelectedRoute call. selectingRoute="
@@ -929,7 +933,9 @@
notifyRouteSelectedToClient(((Client2Record) clientRecord).mClient,
selectedRoute,
- MediaRouter2.SELECT_REASON_USER_SELECTED,
+ clientRecord.mIsManagerSelecting
+ ? MediaRouter2.SELECT_REASON_SYSTEM_SELECTED :
+ MediaRouter2.SELECT_REASON_USER_SELECTED,
controlHints);
updateClientUsage(clientRecord);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 863991c..3c76c67 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -8268,7 +8268,7 @@
try {
assistant.onAllowedAdjustmentsChanged();
} catch (RemoteException ex) {
- Slog.e(TAG, "unable to notify assistant (capabilities): " + assistant, ex);
+ Slog.e(TAG, "unable to notify assistant (capabilities): " + info, ex);
}
}
@@ -8278,7 +8278,7 @@
try {
assistant.onNotificationsSeen(keys);
} catch (RemoteException ex) {
- Slog.e(TAG, "unable to notify assistant (seen): " + assistant, ex);
+ Slog.e(TAG, "unable to notify assistant (seen): " + info, ex);
}
}
@@ -8584,7 +8584,7 @@
listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
} catch (RemoteException ex) {
Slog.e(TAG, "unable to notify listener "
- + "(hideSilentStatusIcons): " + listener, ex);
+ + "(hideSilentStatusIcons): " + info, ex);
}
});
}
@@ -8877,7 +8877,7 @@
try {
listener.onNotificationPosted(sbnHolder, rankingUpdate);
} catch (RemoteException ex) {
- Slog.e(TAG, "unable to notify listener (posted): " + listener, ex);
+ Slog.e(TAG, "unable to notify listener (posted): " + info, ex);
}
}
@@ -8891,7 +8891,7 @@
try {
listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
} catch (RemoteException ex) {
- Slog.e(TAG, "unable to notify listener (removed): " + listener, ex);
+ Slog.e(TAG, "unable to notify listener (removed): " + info, ex);
}
}
@@ -8901,7 +8901,7 @@
try {
listener.onNotificationRankingUpdate(rankingUpdate);
} catch (RemoteException ex) {
- Slog.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
+ Slog.e(TAG, "unable to notify listener (ranking update): " + info, ex);
}
}
@@ -8910,7 +8910,7 @@
try {
listener.onListenerHintsChanged(hints);
} catch (RemoteException ex) {
- Slog.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
+ Slog.e(TAG, "unable to notify listener (listener hints): " + info, ex);
}
}
@@ -8920,7 +8920,7 @@
try {
listener.onInterruptionFilterChanged(interruptionFilter);
} catch (RemoteException ex) {
- Slog.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
+ Slog.e(TAG, "unable to notify listener (interruption filter): " + info, ex);
}
}
@@ -8931,7 +8931,7 @@
try {
listener.onNotificationChannelModification(pkg, user, channel, modificationType);
} catch (RemoteException ex) {
- Slog.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
+ Slog.e(TAG, "unable to notify listener (channel changed): " + info, ex);
}
}
@@ -8942,7 +8942,7 @@
try {
listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
} catch (RemoteException ex) {
- Slog.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
+ Slog.e(TAG, "unable to notify listener (channel group changed): " + info, ex);
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index faff394..05f62b2 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3210,6 +3210,13 @@
flags |= UserInfo.FLAG_EPHEMERAL;
}
+ // Always clear EPHEMERAL for pre-created users, otherwise the storage key
+ // won't be persisted. The flag will be re-added (if needed) when the
+ // pre-created user is "converted" to a normal user.
+ if (preCreate) {
+ flags &= ~UserInfo.FLAG_EPHEMERAL;
+ }
+
userInfo = new UserInfo(userId, name, null, flags, userType);
userInfo.serialNumber = mNextSerialNumber++;
userInfo.creationTime = getCreationTime();
@@ -4428,6 +4435,7 @@
pw.println(" Supports switchable users: " + UserManager.supportsMultipleUsers());
pw.println(" All guests ephemeral: " + Resources.getSystem().getBoolean(
com.android.internal.R.bool.config_guestUserEphemeral));
+ pw.println(" Force ephemeral users: " + mForceEphemeralUsers);
pw.println(" Is split-system user: " + UserManager.isSplitSystemUser());
pw.println(" Is headless-system mode: " + UserManager.isHeadlessSystemUserMode());
pw.println(" User version: " + mUserVersion);
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index 6abfbdc..0a6a435 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -85,28 +85,30 @@
* System Property whether to only install system packages on a user if they're whitelisted for
* that user type. These are flags and can be freely combined.
* <ul>
- * <li> 0 (0b000) - disable whitelist (install all system packages; no logging)</li>
- * <li> 1 (0b001) - enforce (only install system packages if they are whitelisted)</li>
- * <li> 2 (0b010) - log (log when a non-whitelisted package is run)</li>
- * <li> 4 (0b100) - implicitly whitelist any package not mentioned in the whitelist</li>
- * <li>-1 - use device default (as defined in res/res/values/config.xml)</li>
+ * <li> 0 (0b0000) - disable whitelist (install all system packages; no logging)</li>
+ * <li> 1 (0b0001) - enforce (only install system packages if they are whitelisted)</li>
+ * <li> 2 (0b0010) - log (log when a non-whitelisted package is run)</li>
+ * <li> 4 (0b0100) - implicitly whitelist any package not mentioned in the whitelist</li>
+ * <li> 8 (0b1000) - ignore OTAs (don't install system packages during OTAs)</li>
+ * <li>-1 - use device default (as defined in res/res/values/config.xml)</li>
* </ul>
* Note: This list must be kept current with config_userTypePackageWhitelistMode in
* frameworks/base/core/res/res/values/config.xml
*/
static final String PACKAGE_WHITELIST_MODE_PROP = "persist.debug.user.package_whitelist_mode";
static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0;
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0b001;
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0b010;
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0b100;
+ static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0b0001;
+ static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0b0010;
+ static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0b0100;
+ static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA = 0b1000;
static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT = -1;
@IntDef(flag = true, prefix = "USER_TYPE_PACKAGE_WHITELIST_MODE_", value = {
USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE,
USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE,
- USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE,
USER_TYPE_PACKAGE_WHITELIST_MODE_LOG,
USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST,
+ USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA,
})
@Retention(RetentionPolicy.SOURCE)
public @interface PackageWhitelistMode {}
@@ -169,11 +171,17 @@
boolean installWhitelistedSystemPackages(boolean isFirstBoot, boolean isUpgrade) {
final int mode = getWhitelistMode();
checkWhitelistedSystemPackages(mode);
- if (!isUpgrade && !isFirstBoot) {
+ final boolean isConsideredUpgrade = isUpgrade && !isIgnoreOtaMode(mode);
+ if (!isConsideredUpgrade && !isFirstBoot) {
+ return false;
+ }
+ if (isFirstBoot && !isEnforceMode(mode)) {
+ // Note that if !isEnforceMode, we nonetheless still install packages if isUpgrade
+ // in order to undo any previous non-installing. isFirstBoot lacks this requirement.
return false;
}
Slog.i(TAG, "Reviewing whitelisted packages due to "
- + (isFirstBoot ? "[firstBoot]" : "") + (isUpgrade ? "[upgrade]" : ""));
+ + (isFirstBoot ? "[firstBoot]" : "") + (isConsideredUpgrade ? "[upgrade]" : ""));
final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
// Install/uninstall system packages per user.
for (int userId : mUm.getUserIds()) {
@@ -185,7 +193,7 @@
final boolean install =
(userWhitelist == null || userWhitelist.contains(pkg.packageName))
&& !pkg.applicationInfo.hiddenUntilInstalled;
- if (isUpgrade && !isFirstBoot && !install) {
+ if (isConsideredUpgrade && !isFirstBoot && !install) {
return; // To be careful, we don’t uninstall apps during OTAs
}
final boolean changed = pmInt.setInstalled(pkg, userId, install);
@@ -245,6 +253,19 @@
}
/**
+ * Whether to ignore OTAs, and therefore not install missing system packages during OTAs.
+ * <p>Note:
+ * If in this mode, old system packages will not be installed on pre-existing users during OTAs.
+ * Any system packages that had not been installed at the time of the user's creation,
+ * due to {@link UserSystemPackageInstaller}'s previous actions, will therefore continue to
+ * remain uninstalled, even if the whitelist (or enforcement mode) now declares that they should
+ * be.
+ */
+ boolean isIgnoreOtaMode() {
+ return isIgnoreOtaMode(getWhitelistMode());
+ }
+
+ /**
* Whether to log a warning concerning potential problems with the user-type package whitelist.
*/
boolean isLogMode() {
@@ -264,6 +285,11 @@
return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE) != 0;
}
+ /** See {@link #isIgnoreOtaMode()}. */
+ private static boolean isIgnoreOtaMode(int whitelistMode) {
+ return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA) != 0;
+ }
+
/** See {@link #isLogMode()}. */
private static boolean isLogMode(int whitelistMode) {
return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_LOG) != 0;
@@ -536,6 +562,7 @@
pw.print(isEnforceMode(mode) ? " (enforced)" : "");
pw.print(isLogMode(mode) ? " (logged)" : "");
pw.print(isImplicitWhitelistMode(mode) ? " (implicit)" : "");
+ pw.print(isIgnoreOtaMode(mode) ? " (ignore OTAs)" : "");
pw.println();
pw.print(prefix); pw.println("Legend");
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 01f29dc..00779ec 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -67,6 +67,7 @@
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -82,6 +83,7 @@
class RollbackManagerServiceImpl extends IRollbackManager.Stub {
private static final String TAG = "RollbackManager";
+ private static final boolean LOCAL_LOGV = false;
// Rollbacks expire after 14 days.
private static final long DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS =
@@ -220,6 +222,9 @@
if (Intent.ACTION_CANCEL_ENABLE_ROLLBACK.equals(intent.getAction())) {
int token = intent.getIntExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN, -1);
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "broadcast=ACTION_CANCEL_ENABLE_ROLLBACK token=" + token);
+ }
synchronized (mLock) {
for (NewRollback rollback : mNewRollbacks) {
if (rollback.hasToken(token)) {
@@ -269,10 +274,17 @@
String action = intent.getAction();
if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
String packageName = intent.getData().getSchemeSpecificPart();
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "broadcast=ACTION_PACKAGE_REPLACED" + " pkg=" + packageName);
+ }
onPackageReplaced(packageName);
}
if (Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
String packageName = intent.getData().getSchemeSpecificPart();
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "broadcast=ACTION_PACKAGE_FULLY_REMOVED"
+ + " pkg=" + packageName);
+ }
onPackageFullyRemoved(packageName);
}
}
@@ -359,7 +371,7 @@
*/
private void commitRollbackInternal(int rollbackId, List<VersionedPackage> causePackages,
String callerPackageName, IntentSender statusReceiver) {
- Slog.i(TAG, "Initiating rollback");
+ Slog.i(TAG, "commitRollback id=" + rollbackId + " caller=" + callerPackageName);
Rollback rollback = getRollbackForId(rollbackId);
if (rollback == null) {
@@ -444,6 +456,9 @@
}
void onUnlockUser(int userId) {
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "onUnlockUser id=" + userId);
+ }
// In order to ensure that no package begins running while a backup or restore is taking
// place, onUnlockUser must remain blocked until all pending backups and restores have
// completed.
@@ -611,6 +626,9 @@
if (!now.isBefore(
rollbackTimestamp
.plusMillis(mRollbackLifetimeDurationInMillis))) {
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "runExpiration id=" + rollback.info.getRollbackId());
+ }
iter.remove();
rollback.delete(mAppDataRollbackHelper);
} else if (oldest == null || oldest.isAfter(rollbackTimestamp)) {
@@ -675,6 +693,10 @@
*/
private boolean enableRollback(
int installFlags, File newPackageCodePath, @UserIdInt int user, int token) {
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "enableRollback user=" + user + " token=" + token
+ + " path=" + newPackageCodePath.getAbsolutePath());
+ }
// Find the session id associated with this install.
// TODO: It would be nice if package manager or package installer told
@@ -838,6 +860,10 @@
}
private void snapshotUserDataInternal(String packageName, int[] userIds) {
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "snapshotUserData pkg=" + packageName
+ + " users=" + Arrays.toString(userIds));
+ }
synchronized (mLock) {
// staged installs
for (int i = 0; i < mRollbacks.size(); i++) {
@@ -854,6 +880,10 @@
private void restoreUserDataInternal(
String packageName, int[] userIds, int appId, String seInfo) {
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "restoreUserData pkg=" + packageName
+ + " users=" + Arrays.toString(userIds));
+ }
synchronized (mLock) {
for (int i = 0; i < mRollbacks.size(); ++i) {
Rollback rollback = mRollbacks.get(i);
@@ -1041,6 +1071,9 @@
@Override
public void onFinished(int sessionId, boolean success) {
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "SessionCallback.onFinished id=" + sessionId + " success=" + success);
+ }
NewRollback newRollback;
synchronized (mLock) {
newRollback = getNewRollbackForPackageSessionLocked(sessionId);
@@ -1070,6 +1103,10 @@
*/
private Rollback completeEnableRollback(NewRollback newRollback, boolean success) {
Rollback rollback = newRollback.rollback;
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "completeEnableRollback id="
+ + rollback.info.getRollbackId() + " success=" + success);
+ }
if (!success) {
// The install session was aborted, clean up the pending install.
rollback.delete(mAppDataRollbackHelper);
@@ -1108,6 +1145,9 @@
@GuardedBy("rollback.getLock")
private void makeRollbackAvailable(Rollback rollback) {
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "makeRollbackAvailable id=" + rollback.info.getRollbackId());
+ }
rollback.makeAvailable();
// TODO(zezeozue): Provide API to explicitly start observing instead
@@ -1280,6 +1320,11 @@
final Rollback rollback;
int parentSessionId = parentSession.getSessionId();
+ if (LOCAL_LOGV) {
+ Slog.v(TAG, "createNewRollback id=" + rollbackId
+ + " user=" + userId + " installer=" + installerPackageName);
+ }
+
if (parentSession.isStaged()) {
rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId, userId,
installerPackageName);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 0930975..7f5b403 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -149,6 +149,6 @@
}
private void enforceSuggestManualTimePermission() {
- mContext.enforceCallingPermission(android.Manifest.permission.SET_TIME, "set time");
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SET_TIME, "set time");
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 45e3c68..db94cf1 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -73,7 +73,9 @@
import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.protolog.common.ProtoLog;
import java.io.PrintWriter;
@@ -617,7 +619,7 @@
continue;
}
- stack.findTaskLocked(r, mTmpFindTaskResult);
+ mTmpFindTaskResult.process(r, stack);
// It is possible to have tasks in multiple stacks with the same root affinity, so
// we should keep looking after finding an affinity match to see if there is a
// better match in another stack. Also, task affinity isn't a good enough reason
@@ -1190,12 +1192,11 @@
}
boolean isUidPresent(int uid) {
- for (ActivityStack stack : mStacks) {
- if (stack.isUidPresent(uid)) {
- return true;
- }
- }
- return false;
+ final PooledPredicate p = PooledLambda.obtainPredicate(
+ ActivityRecord::isUid, PooledLambda.__(ActivityRecord.class), uid);
+ final boolean isUidPresent = mDisplayContent.getActivity(p) != null;
+ p.recycle();
+ return isUidPresent;
}
/**
@@ -1291,12 +1292,16 @@
/** Update and get all UIDs that are present on the display and have access to it. */
IntArray getPresentUIDs() {
mDisplayAccessUIDs.clear();
- for (ActivityStack stack : mStacks) {
- stack.getPresentUIDs(mDisplayAccessUIDs);
- }
+ final PooledConsumer c = PooledLambda.obtainConsumer(ActivityDisplay::addActivityUid,
+ PooledLambda.__(ActivityRecord.class), mDisplayAccessUIDs);
+ mDisplayContent.forAllActivities(c);
+ c.recycle();
return mDisplayAccessUIDs;
}
+ private static void addActivityUid(ActivityRecord r, IntArray uids) {
+ uids.add(r.getUid());
+ }
/**
* Checks if system decorations should be shown on this display.
*
@@ -1449,22 +1454,16 @@
return null;
}
- final ArrayList<Task> tasks = mHomeStack.getAllTasks();
- for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = tasks.get(taskNdx);
- if (!task.isActivityTypeHome()) {
- continue;
- }
+ final PooledPredicate p = PooledLambda.obtainPredicate(
+ ActivityDisplay::isHomeActivityForUser, PooledLambda.__(ActivityRecord.class),
+ userId);
+ final ActivityRecord r = mHomeStack.getActivity(p);
+ p.recycle();
+ return r;
+ }
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = task.getChildAt(activityNdx);
- if (r.isActivityTypeHome()
- && ((userId == UserHandle.USER_ALL) || (r.mUserId == userId))) {
- return r;
- }
- }
- }
- return null;
+ private static boolean isHomeActivityForUser(ActivityRecord r, int userId) {
+ return r.isActivityTypeHome() && (userId == UserHandle.USER_ALL || r.mUserId == userId);
}
boolean isSleeping() {
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 9fa5d9f1..a593ef8 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -546,13 +546,7 @@
/** @return {@code true} if the given task has an activity will be drawn. */
private static boolean hasActivityToBeDrawn(Task t) {
- for (int i = t.getChildCount() - 1; i >= 0; --i) {
- final ActivityRecord r = t.getChildAt(i);
- if (r.mVisibleRequested && !r.mDrawn && !r.finishing) {
- return true;
- }
- }
- return false;
+ return t.forAllActivities((r) -> r.mVisibleRequested && !r.mDrawn && !r.finishing);
}
private void checkVisibility(Task t, ActivityRecord r) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 3de3578..6af5025 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -301,6 +301,9 @@
import com.android.internal.content.ReferrerIntent;
import com.android.internal.util.ToBooleanFunction;
import com.android.internal.util.XmlUtils;
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledFunction;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.AttributeCache;
import com.android.server.LocalServices;
import com.android.server.am.AppTimeTracker;
@@ -695,12 +698,6 @@
}
}
- void dump(PrintWriter pw, String prefix) {
- }
-
- /**
- * Copied from old AppWindowToken.
- */
@Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
final long now = SystemClock.uptimeMillis();
@@ -940,6 +937,10 @@
}
}
+ void setAppTimeTracker(AppTimeTracker att) {
+ appTimeTracker = att;
+ }
+
/** Update the saved state of an activity. */
void setSavedState(@Nullable Bundle savedState) {
mIcicle = savedState;
@@ -1167,6 +1168,15 @@
super.onParentChanged(newParent, oldParent);
+ if (isPersistable()) {
+ if (oldTask != null) {
+ mAtmService.notifyTaskPersisterLocked(oldTask, false);
+ }
+ if (newTask != null) {
+ mAtmService.notifyTaskPersisterLocked(newTask, false);
+ }
+ }
+
if (oldParent == null && newParent != null) {
// First time we are adding the activity to the system.
mVoiceInteraction = newTask.voiceSession != null;
@@ -1261,12 +1271,8 @@
if (prevDc.mFocusedApp == this) {
prevDc.setFocusedApp(null);
- final ActivityStack stack = dc.getTopStack();
- if (stack != null) {
- final Task task = stack.getTopChild();
- if (task != null && task.getTopChild() == this) {
- dc.setFocusedApp(this);
- }
+ if (dc.getTopMostActivity() == this) {
+ dc.setFocusedApp(this);
}
}
@@ -1520,7 +1526,13 @@
hasBeenLaunched = false;
mStackSupervisor = supervisor;
- taskAffinity = aInfo.taskAffinity;
+ // b/35954083: Limit task affinity to uid to avoid various issues associated with sharing
+ // affinity across uids.
+ final String uid = Integer.toString(info.applicationInfo.uid);
+ if (info.taskAffinity != null && !info.taskAffinity.startsWith(uid)) {
+ info.taskAffinity = uid + ":" + info.taskAffinity;
+ }
+ taskAffinity = info.taskAffinity;
stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0;
nonLocalizedLabel = aInfo.nonLocalizedLabel;
labelRes = aInfo.labelRes;
@@ -1798,7 +1810,7 @@
// task snapshot starting window.
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
}
- return snapshot == null ? STARTING_WINDOW_TYPE_SPLASH_SCREEN
+ return snapshot == null ? STARTING_WINDOW_TYPE_NONE
: snapshotOrientationSameAsTask(snapshot) || fromRecents
? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
} else {
@@ -2206,7 +2218,7 @@
OP_PICTURE_IN_PICTURE, info.applicationInfo.uid, packageName) == MODE_ALLOWED;
}
- boolean isAlwaysFocusable() {
+ private boolean isAlwaysFocusable() {
return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
}
@@ -2263,23 +2275,28 @@
return true;
}
+ void finishIfSubActivity(ActivityRecord parent, String otherResultWho, int otherRequestCode) {
+ if (resultTo != parent
+ || requestCode != otherRequestCode
+ || !Objects.equals(resultWho, otherResultWho)) return;
+
+ finishIfPossible("request-sub", false /* oomAdj */);
+ }
+
/** Finish all activities in the task with the same affinity as this one. */
- void finishActivityAffinity() {
- final ArrayList<ActivityRecord> activities = task.mChildren;
- for (int index = activities.indexOf(this); index >= 0; --index) {
- final ActivityRecord cur = activities.get(index);
- if (!Objects.equals(cur.taskAffinity, taskAffinity)) {
- break;
- }
- cur.finishIfPossible("request-affinity", true /* oomAdj */);
- }
+ boolean finishIfSameAffinity(ActivityRecord r) {
+ // End search once we get to the activity that doesn't have the same affinity.
+ if (!Objects.equals(r.taskAffinity, taskAffinity)) return true;
+
+ r.finishIfPossible("request-affinity", true /* oomAdj */);
+ return false;
}
/**
* Sets the result for activity that started this one, clears the references to activities
* started for result from this one, and clears new intents.
*/
- void finishActivityResults(int resultCode, Intent resultData) {
+ private void finishActivityResults(int resultCode, Intent resultData) {
// Send the result if needed
if (resultTo != null) {
if (DEBUG_RESULTS) {
@@ -2378,14 +2395,12 @@
final Task task = getTask();
EventLogTags.writeWmFinishActivity(mUserId, System.identityHashCode(this),
task.mTaskId, shortComponentName, reason);
- final ArrayList<ActivityRecord> activities = task.mChildren;
- final int index = activities.indexOf(this);
- if (index < (task.getChildCount() - 1)) {
+ ActivityRecord next = task.getActivityAbove(this);
+ if (next != null) {
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
// If the caller asked that this activity (and all above it)
// be cleared when the task is reset, don't lose that information,
// but propagate it up to the next activity.
- final ActivityRecord next = task.getChildAt(index + 1);
next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
}
}
@@ -2403,7 +2418,7 @@
} else {
// Only move the next stack to top in its display.
final ActivityDisplay display = stack.getDisplay();
- final ActivityRecord next = display.topRunningActivity();
+ next = display.topRunningActivity();
if (next != null) {
display.positionChildAtTop(next.getActivityStack(),
false /* includingParents */, "finish-display-top");
@@ -2413,7 +2428,8 @@
finishActivityResults(resultCode, resultData);
- final boolean endTask = index <= 0 && !task.isClearingToReuseTask();
+ final boolean endTask = task.getActivityBelow(this) == null
+ && !task.isClearingToReuseTask();
final int transit = endTask ? TRANSIT_TASK_CLOSE : TRANSIT_ACTIVITY_CLOSE;
if (isState(RESUMED)) {
if (endTask) {
@@ -2473,16 +2489,13 @@
// sync with the activity visibility being set for this finishing activity above.
// In this case, we can set the visibility of all the task overlay activities when
// we detect the last one is finishing to keep them in sync.
- if (task.onlyHasTaskOverlayActivities(true /* excludeFinishing */)) {
- for (int i = task.getChildCount() - 1; i >= 0 ; --i) {
- final ActivityRecord taskOverlay = task.getChildAt(i);
- if (!taskOverlay.mTaskOverlay) {
- continue;
- }
- taskOverlay.prepareActivityHideTransitionAnimation(transit);
- }
+ if (task.onlyHasTaskOverlayActivities(false /* includeFinishing */)) {
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ ActivityRecord::prepareActivityHideTransitionAnimationIfOvarlay,
+ PooledLambda.__(ActivityRecord.class), transit);
+ task.forAllActivities(c);
+ c.recycle();
}
-
return removedActivity ? FINISH_RESULT_REMOVED : FINISH_RESULT_REQUESTED;
} else {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + this);
@@ -2494,6 +2507,12 @@
}
}
+ private void prepareActivityHideTransitionAnimationIfOvarlay(int transit) {
+ if (mTaskOverlay) {
+ prepareActivityHideTransitionAnimation(transit);
+ }
+ }
+
private void prepareActivityHideTransitionAnimation(int transit) {
final DisplayContent dc = getDisplay().mDisplayContent;
dc.prepareAppTransition(transit, false);
@@ -3265,15 +3284,16 @@
* immediately finishes after, so we have to transfer T to M.
*/
void transferStartingWindowFromHiddenAboveTokenIfNeeded() {
- for (int i = task.mChildren.size() - 1; i >= 0; i--) {
- final ActivityRecord fromActivity = task.mChildren.get(i);
- if (fromActivity == this) {
- return;
- }
- if (!fromActivity.mVisibleRequested && transferStartingWindow(fromActivity.token)) {
- return;
- }
- }
+ final PooledFunction p = PooledLambda.obtainFunction(ActivityRecord::transferStartingWindow,
+ this, PooledLambda.__(ActivityRecord.class));
+ task.forAllActivities(p);
+ p.recycle();
+ }
+
+ private boolean transferStartingWindow(ActivityRecord fromActivity) {
+ if (fromActivity == this) return true;
+
+ return !fromActivity.mVisibleRequested && transferStartingWindow(fromActivity.token);
}
void checkKeyguardFlagsChanged() {
@@ -3345,7 +3365,7 @@
if (!inPinnedWindowingMode() && (mShowWhenLocked || containsShowWhenLockedWindow())) {
return true;
} else if (mInheritShownWhenLocked) {
- final ActivityRecord r = getActivityBelow();
+ final ActivityRecord r = task.getActivityBelow(this);
return r != null && !r.inPinnedWindowingMode() && (r.mShowWhenLocked
|| r.containsShowWhenLockedWindow());
} else {
@@ -3370,19 +3390,6 @@
true /* topToBottom */);
}
- /**
- * @return an {@link ActivityRecord} of the activity below this activity, or {@code null} if no
- * such activity exists.
- */
- @Nullable
- private ActivityRecord getActivityBelow() {
- final int pos = task.mChildren.indexOf(this);
- if (pos == -1) {
- throw new IllegalStateException("Activity not found in its task");
- }
- return pos == 0 ? null : task.getChildAt(pos - 1);
- }
-
WindowState getImeTargetBelowWindow(WindowState w) {
final int index = mChildren.indexOf(w);
if (index > 0) {
@@ -3426,7 +3433,8 @@
}
@Override
- boolean forAllActivities(Function<ActivityRecord, Boolean> callback) {
+ boolean forAllActivities(
+ Function<ActivityRecord, Boolean> callback, boolean traverseTopToBottom) {
return callback.apply(this);
}
@@ -3603,7 +3611,9 @@
clearOptionsLocked(false /* withAbort */);
} else {
// This will clear the options for all the ActivityRecords for this Task.
- task.clearAllPendingOptions();
+ task.forAllActivities((r) -> {
+ r.clearOptionsLocked(false /* withAbort */);
+ });
}
}
}
@@ -4596,16 +4606,15 @@
}
// Check if position in task allows to become paused
- final int positionInTask = task.mChildren.indexOf(this);
- if (positionInTask == -1) {
+ if (!task.hasChild(this)) {
throw new IllegalStateException("Activity not found in its task");
}
- if (positionInTask == task.getChildCount() - 1) {
+ final ActivityRecord activityAbove = task.getActivityAbove(this);
+ if (activityAbove == null) {
// It's the topmost activity in the task - should become resumed now
return true;
}
// Check if activity above is finishing now and this one becomes the topmost in task.
- final ActivityRecord activityAbove = task.getChildAt(positionInTask + 1);
if (activityAbove.finishing) {
return true;
}
@@ -4661,7 +4670,7 @@
stopped = false;
if (isActivityTypeHome()) {
- mStackSupervisor.updateHomeProcess(task.getChildAt(0).app);
+ mStackSupervisor.updateHomeProcess(task.getBottomMostActivity().app);
}
if (nowVisible) {
@@ -5288,6 +5297,10 @@
&& mAtmService.mAmInternal.isUserRunning(mUserId, 0 /* flags */));
}
+ boolean canBeTopRunning() {
+ return !finishing && okToShowLocked();
+ }
+
/**
* This method will return true if the activity is either visible, is becoming visible, is
* currently pausing, or is resumed.
@@ -5319,13 +5332,12 @@
static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
- if (r == null) {
+ if (r == null || r.getParent() == null) {
return INVALID_TASK_ID;
}
final Task task = r.task;
- final int activityNdx = task.mChildren.indexOf(r);
- if (activityNdx < 0
- || (onlyRoot && activityNdx > task.findRootIndex(true /* effectiveRoot */))) {
+ if (onlyRoot && r.compareTo(task.getRootActivity(
+ false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/)) > 0) {
return INVALID_TASK_ID;
}
return task.mTaskId;
@@ -7216,6 +7228,10 @@
return info.applicationInfo.uid;
}
+ boolean isUid(int uid) {
+ return info.applicationInfo.uid == uid;
+ }
+
int getPid() {
return app != null ? app.getPid() : 0;
}
@@ -7279,13 +7295,8 @@
if (task == null) {
return false;
}
- final ActivityRecord rootActivity = task.getRootActivity();
- if (rootActivity != null) {
- return this == rootActivity;
- }
- // No non-finishing activity found. In this case the bottom-most activity is considered to
- // be the root.
- return task.getChildAt(0) == this;
+ final ActivityRecord rootActivity = task.getRootActivity(true);
+ return this == rootActivity;
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 6ddbb0d..bb3126b 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -76,12 +76,10 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
@@ -107,7 +105,6 @@
import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
-import static com.android.server.wm.RootActivityContainer.FindTaskResult;
import static com.android.server.wm.StackProto.ADJUSTED_BOUNDS;
import static com.android.server.wm.StackProto.ADJUSTED_FOR_IME;
import static com.android.server.wm.StackProto.ADJUST_DIVIDER_AMOUNT;
@@ -143,12 +140,10 @@
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
-import android.net.Uri;
import android.os.Binder;
import android.os.Debug;
import android.os.Handler;
@@ -162,7 +157,6 @@
import android.service.voice.IVoiceInteractionSession;
import android.util.ArraySet;
import android.util.DisplayMetrics;
-import android.util.IntArray;
import android.util.Log;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -178,7 +172,10 @@
import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.internal.policy.DockedDividerUtils;
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledFunction;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.ActivityManagerService.ItemMatcher;
@@ -189,14 +186,12 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
-import java.util.Set;
import java.util.function.Consumer;
/**
* State and management of a single stack of activities.
*/
-class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarget,
- ConfigurationContainerListener {
+class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarget {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_ATM;
static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
private static final String TAG_APP = TAG + POSTFIX_APP;
@@ -499,7 +494,7 @@
case DESTROY_ACTIVITIES_MSG: {
ScheduleDestroyArgs args = (ScheduleDestroyArgs)msg.obj;
synchronized (mService.mGlobalLock) {
- destroyActivitiesLocked(args.mOwner, args.mReason);
+ destroyActivities(args.mOwner, args.mReason);
}
} break;
case TRANSLUCENT_TIMEOUT_MSG: {
@@ -514,13 +509,226 @@
private static final ResetTargetTaskHelper sResetTargetTaskHelper = new ResetTargetTaskHelper();
private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper =
new EnsureActivitiesVisibleHelper(this);
+ private final EnsureVisibleActivitiesConfigHelper mEnsureVisibleActivitiesConfigHelper =
+ new EnsureVisibleActivitiesConfigHelper();
+ private class EnsureVisibleActivitiesConfigHelper {
+ private boolean mUpdateConfig;
+ private boolean mPreserveWindow;
+ private boolean mBehindFullscreen;
- int numActivities() {
- int count = 0;
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- count += getChildAt(taskNdx).getChildCount();
+ void reset(boolean preserveWindow) {
+ mPreserveWindow = preserveWindow;
+ mUpdateConfig = false;
+ mBehindFullscreen = false;
}
- return count;
+
+ void process(ActivityRecord start, boolean preserveWindow) {
+ if (start == null || !start.mVisibleRequested) {
+ return;
+ }
+ reset(preserveWindow);
+
+ final PooledFunction f = PooledLambda.obtainFunction(
+ EnsureVisibleActivitiesConfigHelper::processActivity, this,
+ PooledLambda.__(ActivityRecord.class));
+ forAllActivities(f, start.getTask(), true /*includeBoundary*/,
+ true /*traverseTopToBottom*/);
+ f.recycle();
+
+ if (mUpdateConfig) {
+ // Ensure the resumed state of the focus activity if we updated the configuration of
+ // any activity.
+ mRootActivityContainer.resumeFocusedStacksTopActivities();
+ }
+ }
+
+ boolean processActivity(ActivityRecord r) {
+ mUpdateConfig |= r.ensureActivityConfiguration(0 /*globalChanges*/, mPreserveWindow);
+ mBehindFullscreen |= r.occludesParent();
+ return mBehindFullscreen;
+ }
+ }
+
+ private final CheckBehindFullscreenActivityHelper mCheckBehindFullscreenActivityHelper =
+ new CheckBehindFullscreenActivityHelper();
+ private class CheckBehindFullscreenActivityHelper {
+ private boolean mAboveTop;
+ private boolean mBehindFullscreenActivity;
+ private ActivityRecord mToCheck;
+ private Consumer<ActivityRecord> mHandleBehindFullscreenActivity;
+ private boolean mHandlingOccluded;
+
+ private void reset(ActivityRecord toCheck,
+ Consumer<ActivityRecord> handleBehindFullscreenActivity) {
+ mToCheck = toCheck;
+ mHandleBehindFullscreenActivity = handleBehindFullscreenActivity;
+ mAboveTop = true;
+ mBehindFullscreenActivity = false;
+
+ if (!shouldBeVisible(null)) {
+ // The stack is not visible, so no activity in it should be displaying a starting
+ // window. Mark all activities below top and behind fullscreen.
+ mAboveTop = false;
+ mBehindFullscreenActivity = true;
+ }
+
+ mHandlingOccluded = mToCheck == null && mHandleBehindFullscreenActivity != null;
+ }
+
+ boolean process(ActivityRecord toCheck,
+ Consumer<ActivityRecord> handleBehindFullscreenActivity) {
+ reset(toCheck, handleBehindFullscreenActivity);
+
+ if (!mHandlingOccluded && mBehindFullscreenActivity) {
+ return true;
+ }
+
+ final ActivityRecord topActivity = topRunningActivityLocked();
+ final PooledFunction f = PooledLambda.obtainFunction(
+ CheckBehindFullscreenActivityHelper::processActivity, this,
+ PooledLambda.__(ActivityRecord.class), topActivity);
+ forAllActivities(f);
+ f.recycle();
+
+ return mBehindFullscreenActivity;
+ }
+
+ private boolean processActivity(ActivityRecord r, ActivityRecord topActivity) {
+ if (mAboveTop) {
+ if (r == topActivity) {
+ if (r == mToCheck) {
+ // It is the top activity in a visible stack.
+ mBehindFullscreenActivity = false;
+ return true;
+ }
+ mAboveTop = false;
+ }
+ mBehindFullscreenActivity |= r.occludesParent();
+ return false;
+ }
+
+ if (mHandlingOccluded) {
+ mHandleBehindFullscreenActivity.accept(r);
+ } else if (r == mToCheck) {
+ return true;
+ } else if (mBehindFullscreenActivity) {
+ // It is occluded before {@param toCheck} is found.
+ return true;
+ }
+ mBehindFullscreenActivity |= r.occludesParent();
+ return false;
+ }
+ }
+
+ // TODO: Can we just loop through WindowProcessController#mActivities instead of doing this?
+ private final RemoveHistoryRecordsForApp mRemoveHistoryRecordsForApp =
+ new RemoveHistoryRecordsForApp();
+ private class RemoveHistoryRecordsForApp {
+ private boolean mHasVisibleActivities;
+ private boolean mIsProcessRemoved;
+ private WindowProcessController mApp;
+ private ArrayList<ActivityRecord> mToRemove = new ArrayList<>();
+
+ boolean process(WindowProcessController app) {
+ mToRemove.clear();
+ mHasVisibleActivities = false;
+ mApp = app;
+ mIsProcessRemoved = app.isRemoved();
+ if (mIsProcessRemoved) {
+ // The package of the died process should be force-stopped, so make its activities
+ // as finishing to prevent the process from being started again if the next top
+ // (or being visible) activity also resides in the same process.
+ app.makeFinishingForProcessRemoved();
+ }
+
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ RemoveHistoryRecordsForApp::addActivityToRemove, this,
+ PooledLambda.__(ActivityRecord.class));
+ forAllActivities(c);
+ c.recycle();
+
+ while (!mToRemove.isEmpty()) {
+ processActivity(mToRemove.remove(0));
+ }
+
+ mApp = null;
+ return mHasVisibleActivities;
+ }
+
+ private void addActivityToRemove(ActivityRecord r) {
+ if (r.app == mApp) {
+ mToRemove.add(r);
+ }
+ }
+
+ private void processActivity(ActivityRecord r) {
+ if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "Record " + r + ": app=" + r.app);
+
+ if (r.app != mApp) {
+ return;
+ }
+ if (r.isVisible() || r.mVisibleRequested) {
+ // While an activity launches a new activity, it's possible that the old
+ // activity is already requested to be hidden (mVisibleRequested=false), but
+ // this visibility is not yet committed, so isVisible()=true.
+ mHasVisibleActivities = true;
+ }
+ final boolean remove;
+ if ((r.mRelaunchReason == RELAUNCH_REASON_WINDOWING_MODE_RESIZE
+ || r.mRelaunchReason == RELAUNCH_REASON_FREE_RESIZE)
+ && r.launchCount < 3 && !r.finishing) {
+ // If the process crashed during a resize, always try to relaunch it, unless
+ // it has failed more than twice. Skip activities that's already finishing
+ // cleanly by itself.
+ remove = false;
+ } else if ((!r.hasSavedState() && !r.stateNotNeeded
+ && !r.isState(ActivityState.RESTARTING_PROCESS)) || r.finishing) {
+ // Don't currently have state for the activity, or
+ // it is finishing -- always remove it.
+ remove = true;
+ } else if (!r.mVisibleRequested && r.launchCount > 2
+ && r.lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) {
+ // We have launched this activity too many times since it was
+ // able to run, so give up and remove it.
+ // (Note if the activity is visible, we don't remove the record.
+ // We leave the dead window on the screen but the process will
+ // not be restarted unless user explicitly tap on it.)
+ remove = true;
+ } else {
+ // The process may be gone, but the activity lives on!
+ remove = false;
+ }
+ if (remove) {
+ if (DEBUG_ADD_REMOVE || DEBUG_CLEANUP) Slog.i(TAG_ADD_REMOVE,
+ "Removing activity " + r + " from stack "
+ + ": hasSavedState=" + r.hasSavedState()
+ + " stateNotNeeded=" + r.stateNotNeeded
+ + " finishing=" + r.finishing
+ + " state=" + r.getState() + " callers=" + Debug.getCallers(5));
+ if (!r.finishing || mIsProcessRemoved) {
+ Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
+ EventLogTags.writeWmFinishActivity(r.mUserId,
+ System.identityHashCode(r), r.getTask().mTaskId,
+ r.shortComponentName, "proc died without state saved");
+ }
+ } else {
+ // We have the current state for this activity, so
+ // it can be restarted later when needed.
+ if (DEBUG_ALL) Slog.v(TAG, "Keeping entry, setting app to null");
+ if (DEBUG_APP) Slog.v(TAG_APP,
+ "Clearing app during removeHistory for activity " + r);
+ r.app = null;
+ // Set nowVisible to previous visible state. If the app was visible while
+ // it died, we leave the dead window on screen so it's basically visible.
+ // This is needed when user later tap on the dead window, we need to stop
+ // other apps when user transfers focus to the restarted activity.
+ r.nowVisible = r.mVisibleRequested;
+ }
+ r.cleanUp(true /* cleanServices */, true /* setState */);
+ if (remove) {
+ r.removeFromHistory("appDied");
+ }
+ }
}
ActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
@@ -941,7 +1149,7 @@
}
}
- boolean updateBoundsAllowed(Rect bounds) {
+ private boolean updateBoundsAllowed(Rect bounds) {
if (!mUpdateBoundsDeferred) {
return true;
}
@@ -954,7 +1162,7 @@
return false;
}
- boolean updateDisplayedBoundsAllowed(Rect bounds) {
+ private boolean updateDisplayedBoundsAllowed(Rect bounds) {
if (!mUpdateBoundsDeferred) {
return true;
}
@@ -971,47 +1179,29 @@
return topRunningActivityLocked(false /* focusableOnly */);
}
- void getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities) {
- outActivities.clear();
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- getChildAt(taskNdx).getAllRunningVisibleActivitiesLocked(outActivities);
- }
- }
-
ActivityRecord topRunningActivityLocked(boolean focusableOnly) {
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- ActivityRecord r = getChildAt(taskNdx).topRunningActivityLocked();
- if (r != null && (!focusableOnly || r.isFocusable())) {
- return r;
- }
+ // Split into 2 to avoid object creation due to variable capture.
+ if (focusableOnly) {
+ return getActivity((r) -> r.canBeTopRunning() && r.isFocusable());
+ } else {
+ return getActivity(ActivityRecord::canBeTopRunning);
}
- return null;
}
- ActivityRecord topRunningNonOverlayTaskActivity() {
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = task.getChildAt(activityNdx);
- if (!r.finishing && !r.mTaskOverlay) {
- return r;
- }
- }
- }
- return null;
+ private ActivityRecord topRunningNonOverlayTaskActivity() {
+ return getActivity((r) -> (r.canBeTopRunning() && !r.mTaskOverlay));
}
ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = task.getChildAt(activityNdx);
- if (!r.finishing && !r.delayedResume && r != notTop && r.okToShowLocked()) {
- return r;
- }
- }
- }
- return null;
+ final PooledPredicate p = PooledLambda.obtainPredicate(ActivityStack::isTopRunningNonDelayed
+ , PooledLambda.__(ActivityRecord.class), notTop);
+ final ActivityRecord r = getActivity(p);
+ p.recycle();
+ return r;
+ }
+
+ private static boolean isTopRunningNonDelayed(ActivityRecord r, ActivityRecord notTop) {
+ return !r.delayedResume && r != notTop && r.canBeTopRunning();
}
/**
@@ -1024,30 +1214,19 @@
* @return Returns the HistoryRecord of the next activity on the stack.
*/
final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- Task task = getChildAt(taskNdx);
- if (task.mTaskId == taskId) {
- continue;
- }
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = task.getChildAt(activityNdx);
- // Note: the taskId check depends on real taskId fields being non-zero
- if (!r.finishing && (token != r.appToken) && r.okToShowLocked()) {
- return r;
- }
- }
- }
- return null;
+ final PooledPredicate p = PooledLambda.obtainPredicate(ActivityStack::isTopRunning,
+ PooledLambda.__(ActivityRecord.class), taskId, token);
+ final ActivityRecord r = getActivity(p);
+ p.recycle();
+ return r;
+ }
+
+ private static boolean isTopRunning(ActivityRecord r, int taskId, IBinder notTop) {
+ return r.getTask().mTaskId == taskId && r.appToken != notTop && r.canBeTopRunning();
}
ActivityRecord getTopNonFinishingActivity() {
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final ActivityRecord r = getChildAt(taskNdx).getTopNonFinishingActivity();
- if (r != null) {
- return r;
- }
- }
- return null;
+ return getTopActivity(false /*includeFinishing*/, true /*includeOverlays*/);
}
final Task topTask() {
@@ -1087,35 +1266,6 @@
return null;
}
- boolean isInStackLocked(Task task) {
- return mChildren.contains(task);
- }
-
- /** Checks if there are tasks with specific UID in the stack. */
- boolean isUidPresent(int uid) {
- for (int j = getChildCount() - 1; j >= 0; --j) {
- final Task task = getChildAt(j);
- for (int i = task.getChildCount() - 1; i >= 0 ; --i) {
- final ActivityRecord r = task.getChildAt(i);
- if (r.getUid() == uid) {
- return true;
- }
- }
- }
- return false;
- }
-
- /** Get all UIDs that are present in the stack. */
- void getPresentUIDs(IntArray presentUIDs) {
- for (int j = getChildCount() - 1; j >= 0; --j) {
- final Task task = getChildAt(j);
- for (int i = task.getChildCount() - 1; i >= 0 ; --i) {
- final ActivityRecord r = task.getChildAt(i);
- presentUIDs.add(r.getUid());
- }
- }
- }
-
/** @return true if the stack can only contain one task */
boolean isSingleTaskInstance() {
final ActivityDisplay display = getDisplay();
@@ -1232,138 +1382,6 @@
return display != null && !display.isRemoved();
}
- /**
- * Returns the top activity in any existing task matching the given Intent in the input result.
- * Returns null if no such task is found.
- */
- void findTaskLocked(ActivityRecord target, FindTaskResult result) {
- Intent intent = target.intent;
- ActivityInfo info = target.info;
- ComponentName cls = intent.getComponent();
- if (info.targetActivity != null) {
- cls = new ComponentName(info.packageName, info.targetActivity);
- }
- final int userId = UserHandle.getUserId(info.applicationInfo.uid);
- boolean isDocument = intent != null & intent.isDocument();
- // If documentData is non-null then it must match the existing task data.
- Uri documentData = isDocument ? intent.getData() : null;
-
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + this);
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- if (task.voiceSession != null) {
- // We never match voice sessions; those always run independently.
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": voice session");
- continue;
- }
- if (task.mUserId != userId) {
- // Looking for a different task.
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": different user");
- continue;
- }
-
- // Overlays should not be considered as the task's logical top activity.
- final ActivityRecord r = task.getTopNonFinishingActivity(false /* includeOverlays */);
- if (r == null || r.finishing || r.mUserId != userId ||
- r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch root " + r);
- continue;
- }
- if (!r.hasCompatibleActivityType(target)) {
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch activity type");
- continue;
- }
-
- final Intent taskIntent = task.intent;
- final Intent affinityIntent = task.affinityIntent;
- final boolean taskIsDocument;
- final Uri taskDocumentData;
- if (taskIntent != null && taskIntent.isDocument()) {
- taskIsDocument = true;
- taskDocumentData = taskIntent.getData();
- } else if (affinityIntent != null && affinityIntent.isDocument()) {
- taskIsDocument = true;
- taskDocumentData = affinityIntent.getData();
- } else {
- taskIsDocument = false;
- taskDocumentData = null;
- }
-
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
- + (task.realActivity != null ? task.realActivity.flattenToShortString() : "")
- + "/aff=" + r.getTask().rootAffinity + " to new cls="
- + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
- // TODO Refactor to remove duplications. Check if logic can be simplified.
- if (task.realActivity != null && task.realActivity.compareTo(cls) == 0
- && Objects.equals(documentData, taskDocumentData)) {
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
- //dump();
- if (DEBUG_TASKS) Slog.d(TAG_TASKS,
- "For Intent " + intent + " bringing to top: " + r.intent);
- result.mRecord = r;
- result.mIdealMatch = true;
- break;
- } else if (affinityIntent != null && affinityIntent.getComponent() != null &&
- affinityIntent.getComponent().compareTo(cls) == 0 &&
- Objects.equals(documentData, taskDocumentData)) {
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
- //dump();
- if (DEBUG_TASKS) Slog.d(TAG_TASKS,
- "For Intent " + intent + " bringing to top: " + r.intent);
- result.mRecord = r;
- result.mIdealMatch = true;
- break;
- } else if (!isDocument && !taskIsDocument
- && result.mRecord == null && task.rootAffinity != null) {
- if (task.rootAffinity.equals(target.taskAffinity)) {
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
- // It is possible for multiple tasks to have the same root affinity especially
- // if they are in separate stacks. We save off this candidate, but keep looking
- // to see if there is a better candidate.
- result.mRecord = r;
- result.mIdealMatch = false;
- }
- } else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
- }
- }
-
- /**
- * Returns the first activity (starting from the top of the stack) that
- * is the same as the given activity. Returns null if no such activity
- * is found.
- */
- ActivityRecord findActivityLocked(Intent intent, ActivityInfo info,
- boolean compareIntentFilters) {
- ComponentName cls = intent.getComponent();
- if (info.targetActivity != null) {
- cls = new ComponentName(info.packageName, info.targetActivity);
- }
- final int userId = UserHandle.getUserId(info.applicationInfo.uid);
-
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = task.getChildAt(activityNdx);
- if (!r.okToShowLocked()) {
- continue;
- }
- if (!r.finishing && r.mUserId == userId) {
- if (compareIntentFilters) {
- if (r.intent.filterEquals(intent)) {
- return r;
- }
- } else {
- if (r.intent.getComponent().equals(cls)) {
- return r;
- }
- }
- }
- }
- }
-
- return null;
- }
-
// TODO: Should each user have there own stacks?
@Override
void switchUser(int userId) {
@@ -1401,35 +1419,13 @@
void awakeFromSleepingLocked() {
// Ensure activities are no longer sleeping.
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = task.getChildAt(activityNdx);
- r.setSleeping(false);
- }
- }
+ forAllActivities((Consumer<ActivityRecord>) (r) -> r.setSleeping(false));
if (mPausingActivity != null) {
Slog.d(TAG, "awakeFromSleepingLocked: previously pausing activity didn't pause");
activityPausedLocked(mPausingActivity.appToken, true);
}
}
- void updateActivityApplicationInfoLocked(ApplicationInfo aInfo) {
- final String packageName = aInfo.packageName;
- final int userId = UserHandle.getUserId(aInfo.uid);
-
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord ar = task.getChildAt(activityNdx);
-
- if ((userId == ar.mUserId) && packageName.equals(ar.packageName)) {
- ar.updateApplicationInfo(aInfo);
- }
- }
- }
- }
-
void checkReadyForSleep() {
if (shouldSleepActivities() && goToSleepIfPossible(false /* shuttingDown */)) {
mStackSupervisor.checkReadyForSleepLocked(true /* allowDelay */);
@@ -1495,15 +1491,11 @@
// Make sure any paused or stopped but visible activities are now sleeping.
// This ensures that the activity's onStop() is called.
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = task.getChildAt(activityNdx);
- if (r.isState(STARTED, STOPPING, STOPPED, PAUSED, PAUSING)) {
- r.setSleeping(true);
- }
+ forAllActivities((r) -> {
+ if (r.isState(STARTED, STOPPING, STOPPED, PAUSED, PAUSING)) {
+ r.setSleeping(true);
}
- }
+ });
}
private boolean containsActivityFromStack(List<ActivityRecord> rs) {
@@ -1779,31 +1771,32 @@
if (!isAttached() || mForceHidden) {
return true;
}
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = task.getChildAt(activityNdx);
+ final PooledPredicate p = PooledLambda.obtainPredicate(ActivityStack::isOpaqueActivity,
+ PooledLambda.__(ActivityRecord.class), starting);
+ final ActivityRecord opaque = getActivity(p);
+ p.recycle();
+ return opaque == null;
+ }
- if (r.finishing) {
- // We don't factor in finishing activities when determining translucency since
- // they will be gone soon.
- continue;
- }
-
- if (!r.visibleIgnoringKeyguard && r != starting) {
- // Also ignore invisible activities that are not the currently starting
- // activity (about to be visible).
- continue;
- }
-
- if (r.occludesParent() || r.hasWallpaper) {
- // Stack isn't translucent if it has at least one fullscreen activity
- // that is visible.
- return false;
- }
- }
+ private static boolean isOpaqueActivity(ActivityRecord r, ActivityRecord starting) {
+ if (r.finishing) {
+ // We don't factor in finishing activities when determining translucency since
+ // they will be gone soon.
+ return false;
}
- return true;
+
+ if (!r.visibleIgnoringKeyguard && r != starting) {
+ // Also ignore invisible activities that are not the currently starting
+ // activity (about to be visible).
+ return false;
+ }
+
+ if (r.occludesParent() || r.hasWallpaper) {
+ // Stack isn't translucent if it has at least one fullscreen activity
+ // that is visible.
+ return true;
+ }
+ return false;
}
boolean isTopStackOnDisplay() {
@@ -1958,20 +1951,6 @@
: STACK_VISIBILITY_VISIBLE;
}
- final int rankTaskLayers(int baseLayer) {
- int layer = 0;
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- ActivityRecord r = task.topRunningActivityLocked();
- if (r == null || r.finishing || !r.mVisibleRequested) {
- task.mLayerRank = -1;
- } else {
- task.mLayerRank = baseLayer + layer++;
- }
- }
- return layer;
- }
-
/**
* Make sure that all activities that need to be visible in the stack (that is, they
* currently can be seen by the user) actually are and update their configuration.
@@ -2006,12 +1985,6 @@
}
}
- void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- getChildAt(taskNdx).addStartingWindowsForVisibleActivities(taskSwitch);
- }
- }
-
/**
* @return true if the top visible activity wants to occlude the Keyguard, false otherwise
*/
@@ -2127,18 +2100,6 @@
mHandler.sendEmptyMessageDelayed(TRANSLUCENT_TIMEOUT_MSG, TRANSLUCENT_CONVERSION_TIMEOUT);
}
- void clearOtherAppTimeTrackers(AppTimeTracker except) {
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = task.getChildAt(activityNdx);
- if ( r.appTimeTracker != except) {
- r.appTimeTracker = null;
- }
- }
- }
- }
-
/**
* Called as activities below the top translucent activity are redrawn. When the last one is
* redrawn notify the top activity by calling
@@ -2186,50 +2147,8 @@
*/
boolean checkBehindFullscreenActivity(ActivityRecord toCheck,
Consumer<ActivityRecord> handleBehindFullscreenActivity) {
- boolean aboveTop = true;
- boolean behindFullscreenActivity = false;
-
- if (!shouldBeVisible(null)) {
- // The stack is not visible, so no activity in it should be displaying a starting
- // window. Mark all activities below top and behind fullscreen.
- aboveTop = false;
- behindFullscreenActivity = true;
- }
-
- final boolean handlingOccluded = toCheck == null && handleBehindFullscreenActivity != null;
- if (!handlingOccluded && behindFullscreenActivity) {
- return true;
- }
-
- final ActivityRecord topActivity = topRunningActivityLocked();
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = task.getChildAt(activityNdx);
- if (aboveTop) {
- if (r == topActivity) {
- if (r == toCheck) {
- // It is the top activity in a visible stack.
- return false;
- }
- aboveTop = false;
- }
- behindFullscreenActivity |= r.occludesParent();
- continue;
- }
-
- if (handlingOccluded) {
- handleBehindFullscreenActivity.accept(r);
- } else if (r == toCheck) {
- return behindFullscreenActivity;
- } else if (behindFullscreenActivity) {
- // It is occluded before {@param toCheck} is found.
- return true;
- }
- behindFullscreenActivity |= r.occludesParent();
- }
- }
- return behindFullscreenActivity;
+ return mCheckBehindFullscreenActivityHelper.process(
+ toCheck, handleBehindFullscreenActivity);
}
/**
@@ -2787,7 +2706,7 @@
}
break;
} else if (!isOccluded) {
- isOccluded = task.forAllActivities(ActivityRecord::occludesParent);
+ isOccluded = task.getActivity(ActivityRecord::occludesParent) != null;
}
}
}
@@ -2812,7 +2731,7 @@
// The transition animation and starting window are not needed if {@code allowMoveToFront}
// is false, because the activity won't be visible.
- if ((!isHomeOrRecentsStack() || numActivities() > 0) && allowMoveToFront) {
+ if ((!isHomeOrRecentsStack() || hasActivity()) && allowMoveToFront) {
final DisplayContent dc = getDisplay().mDisplayContent;
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: starting " + r);
@@ -2915,8 +2834,7 @@
return true;
}
- private boolean isTaskSwitch(ActivityRecord r,
- ActivityRecord topFocusedActivity) {
+ private boolean isTaskSwitch(ActivityRecord r, ActivityRecord topFocusedActivity) {
return topFocusedActivity != null && r.getTask() != topFocusedActivity.getTask();
}
@@ -2996,23 +2914,6 @@
return stack;
}
- /** Finish all activities that were started for result from the specified activity. */
- final void finishSubActivityLocked(ActivityRecord self, String resultWho, int requestCode) {
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = task.getChildAt(activityNdx);
- if (r.resultTo == self && r.requestCode == requestCode) {
- if ((r.resultWho == null && resultWho == null) ||
- (r.resultWho != null && r.resultWho.equals(resultWho))) {
- r.finishIfPossible("request-sub", false /* oomAdj */);
- }
- }
- }
- }
- mService.updateOomAdj();
- }
-
/**
* Finish the topmost activity that belongs to the crashed app. We may also finish the activity
* that requested launch of the crashed one to prevent launch-crash loop.
@@ -3023,103 +2924,84 @@
*/
final Task finishTopCrashedActivityLocked(WindowProcessController app, String reason) {
ActivityRecord r = topRunningActivityLocked();
- Task finishedTask = null;
if (r == null || r.app != app) {
return null;
}
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
- finishedTask = r.getTask();
- int taskNdx = mChildren.indexOf(finishedTask);
- final Task task = finishedTask;
- int activityNdx = task.mChildren.indexOf(r);
+ Task finishedTask = r.getTask();
getDisplay().mDisplayContent.prepareAppTransition(
TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
r.finishIfPossible(reason, false /* oomAdj */);
- finishedTask = task;
- // Also terminate any activities below it that aren't yet
- // stopped, to avoid a situation where one will get
- // re-start our crashing activity once it gets resumed again.
- --activityNdx;
- if (activityNdx < 0) {
- do {
- --taskNdx;
- if (taskNdx < 0) {
- break;
- }
- activityNdx = getChildAt(taskNdx).getChildCount() - 1;
- } while (activityNdx < 0);
- }
- if (activityNdx >= 0) {
- r = getChildAt(taskNdx).getChildAt(activityNdx);
- if (r.isState(STARTED, RESUMED, PAUSING, PAUSED)) {
- if (!r.isActivityTypeHome() || mService.mHomeProcess != r.app) {
+
+ // Also terminate any activities below it that aren't yet stopped, to avoid a situation
+ // where one will get re-start our crashing activity once it gets resumed again.
+ final ActivityRecord activityBelow = getActivityBelow(r);
+ if (activityBelow != null) {
+ if (activityBelow.isState(STARTED, RESUMED, PAUSING, PAUSED)) {
+ if (!activityBelow.isActivityTypeHome()
+ || mService.mHomeProcess != activityBelow.app) {
Slog.w(TAG, " Force finishing activity "
- + r.intent.getComponent().flattenToShortString());
- r.finishIfPossible(reason, false /* oomAdj */);
+ + activityBelow.intent.getComponent().flattenToShortString());
+ activityBelow.finishIfPossible(reason, false /* oomAdj */);
}
}
}
+
return finishedTask;
}
- final void finishVoiceTask(IVoiceInteractionSession session) {
- IBinder sessionBinder = session.asBinder();
- boolean didOne = false;
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- Task tr = getChildAt(taskNdx);
- if (tr.voiceSession != null && tr.voiceSession.asBinder() == sessionBinder) {
- for (int activityNdx = tr.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- ActivityRecord r = tr.getChildAt(activityNdx);
- if (!r.finishing) {
- r.finishIfPossible("finish-voice", false /* oomAdj */);
- didOne = true;
- }
- }
- } else {
- // Check if any of the activities are using voice
- for (int activityNdx = tr.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- ActivityRecord r = tr.getChildAt(activityNdx);
- if (r.voiceSession != null && r.voiceSession.asBinder() == sessionBinder) {
- // Inform of cancellation
- r.clearVoiceSessionLocked();
- try {
- r.app.getThread().scheduleLocalVoiceInteractionStarted(
- r.appToken, null);
- } catch (RemoteException re) {
- // Ok
- }
- mService.finishRunningVoiceLocked();
- break;
- }
- }
- }
- }
+ void finishVoiceTask(IVoiceInteractionSession session) {
+ final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::finishIfVoiceTask,
+ PooledLambda.__(Task.class), session.asBinder());
+ forAllTasks(c);
+ c.recycle();
+ }
- if (didOne) {
- mService.updateOomAdj();
+ private static void finishIfVoiceTask(Task tr, IBinder binder) {
+ if (tr.voiceSession != null && tr.voiceSession.asBinder() == binder) {
+ tr.forAllActivities((r) -> {
+ if (r.finishing) return;
+ r.finishIfPossible("finish-voice", false /* oomAdj */);
+ tr.mAtmService.updateOomAdj();
+ });
+ } else {
+ // Check if any of the activities are using voice
+ final PooledFunction f = PooledLambda.obtainFunction(
+ ActivityStack::finishIfVoiceActivity, PooledLambda.__(ActivityRecord.class),
+ binder);
+ tr.forAllActivities(f);
+ f.recycle();
}
}
+ private static boolean finishIfVoiceActivity(ActivityRecord r, IBinder binder) {
+ if (r.voiceSession == null || r.voiceSession.asBinder() != binder) return false;
+ // Inform of cancellation
+ r.clearVoiceSessionLocked();
+ try {
+ r.app.getThread().scheduleLocalVoiceInteractionStarted(r.appToken, null);
+ } catch (RemoteException re) {
+ // Ok Boomer...
+ }
+ r.mAtmService.finishRunningVoiceLocked();
+ return true;
+ }
+
/** Finish all activities in the stack without waiting. */
void finishAllActivitiesImmediately() {
- boolean noActivitiesInStack = true;
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = task.getChildAt(activityNdx);
- noActivitiesInStack = false;
- Slog.d(TAG, "finishAllActivitiesImmediatelyLocked: finishing " + r);
- r.destroyIfPossible("finishAllActivitiesImmediatelyLocked");
- }
- }
- if (noActivitiesInStack) {
+ if (!hasChild()) {
removeIfPossible();
+ return;
}
+ forAllActivities((r) -> {
+ Slog.d(TAG, "finishAllActivitiesImmediatelyLocked: finishing " + r);
+ r.destroyIfPossible("finishAllActivitiesImmediately");
+ });
}
/** @return true if the stack behind this one is a standard activity type. */
- boolean inFrontOfStandardStack() {
+ private boolean inFrontOfStandardStack() {
final ActivityDisplay display = getDisplay();
if (display == null) {
return false;
@@ -3166,28 +3048,25 @@
return false;
}
- final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
+ boolean navigateUpTo(ActivityRecord srec, Intent destIntent, int resultCode,
Intent resultData) {
final Task task = srec.getTask();
- final ArrayList<ActivityRecord> activities = task.mChildren;
- final int start = activities.indexOf(srec);
- if (!mChildren.contains(task) || (start < 0)) {
+
+ if (!mChildren.contains(task) || !task.hasChild(srec)) {
return false;
}
- int finishTo = start - 1;
- ActivityRecord parent = finishTo < 0 ? null : task.getChildAt(finishTo);
+
+ ActivityRecord parent = task.getActivityBelow(srec);
boolean foundParentInTask = false;
final ComponentName dest = destIntent.getComponent();
- if (start > 0 && dest != null) {
- for (int i = finishTo; i >= 0; i--) {
- ActivityRecord r = task.getChildAt(i);
- if (r.info.packageName.equals(dest.getPackageName()) &&
- r.info.name.equals(dest.getClassName())) {
- finishTo = i;
- parent = r;
- foundParentInTask = true;
- break;
- }
+ if (task.getBottomMostActivity() != srec && dest != null) {
+ final ActivityRecord candidate = task.getActivity((ar) ->
+ ar.info.packageName.equals(dest.getPackageName()) &&
+ ar.info.name.equals(dest.getClassName()), srec, false /*includeBoundary*/,
+ true /*traverseTopToBottom*/);
+ if (candidate != null) {
+ parent = candidate;
+ foundParentInTask = true;
}
}
@@ -3212,13 +3091,24 @@
}
}
final long origId = Binder.clearCallingIdentity();
- for (int i = start; i > finishTo; i--) {
- final ActivityRecord r = activities.get(i);
- r.finishIfPossible(resultCode, resultData, "navigate-up", true /* oomAdj */);
+
+ final int[] resultCodeHolder = new int[1];
+ resultCodeHolder[0] = resultCode;
+ final Intent[] resultDataHolder = new Intent[1];
+ resultDataHolder[0] = resultData;
+ final ActivityRecord finalParent = parent;
+ task.forAllActivities((ar) -> {
+ if (ar == finalParent) return true;
+
+ ar.finishIfPossible(
+ resultCodeHolder[0], resultDataHolder[0], "navigate-up", true /* oomAdj */);
// Only return the supplied result for the first activity finished
- resultCode = Activity.RESULT_CANCELED;
- resultData = null;
- }
+ resultCodeHolder[0] = Activity.RESULT_CANCELED;
+ resultDataHolder[0] = null;
+ return false;
+ }, srec, true, true);
+ resultCode = resultCodeHolder[0];
+ resultData = resultDataHolder[0];
if (parent != null && foundParentInTask) {
final int parentLaunchMode = parent.info.launchMode;
@@ -3285,7 +3175,6 @@
}
}
- /// HANDLER INTERFACE BEGIN
void removeTimeoutsForActivity(ActivityRecord r) {
mStackSupervisor.removeTimeoutsForActivityLocked(r);
removePauseTimeoutForActivity(r);
@@ -3343,86 +3232,33 @@
}
/// HANDLER INTERFACE END
- private void destroyActivitiesLocked(WindowProcessController owner, String reason) {
- boolean lastIsOpaque = false;
- boolean activityRemoved = false;
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = task.getChildAt(activityNdx);
- if (r.finishing) {
- continue;
- }
- if (r.occludesParent()) {
- lastIsOpaque = true;
- }
- if (owner != null && r.app != owner) {
- continue;
- }
- if (!lastIsOpaque) {
- continue;
- }
- if (r.isDestroyable()) {
- if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Destroying " + r
- + " in state " + r.getState()
- + " resumed=" + mResumedActivity
- + " pausing=" + mPausingActivity + " for reason " + reason);
- if (r.destroyImmediately(true /* removeFromTask */, reason)) {
- activityRemoved = true;
- }
- }
- }
- }
- if (activityRemoved) {
+ private void destroyActivities(WindowProcessController owner, String reason) {
+ try {
+ mStackSupervisor.beginDeferResume();
+
+ final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::destroyActivity,
+ PooledLambda.__(ActivityRecord.class), owner, reason);
+ forAllActivities(c);
+ c.recycle();
+ } finally {
+ mStackSupervisor.endDeferResume();
mRootActivityContainer.resumeFocusedStacksTopActivities();
}
}
- final int releaseSomeActivitiesLocked(WindowProcessController app, ArraySet<Task> tasks,
- String reason) {
- // Iterate over tasks starting at the back (oldest) first.
- if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Trying to release some activities in " + app);
- int maxTasks = tasks.size() / 4;
- if (maxTasks < 1) {
- maxTasks = 1;
- }
- int numReleased = 0;
- for (int taskNdx = 0; taskNdx < getChildCount() && maxTasks > 0; taskNdx++) {
- final Task task = getChildAt(taskNdx);
- if (!tasks.contains(task)) {
- continue;
- }
- if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Looking for activities to release in " + task);
- int curNum = 0;
- for (int actNdx = 0; actNdx < task.getChildCount(); actNdx++) {
- final ActivityRecord activity = task.getChildAt(actNdx);
- if (activity.app == app && activity.isDestroyable()) {
- if (DEBUG_RELEASE) Slog.v(TAG_RELEASE, "Destroying " + activity
- + " in state " + activity.getState() + " resumed=" + mResumedActivity
- + " pausing=" + mPausingActivity + " for reason " + reason);
- activity.destroyImmediately(true /* removeFromApp */, reason);
- if (task.getChildAt(actNdx) != activity) {
- // Was removed from list, back up so we don't miss the next one.
- actNdx--;
- }
- curNum++;
- }
- }
- if (curNum > 0) {
- numReleased += curNum;
- maxTasks--;
- if (getChildAt(taskNdx) != task) {
- // The entire task got removed, back up so we don't miss the next one.
- taskNdx--;
- }
- }
- }
- if (DEBUG_RELEASE) Slog.d(TAG_RELEASE,
- "Done releasing: did " + numReleased + " activities");
- return numReleased;
+ private static void destroyActivity(
+ ActivityRecord r, WindowProcessController owner, String reason) {
+ if (r.finishing || (owner != null && r.app != owner) || !r.isDestroyable()) return;
+
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Destroying " + r
+ + " in state " + r.getState()
+ + " resumed=" + r.getStack().mResumedActivity
+ + " pausing=" + r.getStack().mPausingActivity + " for reason " + reason);
+
+ r.destroyImmediately(true /* removeFromTask */, reason);
}
- private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
+ private void removeHistoryRecordsForApp(ArrayList<ActivityRecord> list,
WindowProcessController app, String listName) {
int i = list.size();
if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
@@ -3439,107 +3275,15 @@
}
}
- private boolean removeHistoryRecordsForAppLocked(WindowProcessController app) {
- removeHistoryRecordsForAppLocked(mLruActivities, app, "mLruActivities");
- removeHistoryRecordsForAppLocked(mStackSupervisor.mStoppingActivities, app,
+ private boolean removeHistoryRecordsForApp(WindowProcessController app) {
+ removeHistoryRecordsForApp(mLruActivities, app, "mLruActivities");
+ removeHistoryRecordsForApp(mStackSupervisor.mStoppingActivities, app,
"mStoppingActivities");
- removeHistoryRecordsForAppLocked(mStackSupervisor.mGoingToSleepActivities, app,
+ removeHistoryRecordsForApp(mStackSupervisor.mGoingToSleepActivities, app,
"mGoingToSleepActivities");
- removeHistoryRecordsForAppLocked(mStackSupervisor.mFinishingActivities, app,
+ removeHistoryRecordsForApp(mStackSupervisor.mFinishingActivities, app,
"mFinishingActivities");
-
- final boolean isProcessRemoved = app.isRemoved();
- if (isProcessRemoved) {
- // The package of the died process should be force-stopped, so make its activities as
- // finishing to prevent the process from being started again if the next top (or being
- // visible) activity also resides in the same process.
- app.makeFinishingForProcessRemoved();
- }
-
- boolean hasVisibleActivities = false;
-
- // Clean out the history list.
- int i = numActivities();
- if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
- "Removing app " + app + " from history with " + i + " entries");
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final ArrayList<ActivityRecord> activities = getChildAt(taskNdx).mChildren;
- mTmpActivities.clear();
- mTmpActivities.addAll(activities);
-
- while (!mTmpActivities.isEmpty()) {
- final int targetIndex = mTmpActivities.size() - 1;
- final ActivityRecord r = mTmpActivities.remove(targetIndex);
- if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
- "Record #" + targetIndex + " " + r + ": app=" + r.app);
-
- if (r.app == app) {
- if (r.isVisible() || r.mVisibleRequested) {
- // While an activity launches a new activity, it's possible that the old
- // activity is already requested to be hidden (mVisibleRequested=false), but
- // this visibility is not yet committed, so isVisible()=true.
- hasVisibleActivities = true;
- }
- final boolean remove;
- if ((r.mRelaunchReason == RELAUNCH_REASON_WINDOWING_MODE_RESIZE
- || r.mRelaunchReason == RELAUNCH_REASON_FREE_RESIZE)
- && r.launchCount < 3 && !r.finishing) {
- // If the process crashed during a resize, always try to relaunch it, unless
- // it has failed more than twice. Skip activities that's already finishing
- // cleanly by itself.
- remove = false;
- } else if ((!r.hasSavedState() && !r.stateNotNeeded
- && !r.isState(ActivityState.RESTARTING_PROCESS)) || r.finishing) {
- // Don't currently have state for the activity, or
- // it is finishing -- always remove it.
- remove = true;
- } else if (!r.mVisibleRequested && r.launchCount > 2
- && r.lastLaunchTime > (SystemClock.uptimeMillis() - 60000)) {
- // We have launched this activity too many times since it was
- // able to run, so give up and remove it.
- // (Note if the activity is visible, we don't remove the record.
- // We leave the dead window on the screen but the process will
- // not be restarted unless user explicitly tap on it.)
- remove = true;
- } else {
- // The process may be gone, but the activity lives on!
- remove = false;
- }
- if (remove) {
- if (DEBUG_ADD_REMOVE || DEBUG_CLEANUP) Slog.i(TAG_ADD_REMOVE,
- "Removing activity " + r + " from stack at " + i
- + ": hasSavedState=" + r.hasSavedState()
- + " stateNotNeeded=" + r.stateNotNeeded
- + " finishing=" + r.finishing
- + " state=" + r.getState() + " callers=" + Debug.getCallers(5));
- if (!r.finishing || isProcessRemoved) {
- Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
- EventLogTags.writeWmFinishActivity(r.mUserId,
- System.identityHashCode(r), r.getTask().mTaskId,
- r.shortComponentName, "proc died without state saved");
- }
- } else {
- // We have the current state for this activity, so
- // it can be restarted later when needed.
- if (DEBUG_ALL) Slog.v(TAG, "Keeping entry, setting app to null");
- if (DEBUG_APP) Slog.v(TAG_APP,
- "Clearing app during removeHistory for activity " + r);
- r.app = null;
- // Set nowVisible to previous visible state. If the app was visible while
- // it died, we leave the dead window on screen so it's basically visible.
- // This is needed when user later tap on the dead window, we need to stop
- // other apps when user transfers focus to the restarted activity.
- r.nowVisible = r.mVisibleRequested;
- }
- r.cleanUp(true /* cleanServices */, true /* setState */);
- if (remove) {
- r.removeFromHistory("appDied");
- }
- }
- }
- }
-
- return hasVisibleActivities;
+ return mRemoveHistoryRecordsForApp.process(app);
}
private void updateTransitLocked(int transit, ActivityOptions options) {
@@ -3559,8 +3303,7 @@
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
final ActivityStack topStack = getDisplay().getTopStack();
- final ActivityRecord topActivity = topStack != null
- ? topStack.getTopNonFinishingActivity() : null;
+ final ActivityRecord topActivity = topStack != null ? topStack.getTopNonFinishingActivity() : null;
final int numTasks = getChildCount();
final int index = mChildren.indexOf(tr);
if (numTasks == 0 || index < 0) {
@@ -3575,9 +3318,10 @@
if (timeTracker != null) {
// The caller wants a time tracker associated with this task.
- for (int i = tr.getChildCount() - 1; i >= 0; i--) {
- tr.getChildAt(i).appTimeTracker = timeTracker;
- }
+ final PooledConsumer c = PooledLambda.obtainConsumer(ActivityRecord::setAppTimeTracker,
+ PooledLambda.__(ActivityRecord.class), timeTracker);
+ tr.forAllActivities(c);
+ c.recycle();
}
try {
@@ -3711,38 +3455,8 @@
/**
* Ensures all visible activities at or below the input activity have the right configuration.
*/
- void ensureVisibleActivitiesConfigurationLocked(ActivityRecord start, boolean preserveWindow) {
- if (start == null || !start.mVisibleRequested) {
- return;
- }
-
- final Task startTask = start.getTask();
- boolean behindFullscreen = false;
- boolean updatedConfig = false;
-
- for (int taskIndex = mChildren.indexOf(startTask); taskIndex >= 0; --taskIndex) {
- final Task task = getChildAt(taskIndex);
- final ArrayList<ActivityRecord> activities = task.mChildren;
- int activityIndex = (start.getTask() == task)
- ? activities.indexOf(start) : activities.size() - 1;
- for (; activityIndex >= 0; --activityIndex) {
- final ActivityRecord r = activities.get(activityIndex);
- updatedConfig |= r.ensureActivityConfiguration(0 /* globalChanges */,
- preserveWindow);
- if (r.occludesParent()) {
- behindFullscreen = true;
- break;
- }
- }
- if (behindFullscreen) {
- break;
- }
- }
- if (updatedConfig) {
- // Ensure the resumed state of the focus activity if we updated the configuration of
- // any activity.
- mRootActivityContainer.resumeFocusedStacksTopActivities();
- }
+ void ensureVisibleActivitiesConfiguration(ActivityRecord start, boolean preserveWindow) {
+ mEnsureVisibleActivitiesConfigHelper.process(start, preserveWindow);
}
// TODO: Can only be called from special methods in ActivityStackSupervisor.
@@ -3774,7 +3488,7 @@
setBounds(bounds);
if (!deferResume) {
- ensureVisibleActivitiesConfigurationLocked(
+ ensureVisibleActivitiesConfiguration(
topRunningActivityLocked(), preserveWindows);
}
} finally {
@@ -3818,85 +3532,23 @@
}
}
- boolean willActivityBeVisibleLocked(IBinder token) {
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = task.getChildAt(activityNdx);
- if (r.appToken == token) {
- return true;
- }
- if (r.occludesParent() && !r.finishing) {
- return false;
- }
- }
- }
+ boolean willActivityBeVisible(IBinder token) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r == null) {
return false;
}
- if (r.finishing) Slog.e(TAG, "willActivityBeVisibleLocked: Returning false,"
+
+ // See if there is an occluding activity on-top of this one.
+ final ActivityRecord occludingActivity = getActivity((ar) ->
+ ar.occludesParent() && !ar.finishing,
+ r, false /*includeBoundary*/, true /*traverseTopToBottom*/);
+ if (occludingActivity != null) return false;
+
+ if (r.finishing) Slog.e(TAG, "willActivityBeVisible: Returning false,"
+ " would have returned true for r=" + r);
return !r.finishing;
}
- void closeSystemDialogsLocked() {
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = task.getChildAt(activityNdx);
- if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
- r.finishIfPossible("close-sys", true /* oomAdj */);
- }
- }
- }
- }
-
- boolean finishDisabledPackageActivitiesLocked(String packageName, Set<String> filterByClasses,
- boolean doit, boolean evenPersistent, int userId) {
- boolean didSomething = false;
- Task lastTask = null;
- ComponentName homeActivity = null;
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final ArrayList<ActivityRecord> activities = getChildAt(taskNdx).mChildren;
- mTmpActivities.clear();
- mTmpActivities.addAll(activities);
-
- while (!mTmpActivities.isEmpty()) {
- ActivityRecord r = mTmpActivities.remove(0);
- final boolean sameComponent =
- (r.packageName.equals(packageName) && (filterByClasses == null
- || filterByClasses.contains(r.mActivityComponent.getClassName())))
- || (packageName == null && r.mUserId == userId);
- if ((userId == UserHandle.USER_ALL || r.mUserId == userId)
- && (sameComponent || r.getTask() == lastTask)
- && (r.app == null || evenPersistent || !r.app.isPersistent())) {
- if (!doit) {
- if (r.finishing) {
- // If this activity is just finishing, then it is not
- // interesting as far as something to stop.
- continue;
- }
- return true;
- }
- if (r.isActivityTypeHome()) {
- if (homeActivity != null && homeActivity.equals(r.mActivityComponent)) {
- Slog.i(TAG, "Skip force-stop again " + r);
- continue;
- } else {
- homeActivity = r.mActivityComponent;
- }
- }
- didSomething = true;
- Slog.i(TAG, " Force finishing activity " + r);
- lastTask = r.getTask();
- r.finishIfPossible("force-stop", true);
- }
- }
- }
- return didSomething;
- }
-
/**
* @return The set of running tasks through {@param tasksOut} that are available to the caller.
* If {@param ignoreActivityType} or {@param ignoreWindowingMode} are not undefined,
@@ -3948,14 +3600,11 @@
}
void unhandledBackLocked() {
- final int top = getChildCount() - 1;
- if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Performing unhandledBack(): top activity at " + top);
- if (top >= 0) {
- final Task task = getChildAt(top);
- int activityTop = task.getChildCount() - 1;
- if (activityTop >= 0) {
- task.getChildAt(activityTop).finishIfPossible("unhandled-back", true /* oomAdj */);
- }
+ final ActivityRecord topActivity = getTopMostActivity();
+ if (DEBUG_SWITCH) Slog.d(TAG_SWITCH,
+ "Performing unhandledBack(): top activity: " + topActivity);
+ if (topActivity != null) {
+ topActivity.finishIfPossible("unhandled-back", true /* oomAdj */);
}
}
@@ -3975,25 +3624,7 @@
mLastNoHistoryActivity = null;
}
- return removeHistoryRecordsForAppLocked(app);
- }
-
- void handleAppCrash(WindowProcessController app) {
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = task.getChildAt(activityNdx);
- if (r.app == app) {
- Slog.w(TAG, " Force finishing activity "
- + r.intent.getComponent().flattenToShortString());
- // Force the destroy to skip right to removal.
- r.app = null;
- getDisplay().mDisplayContent.prepareAppTransition(
- TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
- r.destroyIfPossible("handleAppCrashedLocked");
- }
- }
- }
+ return removeHistoryRecordsForApp(app);
}
boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient,
@@ -4004,8 +3635,7 @@
pw.println(" isSleeping=" + shouldSleepActivities());
pw.println(" mBounds=" + getRequestedOverrideBounds());
- boolean printed = dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
- needSep);
+ boolean printed = dumpActivities(fd, pw, dumpAll, dumpClient, dumpPackage, needSep);
printed |= dumpHistoryList(fd, pw, mLruActivities, " ", "Run", false,
!dumpAll, false, dumpPackage, true,
@@ -4037,15 +3667,14 @@
return printed;
}
- boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
+ private boolean dumpActivities(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
boolean dumpClient, String dumpPackage, boolean needSep) {
if (!hasChild()) {
return false;
}
final String prefix = " ";
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
+ forAllTasks((task) -> {
if (needSep) {
pw.println("");
}
@@ -4056,9 +3685,11 @@
pw.println(prefix + "mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds);
pw.println(prefix + "* " + task);
task.dump(pw, prefix + " ");
- dumpHistoryList(fd, pw, getChildAt(taskNdx).mChildren,
- prefix, "Hist", true, !dumpAll, dumpClient, dumpPackage, false, null, task);
- }
+ final ArrayList<ActivityRecord> activities = new ArrayList<>();
+ forAllActivities((Consumer<ActivityRecord>) activities::add);
+ dumpHistoryList(fd, pw, activities, prefix, "Hist", true, !dumpAll, dumpClient,
+ dumpPackage, false, null, task);
+ });
return true;
}
@@ -4066,31 +3697,21 @@
ArrayList<ActivityRecord> activities = new ArrayList<>();
if ("all".equals(name)) {
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- activities.addAll(getChildAt(taskNdx).mChildren);
- }
+ forAllActivities((Consumer<ActivityRecord>) activities::add);
} else if ("top".equals(name)) {
- final int top = getChildCount() - 1;
- if (top >= 0) {
- final Task task = getChildAt(top);
- int listTop = task.getChildCount() - 1;
- if (listTop >= 0) {
- activities.add(task.getChildAt(listTop));
- }
+ final ActivityRecord topActivity = getTopMostActivity();
+ if (topActivity != null) {
+ activities.add(topActivity);
}
} else {
ItemMatcher matcher = new ItemMatcher();
matcher.build(name);
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r1 = task.getChildAt(activityNdx);
- if (matcher.match(r1, r1.intent.getComponent())) {
- activities.add(r1);
- }
+ forAllActivities((r) -> {
+ if (matcher.match(r, r.intent.getComponent())) {
+ activities.add(r);
}
- }
+ });
}
return activities;
@@ -4101,22 +3722,24 @@
// All activities that came from the package must be
// restarted as if there was a config change.
- for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = getChildAt(taskNdx);
- for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord a = task.getChildAt(activityNdx);
- if (a.info.packageName.equals(packageName)) {
- a.forceNewConfig = true;
- if (starting != null && a == starting && a.mVisibleRequested) {
- a.startFreezingScreenLocked(CONFIG_SCREEN_LAYOUT);
- }
- }
- }
- }
+ PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::restartPackage,
+ PooledLambda.__(ActivityRecord.class), starting, packageName);
+ forAllActivities(c);
+ c.recycle();
return starting;
}
+ private static void restartPackage(
+ ActivityRecord r, ActivityRecord starting, String packageName) {
+ if (r.info.packageName.equals(packageName)) {
+ r.forceNewConfig = true;
+ if (starting != null && r == starting && r.mVisibleRequested) {
+ r.startFreezingScreenLocked(CONFIG_SCREEN_LAYOUT);
+ }
+ }
+ }
+
/**
* Removes the input task from this stack.
*
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index d088a5e..0376d2c 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -138,6 +138,7 @@
import com.android.internal.os.TransferPipe;
import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.UserState;
@@ -825,7 +826,7 @@
task.mTaskId, r.shortComponentName);
if (r.isActivityTypeHome()) {
// Home process is the root process of the task.
- updateHomeProcess(task.getChildAt(0).app);
+ updateHomeProcess(task.getBottomMostActivity().app);
}
mService.getPackageManagerInternalLocked().notifyPackageUse(
r.intent.getComponent().getPackageName(), NOTIFY_PACKAGE_USE_ACTIVITY);
@@ -1688,7 +1689,7 @@
}
}
if (!deferResume) {
- stack.ensureVisibleActivitiesConfigurationLocked(r, preserveWindows);
+ stack.ensureVisibleActivitiesConfiguration(r, preserveWindows);
}
} finally {
mAllowDockedStackResize = true;
@@ -2485,18 +2486,23 @@
return;
}
- for (int i = task.getChildCount() - 1; i >= 0; i--) {
- final ActivityRecord r = task.getChildAt(i);
- if (r.attachedToProcess()) {
- mMultiWindowModeChangedActivities.add(r);
- }
- }
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ ActivityStackSupervisor::addToMultiWindowModeChangedList, this,
+ PooledLambda.__(ActivityRecord.class));
+ task.forAllActivities(c);
+ c.recycle();
if (!mHandler.hasMessages(REPORT_MULTI_WINDOW_MODE_CHANGED_MSG)) {
mHandler.sendEmptyMessage(REPORT_MULTI_WINDOW_MODE_CHANGED_MSG);
}
}
+ private void addToMultiWindowModeChangedList(ActivityRecord r) {
+ if (r.attachedToProcess()) {
+ mMultiWindowModeChangedActivities.add(r);
+ }
+ }
+
void scheduleUpdatePictureInPictureModeIfNeeded(Task task, ActivityStack prevStack) {
final ActivityStack stack = task.getStack();
if (prevStack == null || prevStack == stack
@@ -2507,17 +2513,13 @@
scheduleUpdatePictureInPictureModeIfNeeded(task, stack.getRequestedOverrideBounds());
}
- void scheduleUpdatePictureInPictureModeIfNeeded(Task task, Rect targetStackBounds) {
- for (int i = task.getChildCount() - 1; i >= 0; i--) {
- final ActivityRecord r = task.getChildAt(i);
- if (r.attachedToProcess()) {
- mPipModeChangedActivities.add(r);
- // If we are scheduling pip change, then remove this activity from multi-window
- // change list as the processing of pip change will make sure multi-window changed
- // message is processed in the right order relative to pip changed.
- mMultiWindowModeChangedActivities.remove(r);
- }
- }
+ private void scheduleUpdatePictureInPictureModeIfNeeded(Task task, Rect targetStackBounds) {
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ ActivityStackSupervisor::addToPipModeChangedList, this,
+ PooledLambda.__(ActivityRecord.class));
+ task.forAllActivities(c);
+ c.recycle();
+
mPipModeChangedTargetStackBounds = targetStackBounds;
if (!mHandler.hasMessages(REPORT_PIP_MODE_CHANGED_MSG)) {
@@ -2525,14 +2527,23 @@
}
}
+ private void addToPipModeChangedList(ActivityRecord r) {
+ if (!r.attachedToProcess()) return;
+
+ mPipModeChangedActivities.add(r);
+ // If we are scheduling pip change, then remove this activity from multi-window
+ // change list as the processing of pip change will make sure multi-window changed
+ // message is processed in the right order relative to pip changed.
+ mMultiWindowModeChangedActivities.remove(r);
+ }
+
void updatePictureInPictureMode(Task task, Rect targetStackBounds, boolean forceUpdate) {
mHandler.removeMessages(REPORT_PIP_MODE_CHANGED_MSG);
- for (int i = task.getChildCount() - 1; i >= 0; i--) {
- final ActivityRecord r = task.getChildAt(i);
- if (r.attachedToProcess()) {
- r.updatePictureInPictureMode(targetStackBounds, forceUpdate);
- }
- }
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ ActivityRecord::updatePictureInPictureMode,
+ PooledLambda.__(ActivityRecord.class), targetStackBounds, forceUpdate);
+ task.forAllActivities(c);
+ c.recycle();
}
void wakeUp(String reason) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 0f912f1..a496396 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -149,7 +149,8 @@
private final ActivityStartController mController;
// Share state variable among methods when starting an activity.
- private ActivityRecord mStartActivity;
+ @VisibleForTesting
+ ActivityRecord mStartActivity;
private Intent mIntent;
private int mCallingUid;
private ActivityOptions mOptions;
@@ -173,7 +174,8 @@
private int mPreferredDisplayId;
private Task mInTask;
- private boolean mAddingToTask;
+ @VisibleForTesting
+ boolean mAddingToTask;
private Task mReuseTask;
private ActivityInfo mNewTaskInfo;
@@ -1444,7 +1446,7 @@
// Stack should also be detached from display and be removed if it's empty.
if (startedActivityStack != null && startedActivityStack.isAttached()
- && startedActivityStack.numActivities() == 0
+ && !startedActivityStack.hasActivity()
&& !startedActivityStack.isActivityTypeHome()) {
startedActivityStack.removeIfPossible();
startedActivityStack = null;
@@ -1638,7 +1640,7 @@
return START_CANCELED;
}
- if (mRestrictedBgActivity && (newTask || !targetTask.containsAppUid(mCallingUid))
+ if (mRestrictedBgActivity && (newTask || !targetTask.isUidPresent(mCallingUid))
&& handleBackgroundActivityAbort(mStartActivity)) {
Slog.e(TAG, "Abort background activity starts from " + mCallingUid);
return START_ABORTED;
@@ -1665,7 +1667,16 @@
* - Comply to the specified activity launch flags
* - Determine whether need to add a new activity on top or just brought the task to front.
*/
- private int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask) {
+ @VisibleForTesting
+ int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask) {
+ // Should not recycle task which is from a different user, just adding the starting
+ // activity to the task.
+ if (targetTask.mUserId != mStartActivity.mUserId) {
+ mTargetStack = targetTask.getStack();
+ mAddingToTask = true;
+ return START_SUCCESS;
+ }
+
// True if we are clearing top and resetting of a standard (default) launch mode
// ({@code LAUNCH_MULTIPLE}) activity. The existing activity will be finished.
final boolean clearTopAndResetStandardLaunchMode =
@@ -1869,8 +1880,8 @@
// In this case, we are launching an activity in our own task that may
// already be running somewhere in the history, and we want to shuffle it to
// the front of the stack if so.
- final ActivityRecord act = targetTask.findActivityInHistoryLocked(
- mStartActivity);
+ final ActivityRecord act =
+ targetTask.findActivityInHistory(mStartActivity.mActivityComponent);
if (act != null) {
final Task task = act.getTask();
task.moveActivityToFrontLocked(act);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index bcd5d36..df03940 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -247,6 +247,8 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledFunction;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.AttributeCache;
import com.android.server.LocalServices;
@@ -695,6 +697,13 @@
int caller() default NONE;
}
+ private final Runnable mUpdateOomAdjRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mAmInternal.updateOomAdj();
+ }
+ };
+
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public ActivityTaskManagerService(Context context) {
mContext = context;
@@ -1661,7 +1670,14 @@
if (getLockTaskController().activityBlockedFromFinish(r)) {
return false;
}
- r.finishActivityAffinity();
+
+ final PooledFunction p = PooledLambda.obtainFunction(
+ ActivityRecord::finishIfSameAffinity, r,
+ PooledLambda.__(ActivityRecord.class));
+ r.getTask().forAllActivities(
+ p, r, true /*includeBoundary*/, true /*traverseTopToBottom*/);
+ p.recycle();
+
return true;
} finally {
Binder.restoreCallingIdentity(origId);
@@ -1994,10 +2010,8 @@
if (r == null) {
return false;
}
- final Task task = r.getTask();
- int index = task.mChildren.lastIndexOf(r);
- if (index > 0) {
- ActivityRecord under = task.getChildAt(index - 1);
+ final ActivityRecord under = r.getTask().getActivityBelow(r);
+ if (under != null) {
under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null;
}
return r.setOccludesParent(false);
@@ -2163,7 +2177,7 @@
synchronized (mGlobalLock) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r != null) {
- return r.getActivityStack().navigateUpToLocked(
+ return r.getActivityStack().navigateUpTo(
r, destIntent, resultCode, resultData);
}
return false;
@@ -2548,11 +2562,22 @@
public final void finishSubActivity(IBinder token, String resultWho, int requestCode) {
synchronized (mGlobalLock) {
final long origId = Binder.clearCallingIdentity();
- ActivityRecord r = ActivityRecord.isInStackLocked(token);
- if (r != null) {
- r.getActivityStack().finishSubActivityLocked(r, resultWho, requestCode);
+ try {
+ ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null) return;
+
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ ActivityRecord::finishIfSubActivity, PooledLambda.__(ActivityRecord.class),
+ r, resultWho, requestCode);
+ // TODO: This should probably only loop over the task since you need to be in the
+ // same task to return results.
+ r.getActivityStack().forAllActivities(c);
+ c.recycle();
+
+ updateOomAdj();
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
- Binder.restoreCallingIdentity(origId);
}
}
@@ -2561,7 +2586,7 @@
synchronized (mGlobalLock) {
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
- return stack.willActivityBeVisibleLocked(token);
+ return stack.willActivityBeVisible(token);
}
return false;
}
@@ -3332,7 +3357,7 @@
final long origId = Binder.clearCallingIdentity();
try {
final WindowProcessController app = getProcessController(appInt);
- mRootActivityContainer.releaseSomeActivitiesLocked(app, "low-mem");
+ app.releaseSomeActivities("low-mem");
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -5545,7 +5570,8 @@
}
void updateOomAdj() {
- mH.post(mAmInternal::updateOomAdj);
+ mH.removeCallbacks(mUpdateOomAdjRunnable);
+ mH.post(mUpdateOomAdjRunnable);
}
void updateCpuStats() {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 283b92c..b046b08 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2482,7 +2482,7 @@
&& !mDividerControllerLocked.isImeHideRequested();
final ActivityStack dockedStack = getSplitScreenPrimaryStack();
final boolean dockVisible = dockedStack != null;
- final Task topDockedTask = dockVisible ? dockedStack.getTopChild() : null;
+ final Task topDockedTask = dockVisible ? dockedStack.getTask((t) -> true): null;
final ActivityStack imeTargetStack = mWmService.getImeFocusStackLocked();
final int imeDockSide = (dockVisible && imeTargetStack != null) ?
imeTargetStack.getDockSide() : DOCKED_INVALID;
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 3b58eca..7645de5 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -196,8 +196,7 @@
// Some stack visibility might change (e.g. docked stack)
mRootActivityContainer.resumeFocusedStacksTopActivities();
mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
- mRootActivityContainer.addStartingWindowsForVisibleActivities(
- true /* taskSwitch */);
+ mRootActivityContainer.addStartingWindowsForVisibleActivities();
mWindowManager.executeAppTransition();
} finally {
mService.continueWindowLayout();
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 824a3c8..f2e9505 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -42,6 +42,8 @@
import android.util.Slog;
import android.view.IRecentsAnimationRunner;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.protolog.common.ProtoLog;
import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks;
@@ -490,13 +492,15 @@
return null;
}
- for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
- final Task task = targetStack.getChildAt(i);
- if (task.mUserId == mUserId
- && task.getBaseIntent().getComponent().equals(mTargetIntent.getComponent())) {
- return task.getTopNonFinishingActivity();
- }
- }
- return null;
+ final PooledPredicate p = PooledLambda.obtainPredicate(RecentsAnimation::matchesTarget,
+ this, PooledLambda.__(Task.class));
+ final Task task = targetStack.getTask(p);
+ p.recycle();
+ return task != null ? task.getTopNonFinishingActivity() : null;
+ }
+
+ private boolean matchesTarget(Task task) {
+ return task.mUserId == mUserId
+ && task.getBaseIntent().getComponent().equals(mTargetIntent.getComponent());
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 282144e..4c5ca38 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -55,6 +55,9 @@
import android.view.SurfaceControl.Transaction;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledFunction;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.protolog.common.ProtoLog;
@@ -369,13 +372,13 @@
final ActivityStack targetStack = mDisplayContent.getStack(WINDOWING_MODE_UNDEFINED,
targetActivityType);
if (targetStack != null) {
- for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
- final Task t = targetStack.getChildAt(i);
- if (!visibleTasks.contains(t)) {
- visibleTasks.add(t);
- }
- }
+ final PooledConsumer c = PooledLambda.obtainConsumer((t, outList) ->
+ { if (!outList.contains(t)) outList.add(t); }, PooledLambda.__(Task.class),
+ visibleTasks);
+ targetStack.forAllTasks(c);
+ c.recycle();
}
+
final int taskCount = visibleTasks.size();
for (int i = 0; i < taskCount; i++) {
final Task task = visibleTasks.get(i);
@@ -800,12 +803,12 @@
private boolean isAnimatingApp(ActivityRecord activity) {
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
final Task task = mPendingAnimations.get(i).mTask;
- for (int j = task.getChildCount() - 1; j >= 0; j--) {
- final ActivityRecord app = task.getChildAt(j);
- if (app == activity) {
- return true;
- }
- }
+ final PooledFunction f = PooledLambda.obtainFunction(
+ (a, b) -> a == b, activity,
+ PooledLambda.__(ActivityRecord.class));
+ boolean isAnimatingApp = task.forAllActivities(f);
+ f.recycle();
+ return isAnimatingApp;
}
return false;
}
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index 413dfd5..3aa91d5 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -125,8 +125,7 @@
// TODO: We should probably look for other stacks also, since corresponding
// task with the same affinity is unlikely to be in the same stack.
final Task targetTask;
- final ActivityRecord bottom = mParent.getActivity(
- (ar) -> true, false /*traverseTopToBottom*/);
+ final ActivityRecord bottom = mParent.getBottomMostActivity();
if (bottom != null && r.taskAffinity.equals(bottom.getTask().affinity)) {
// If the activity currently at the bottom has the same task affinity as
@@ -210,10 +209,8 @@
// we have put it on top of another instance of the same activity? Then we drop
// the instance below so it remains singleTop.
if (r.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
- final ArrayList<ActivityRecord> taskActivities = mTargetTask.mChildren;
- final int targetNdx = taskActivities.indexOf(r);
- if (targetNdx > 0) {
- final ActivityRecord p = taskActivities.get(targetNdx - 1);
+ final ActivityRecord p = mTargetTask.getActivityBelow(r);
+ if (p != null) {
if (p.intent.getComponent().equals(r.intent.getComponent())) {
p.finishIfPossible("replace", false /* oomAdj */);
}
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 8f1d6ee..5fd59fa 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -33,6 +33,7 @@
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
import static com.android.server.am.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER;
@@ -86,6 +87,7 @@
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.power.V1_0.PowerHint;
+import android.net.Uri;
import android.os.FactoryTest;
import android.os.IBinder;
import android.os.RemoteException;
@@ -108,6 +110,11 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ResolverActivity;
+import com.android.internal.util.ToBooleanFunction;
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledFunction;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.LocalServices;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.AppTimeTracker;
@@ -121,6 +128,7 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/**
@@ -201,14 +209,46 @@
// Whether tasks have moved and we need to rank the tasks before next OOM scoring
private boolean mTaskLayersChanged = true;
+ private int mTmpTaskLayerRank;
- private final ArrayList<ActivityRecord> mTmpActivityList = new ArrayList<>();
+ private boolean mTmpBoolean;
+ private RemoteException mTmpRemoteException;
private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
- static class FindTaskResult {
+ static class FindTaskResult implements ToBooleanFunction<Task> {
ActivityRecord mRecord;
boolean mIdealMatch;
+ private ActivityRecord mTarget;
+ private Intent intent;
+ private ActivityInfo info;
+ private ComponentName cls;
+ private int userId;
+ private boolean isDocument;
+ private Uri documentData;
+
+ /**
+ * Returns the top activity in any existing task matching the given Intent in the input
+ * result. Returns null if no such task is found.
+ */
+ void process(ActivityRecord target, ActivityStack parent) {
+ mTarget = target;
+
+ intent = target.intent;
+ info = target.info;
+ cls = intent.getComponent();
+ if (info.targetActivity != null) {
+ cls = new ComponentName(info.packageName, info.targetActivity);
+ }
+ userId = UserHandle.getUserId(info.applicationInfo.uid);
+ isDocument = intent != null & intent.isDocument();
+ // If documentData is non-null then it must match the existing task data.
+ documentData = isDocument ? intent.getData() : null;
+
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + parent);
+ parent.forAllTasks(this);
+ }
+
void clear() {
mRecord = null;
mIdealMatch = false;
@@ -218,6 +258,84 @@
mRecord = result.mRecord;
mIdealMatch = result.mIdealMatch;
}
+
+ @Override
+ public boolean apply(Task task) {
+ if (task.voiceSession != null) {
+ // We never match voice sessions; those always run independently.
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": voice session");
+ return false;
+ }
+ if (task.mUserId != userId) {
+ // Looking for a different task.
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": different user");
+ return false;
+ }
+
+ // Overlays should not be considered as the task's logical top activity.
+ final ActivityRecord r = task.getTopNonFinishingActivity(false /* includeOverlays */);
+ if (r == null || r.finishing || r.mUserId != userId ||
+ r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch root " + r);
+ return false;
+ }
+ if (!r.hasCompatibleActivityType(mTarget)) {
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch activity type");
+ return false;
+ }
+
+ final Intent taskIntent = task.intent;
+ final Intent affinityIntent = task.affinityIntent;
+ final boolean taskIsDocument;
+ final Uri taskDocumentData;
+ if (taskIntent != null && taskIntent.isDocument()) {
+ taskIsDocument = true;
+ taskDocumentData = taskIntent.getData();
+ } else if (affinityIntent != null && affinityIntent.isDocument()) {
+ taskIsDocument = true;
+ taskDocumentData = affinityIntent.getData();
+ } else {
+ taskIsDocument = false;
+ taskDocumentData = null;
+ }
+
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
+ + (task.realActivity != null ? task.realActivity.flattenToShortString() : "")
+ + "/aff=" + r.getTask().rootAffinity + " to new cls="
+ + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
+ // TODO Refactor to remove duplications. Check if logic can be simplified.
+ if (task.realActivity != null && task.realActivity.compareTo(cls) == 0
+ && Objects.equals(documentData, taskDocumentData)) {
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
+ //dump();
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS,
+ "For Intent " + intent + " bringing to top: " + r.intent);
+ mRecord = r;
+ mIdealMatch = true;
+ return true;
+ } else if (affinityIntent != null && affinityIntent.getComponent() != null &&
+ affinityIntent.getComponent().compareTo(cls) == 0 &&
+ Objects.equals(documentData, taskDocumentData)) {
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS,
+ "For Intent " + intent + " bringing to top: " + r.intent);
+ mRecord = r;
+ mIdealMatch = true;
+ return true;
+ } else if (!isDocument && !taskIsDocument
+ && mRecord == null && task.rootAffinity != null) {
+ if (task.rootAffinity.equals(mTarget.taskAffinity)) {
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
+ // It is possible for multiple tasks to have the same root affinity especially
+ // if they are in separate stacks. We save off this candidate, but keep looking
+ // to see if there is a better candidate.
+ mRecord = r;
+ mIdealMatch = false;
+ }
+ } else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
+
+ return false;
+ }
}
RootActivityContainer(ActivityTaskManagerService service) {
@@ -772,27 +890,21 @@
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
final ActivityStack stack = display.getFocusedStack();
- if (stack != null) {
- stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList);
- final ActivityRecord top = stack.topRunningActivityLocked();
- final int size = mTmpActivityList.size();
- for (int i = 0; i < size; i++) {
- final ActivityRecord activity = mTmpActivityList.get(i);
- if (activity.app == null && app.mUid == activity.info.applicationInfo.uid
- && processName.equals(activity.processName)) {
- try {
- if (mStackSupervisor.realStartActivityLocked(activity, app,
- top == activity /* andResume */, true /* checkConfig */)) {
- didSomething = true;
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Exception in new application when starting activity "
- + top.intent.getComponent().flattenToShortString(), e);
- throw e;
- }
- }
- }
+ if (stack == null) {
+ continue;
}
+
+ mTmpRemoteException = null;
+ mTmpBoolean = false; // Set to true if an activity was started.
+ final PooledFunction c = PooledLambda.obtainFunction(
+ RootActivityContainer::startActivityForAttachedApplicationIfNeeded, this,
+ PooledLambda.__(ActivityRecord.class), app, stack.topRunningActivityLocked());
+ stack.forAllActivities(c);
+ c.recycle();
+ if (mTmpRemoteException != null) {
+ throw mTmpRemoteException;
+ }
+ didSomething |= mTmpBoolean;
}
if (!didSomething) {
ensureActivitiesVisible(null, 0, false /* preserve_windows */);
@@ -800,6 +912,27 @@
return didSomething;
}
+ private boolean startActivityForAttachedApplicationIfNeeded(ActivityRecord r,
+ WindowProcessController app, ActivityRecord top) {
+ if (r.finishing || !r.okToShowLocked() || !r.visibleIgnoringKeyguard || r.app != null
+ || app.mUid != r.info.applicationInfo.uid || !app.mName.equals(r.processName)) {
+ return false;
+ }
+
+ try {
+ if (mStackSupervisor.realStartActivityLocked(r, app, top == r /*andResume*/,
+ true /*checkConfig*/)) {
+ mTmpBoolean = true;
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Exception in new application when starting activity "
+ + top.intent.getComponent().flattenToShortString(), e);
+ mTmpRemoteException = e;
+ return true;
+ }
+ return false;
+ }
+
/**
* Make sure that all activities that need to be visible in the system actually are and update
* their configuration.
@@ -1526,14 +1659,12 @@
}
}
- void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getChildAt(stackNdx);
- stack.addStartingWindowsForVisibleActivities(taskSwitch);
+ void addStartingWindowsForVisibleActivities() {
+ mRootWindowContainer.forAllActivities((r) -> {
+ if (r.mVisibleRequested) {
+ r.showStartingWindow(null /* prev */, false /* newTask */, true /*taskSwitch*/);
}
- }
+ });
}
void invalidateTaskLayers() {
@@ -1541,27 +1672,37 @@
}
void rankTaskLayersIfNeeded() {
- if (!mTaskLayersChanged) {
+ if (!mTaskLayersChanged || mRootWindowContainer == null) {
return;
}
mTaskLayersChanged = false;
- for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); displayNdx++) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- int baseLayer = 0;
- for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getChildAt(stackNdx);
- baseLayer += stack.rankTaskLayers(baseLayer);
- }
+ mTmpTaskLayerRank = 0;
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ RootActivityContainer::rankTaskLayerForActivity, this,
+ PooledLambda.__(ActivityRecord.class));
+ mRootWindowContainer.forAllActivities(c);
+ c.recycle();
+ }
+
+ private void rankTaskLayerForActivity(ActivityRecord r) {
+ if (r.canBeTopRunning() && r.mVisibleRequested) {
+ r.getTask().mLayerRank = ++mTmpTaskLayerRank;
+ } else {
+ r.getTask().mLayerRank = -1;
}
}
void clearOtherAppTimeTrackers(AppTimeTracker except) {
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getChildAt(stackNdx);
- stack.clearOtherAppTimeTrackers(except);
- }
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ RootActivityContainer::clearOtherAppTimeTrackers,
+ PooledLambda.__(ActivityRecord.class), except);
+ mRootWindowContainer.forAllActivities(c);
+ c.recycle();
+ }
+
+ private static void clearOtherAppTimeTrackers(ActivityRecord r, AppTimeTracker except) {
+ if ( r.appTimeTracker != except) {
+ r.appTimeTracker = null;
}
}
@@ -1575,30 +1716,6 @@
}
}
- void releaseSomeActivitiesLocked(WindowProcessController app, String reason) {
- // Tasks is non-null only if two or more tasks are found.
- ArraySet<Task> tasks = app.getReleaseSomeActivitiesTasks();
- if (tasks == null) {
- if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Didn't find two or more tasks to release");
- return;
- }
- // If we have activities in multiple tasks that are in a position to be destroyed,
- // let's iterate through the tasks and release the oldest one.
- final int numDisplays = mActivityDisplays.size();
- for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- final int stackCount = display.getChildCount();
- // Step through all stacks starting from behind, to hit the oldest things first.
- for (int stackNdx = 0; stackNdx < stackCount; stackNdx++) {
- final ActivityStack stack = display.getChildAt(stackNdx);
- // Try to release activities in this stack; if we manage to, we are done.
- if (stack.releaseSomeActivitiesLocked(app, tasks, reason) > 0) {
- return;
- }
- }
- }
- }
-
// Tries to put all activity stacks to sleep. Returns true if all stacks were
// successfully put to sleep.
boolean putStacksToSleep(boolean allowDelay, boolean shuttingDown) {
@@ -1625,28 +1742,52 @@
}
void handleAppCrash(WindowProcessController app) {
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getChildAt(stackNdx);
- stack.handleAppCrash(app);
- }
- }
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ RootActivityContainer::handleAppCrash, PooledLambda.__(ActivityRecord.class), app);
+ mRootWindowContainer.forAllActivities(c);
+ c.recycle();
+ }
+
+ private static void handleAppCrash(ActivityRecord r, WindowProcessController app) {
+ if (r.app != app) return;
+ Slog.w(TAG, " Force finishing activity "
+ + r.intent.getComponent().flattenToShortString());
+ // Force the destroy to skip right to removal.
+ r.app = null;
+ r.getDisplay().mDisplayContent.prepareAppTransition(
+ TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
+ r.destroyIfPossible("handleAppCrashed");
}
ActivityRecord findActivity(Intent intent, ActivityInfo info, boolean compareIntentFilters) {
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getChildAt(stackNdx);
- final ActivityRecord ar = stack.findActivityLocked(
- intent, info, compareIntentFilters);
- if (ar != null) {
- return ar;
- }
+ ComponentName cls = intent.getComponent();
+ if (info.targetActivity != null) {
+ cls = new ComponentName(info.packageName, info.targetActivity);
+ }
+ final int userId = UserHandle.getUserId(info.applicationInfo.uid);
+
+ final PooledPredicate p = PooledLambda.obtainPredicate(
+ RootActivityContainer::matchesActivity, PooledLambda.__(ActivityRecord.class),
+ userId, compareIntentFilters, intent, cls);
+ final ActivityRecord r = mRootWindowContainer.getActivity(p);
+ p.recycle();
+ return r;
+ }
+
+ private static boolean matchesActivity(ActivityRecord r, int userId,
+ boolean compareIntentFilters, Intent intent, ComponentName cls) {
+ if (!r.canBeTopRunning() || r.mUserId != userId) return false;
+
+ if (compareIntentFilters) {
+ if (r.intent.filterEquals(intent)) {
+ return true;
+ }
+ } else {
+ if (r.intent.getComponent().equals(cls)) {
+ return true;
}
}
- return null;
+ return false;
}
boolean hasAwakeDisplay() {
@@ -1978,39 +2119,104 @@
}
void closeSystemDialogs() {
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getChildAt(stackNdx);
- stack.closeSystemDialogsLocked();
+ mRootWindowContainer.forAllActivities((r) -> {
+ if ((r.info.flags & ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
+ r.finishIfPossible("close-sys", true /* oomAdj */);
}
+ });
+ }
+
+ FinishDisabledPackageActivitiesHelper mFinishDisabledPackageActivitiesHelper =
+ new FinishDisabledPackageActivitiesHelper();
+ class FinishDisabledPackageActivitiesHelper {
+ private boolean mDidSomething;
+ private String mPackageName;
+ private Set<String> mFilterByClasses;
+ private boolean mDoit;
+ private boolean mEvenPersistent;
+ private int mUserId;
+ private Task mLastTask;
+ private ComponentName mHomeActivity;
+
+ private void reset(String packageName, Set<String> filterByClasses,
+ boolean doit, boolean evenPersistent, int userId) {
+ mDidSomething = false;
+ mPackageName = packageName;
+ mFilterByClasses = filterByClasses;
+ mDoit = doit;
+ mEvenPersistent = evenPersistent;
+ mUserId = userId;
+ mLastTask = null;
+ mHomeActivity = null;
+ }
+
+ boolean process(String packageName, Set<String> filterByClasses,
+ boolean doit, boolean evenPersistent, int userId) {
+ reset(packageName, filterByClasses, doit, evenPersistent, userId);
+
+ final PooledFunction f = PooledLambda.obtainFunction(
+ FinishDisabledPackageActivitiesHelper::processActivity, this,
+ PooledLambda.__(ActivityRecord.class));
+ mRootWindowContainer.forAllActivities(f);
+ f.recycle();
+ return mDidSomething;
+ }
+
+ private boolean processActivity(ActivityRecord r) {
+ final boolean sameComponent =
+ (r.packageName.equals(mPackageName) && (mFilterByClasses == null
+ || mFilterByClasses.contains(r.mActivityComponent.getClassName())))
+ || (mPackageName == null && r.mUserId == mUserId);
+ if ((mUserId == UserHandle.USER_ALL || r.mUserId == mUserId)
+ && (sameComponent || r.getTask() == mLastTask)
+ && (r.app == null || mEvenPersistent || !r.app.isPersistent())) {
+ if (!mDoit) {
+ if (r.finishing) {
+ // If this activity is just finishing, then it is not
+ // interesting as far as something to stop.
+ return false;
+ }
+ return true;
+ }
+ if (r.isActivityTypeHome()) {
+ if (mHomeActivity != null && mHomeActivity.equals(r.mActivityComponent)) {
+ Slog.i(TAG, "Skip force-stop again " + r);
+ return false;
+ } else {
+ mHomeActivity = r.mActivityComponent;
+ }
+ }
+ mDidSomething = true;
+ Slog.i(TAG, " Force finishing activity " + r);
+ mLastTask = r.getTask();
+ r.finishIfPossible("force-stop", true);
+ }
+
+ return false;
}
}
/** @return true if some activity was finished (or would have finished if doit were true). */
boolean finishDisabledPackageActivities(String packageName, Set<String> filterByClasses,
boolean doit, boolean evenPersistent, int userId) {
- boolean didSomething = false;
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getChildAt(stackNdx);
- if (stack.finishDisabledPackageActivitiesLocked(
- packageName, filterByClasses, doit, evenPersistent, userId)) {
- didSomething = true;
- }
- }
- }
- return didSomething;
+ return mFinishDisabledPackageActivitiesHelper.process(packageName, filterByClasses, doit,
+ evenPersistent, userId);
}
void updateActivityApplicationInfo(ApplicationInfo aInfo) {
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getChildAt(stackNdx);
- stack.updateActivityApplicationInfoLocked(aInfo);
- }
+ final String packageName = aInfo.packageName;
+ final int userId = UserHandle.getUserId(aInfo.uid);
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ RootActivityContainer::updateActivityApplicationInfo,
+ PooledLambda.__(ActivityRecord.class), aInfo, userId, packageName);
+ mRootWindowContainer.forAllActivities(c);
+ c.recycle();
+ }
+
+ private static void updateActivityApplicationInfo(
+ ActivityRecord r, ApplicationInfo aInfo, int userId, String packageName) {
+ if (r.mUserId == userId && packageName.equals(r.packageName)) {
+ r.updateApplicationInfo(aInfo);
}
}
@@ -2063,7 +2269,7 @@
// If the focused stack is not null or not empty, there should have some activities
// resuming or resumed. Make sure these activities are idle.
final ActivityStack stack = display.getFocusedStack();
- if (stack == null || stack.numActivities() == 0) {
+ if (stack == null || !stack.hasActivity()) {
continue;
}
final ActivityRecord resumedActivity = stack.getResumedActivity();
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 619b71c..88a38e0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -67,7 +67,6 @@
import static com.android.server.am.TaskRecordProto.RESIZE_MODE;
import static com.android.server.am.TaskRecordProto.STACK_ID;
import static com.android.server.am.TaskRecordProto.TASK;
-import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -138,6 +137,10 @@
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.util.ToBooleanFunction;
import com.android.internal.util.XmlUtils;
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledFunction;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.protolog.common.ProtoLog;
import com.android.server.wm.ActivityStack.ActivityState;
@@ -152,8 +155,9 @@
import java.util.ArrayList;
import java.util.Objects;
import java.util.function.Consumer;
+import java.util.function.Predicate;
-class Task extends WindowContainer<ActivityRecord> implements ConfigurationContainerListener {
+class Task extends WindowContainer<WindowContainer> {
private static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_ATM;
private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
@@ -382,6 +386,44 @@
/** @see #setCanAffectSystemUiFlags */
private boolean mCanAffectSystemUiFlags = true;
+ private static Exception sTmpException;
+
+ private final FindRootHelper mFindRootHelper = new FindRootHelper();
+ private class FindRootHelper {
+ private ActivityRecord mRoot;
+
+ private void clear() {
+ mRoot = null;
+ }
+
+ ActivityRecord findRoot(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) {
+ final PooledFunction f = PooledLambda.obtainFunction(FindRootHelper::processActivity,
+ this, PooledLambda.__(ActivityRecord.class), ignoreRelinquishIdentity,
+ setToBottomIfNone);
+ clear();
+ forAllActivities(f, false /*traverseTopToBottom*/);
+ f.recycle();
+ return mRoot;
+ }
+
+ private boolean processActivity(ActivityRecord r,
+ boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) {
+ if (mRoot == null && setToBottomIfNone) {
+ // This is the first activity we are process. Set it as the candidate root in case
+ // we don't find a better one.
+ mRoot = r;
+ }
+
+ if (r.finishing) return false;
+
+ // Set this as the candidate root since it isn't finishing.
+ mRoot = r;
+
+ // Only end search if we are ignore relinquishing identity or we are not relinquishing.
+ return ignoreRelinquishIdentity || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
+ }
+ }
+
/**
* Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
* ActivityInfo, Intent, TaskDescription)} instead.
@@ -464,7 +506,7 @@
mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
}
- void cleanUpResourcesForDestroy() {
+ private void cleanUpResourcesForDestroy() {
if (hasChild()) {
return;
}
@@ -931,10 +973,11 @@
super.onParentChanged(newParent, oldParent);
if (oldStack != null) {
- for (int i = getChildCount() - 1; i >= 0; --i) {
- final ActivityRecord activity = getChildAt(i);
- oldStack.onActivityRemovedFromStack(activity);
- }
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ ActivityStack::onActivityRemovedFromStack, oldStack,
+ PooledLambda.__(ActivityRecord.class));
+ forAllActivities(c);
+ c.recycle();
if (oldStack.inPinnedWindowingMode()
&& (newStack == null || !newStack.inPinnedWindowingMode())) {
@@ -945,10 +988,11 @@
}
if (newStack != null) {
- for (int i = getChildCount() - 1; i >= 0; --i) {
- final ActivityRecord activity = getChildAt(i);
- newStack.onActivityAddedToStack(activity);
- }
+ final PooledConsumer c = PooledLambda.obtainConsumer(
+ ActivityStack::onActivityAddedToStack, newStack,
+ PooledLambda.__(ActivityRecord.class));
+ forAllActivities(c);
+ c.recycle();
// TODO: Ensure that this is actually necessary here
// Notify the voice session if required
@@ -1068,25 +1112,11 @@
}
ActivityRecord getRootActivity(boolean setToBottomIfNone) {
- return getRootActivity(false /*ignoreRelinquishIdentity*/, false /*setToBottomIfNone*/);
+ return getRootActivity(false /*ignoreRelinquishIdentity*/, setToBottomIfNone);
}
ActivityRecord getRootActivity(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) {
- ActivityRecord root;
- if (ignoreRelinquishIdentity) {
- root = getActivity((r) -> !r.finishing, false /*traverseTopToBottom*/);
- } else {
- root = getActivity((r) ->
- !r.finishing && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0,
- false /*traverseTopToBottom*/);
- }
-
- if (root == null && setToBottomIfNone) {
- // All activities in the task are either finishing or relinquish task identity.
- // But we still want to update the intent, so let's use the bottom activity.
- root = getActivity((r) -> true, false /*traverseTopToBottom*/);
- }
- return root;
+ return mFindRootHelper.findRoot(ignoreRelinquishIdentity, setToBottomIfNone);
}
ActivityRecord getTopNonFinishingActivity() {
@@ -1094,101 +1124,42 @@
}
ActivityRecord getTopNonFinishingActivity(boolean includeOverlays) {
- for (int i = getChildCount() - 1; i >= 0; --i) {
- final ActivityRecord r = getChildAt(i);
- if (r.finishing || (!includeOverlays && r.mTaskOverlay)) {
- continue;
- }
- return r;
- }
- return null;
+ return getTopActivity(false /*includeFinishing*/, includeOverlays);
}
ActivityRecord topRunningActivityLocked() {
- if (mStack != null) {
- for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- ActivityRecord r = getChildAt(activityNdx);
- if (!r.finishing && r.okToShowLocked()) {
- return r;
- }
- }
+ if (getParent() == null) {
+ return null;
}
- return null;
+ return getActivity(ActivityRecord::canBeTopRunning);
}
/**
* Return true if any activities in this task belongs to input uid.
*/
- boolean containsAppUid(int uid) {
- for (int i = getChildCount() - 1; i >= 0; --i) {
- final ActivityRecord r = getChildAt(i);
- if (r.getUid() == uid) {
- return true;
- }
- }
- return false;
- }
-
- void getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities) {
- if (mStack != null) {
- for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- ActivityRecord r = getChildAt(activityNdx);
- if (!r.finishing && r.okToShowLocked() && r.visibleIgnoringKeyguard) {
- outActivities.add(r);
- }
- }
- }
+ boolean isUidPresent(int uid) {
+ final PooledPredicate p = PooledLambda.obtainPredicate(
+ ActivityRecord::isUid, PooledLambda.__(ActivityRecord.class), uid);
+ final boolean isUidPresent = getActivity(p) != null;
+ p.recycle();
+ return isUidPresent;
}
ActivityRecord topRunningActivityWithStartingWindowLocked() {
- if (mStack != null) {
- for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- ActivityRecord r = getChildAt(activityNdx);
- if (r.mStartingWindowState != STARTING_WINDOW_SHOWN
- || r.finishing || !r.okToShowLocked()) {
- continue;
- }
- return r;
- }
+ if (getParent() == null) {
+ return null;
}
- return null;
+ return getActivity((r) -> r.mStartingWindowState == STARTING_WINDOW_SHOWN
+ && r.canBeTopRunning());
}
/**
* Return the number of running activities, and the number of non-finishing/initializing
* activities in the provided {@param reportOut} respectively.
*/
- void getNumRunningActivities(TaskActivitiesReport reportOut) {
+ private void getNumRunningActivities(TaskActivitiesReport reportOut) {
reportOut.reset();
- for (int i = getChildCount() - 1; i >= 0; --i) {
- final ActivityRecord r = getChildAt(i);
- if (r.finishing) {
- continue;
- }
-
- reportOut.base = r;
-
- // Increment the total number of non-finishing activities
- reportOut.numActivities++;
-
- if (reportOut.top == null || (reportOut.top.isState(ActivityState.INITIALIZING))) {
- reportOut.top = r;
- // Reset the number of running activities until we hit the first non-initializing
- // activity
- reportOut.numRunning = 0;
- }
- if (r.attachedToProcess()) {
- // Increment the number of actually running activities
- reportOut.numRunning++;
- }
- }
- }
-
- boolean okToShowLocked() {
- // NOTE: If {@link Task#topRunningActivity} return is not null then it is
- // okay to show the activity when locked.
- return mAtmService.mStackSupervisor.isCurrentProfileLocked(mUserId)
- || topRunningActivityLocked() != null;
+ forAllActivities(reportOut);
}
/**
@@ -1212,10 +1183,11 @@
}
@Override
- void addChild(ActivityRecord r, int index) {
+ void addChild(WindowContainer child, int index) {
// If this task had any child before we added this one.
boolean hadChild = hasChild();
+ final ActivityRecord r = (ActivityRecord) child;
index = getAdjustedAddPosition(r, index);
super.addChild(r, index);
@@ -1244,9 +1216,6 @@
}
updateEffectiveIntent();
- if (r.isPersistable()) {
- mAtmService.notifyTaskPersisterLocked(this, false);
- }
// Make sure the list of display UID whitelists is updated
// now that this record is in a new task.
@@ -1258,16 +1227,13 @@
}
@Override
- void removeChild(ActivityRecord r) {
+ void removeChild(WindowContainer r) {
if (!mChildren.contains(r)) {
Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this);
return;
}
super.removeChild(r);
- if (r.isPersistable()) {
- mAtmService.notifyTaskPersisterLocked(this, false);
- }
if (inPinnedWindowingMode()) {
// We normally notify listeners of task stack changes on pause, however pinned stack
@@ -1283,7 +1249,7 @@
// The following block can be executed multiple times if there is more than one overlay.
// {@link ActivityStackSupervisor#removeTaskByIdLocked} handles this by reverse lookup
// of the task by id and exiting early if not found.
- if (onlyHasTaskOverlayActivities(false /* excludingFinishing */)) {
+ if (onlyHasTaskOverlayActivities(true /*includeFinishing*/)) {
// When destroying a task, tell the supervisor to remove it so that any activity it
// has can be cleaned up correctly. This is currently the only place where we remove
// a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
@@ -1305,25 +1271,20 @@
/**
* @return whether or not there are ONLY task overlay activities in the stack.
- * If {@param excludeFinishing} is set, then ignore finishing activities in the check.
- * If there are no task overlay activities, this call returns false.
+ * If {@param includeFinishing} is set, then don't ignore finishing activities in the
+ * check. If there are no task overlay activities, this call returns false.
*/
- boolean onlyHasTaskOverlayActivities(boolean excludeFinishing) {
- int count = 0;
- for (int i = getChildCount() - 1; i >= 0; i--) {
- final ActivityRecord r = getChildAt(i);
- if (excludeFinishing && r.finishing) {
- continue;
- }
- if (!r.mTaskOverlay) {
- return false;
- }
- count++;
+ boolean onlyHasTaskOverlayActivities(boolean includeFinishing) {
+ if (getChildCount() == 0) {
+ return false;
}
- return count > 0;
+ if (includeFinishing) {
+ return getActivity((r) -> r.mTaskOverlay) != null;
+ }
+ return getActivity((r) -> !r.finishing && r.mTaskOverlay) != null;
}
- boolean autoRemoveFromRecents() {
+ private boolean autoRemoveFromRecents() {
// We will automatically remove the task either if it has explicitly asked for
// this, or it is empty and has never contained an activity that got shown to
// the user.
@@ -1335,24 +1296,21 @@
* task starting at a specified index.
*/
private void performClearTaskAtIndexLocked(String reason) {
- int numActivities = getChildCount();
- for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
- final ActivityRecord r = getChildAt(activityNdx);
- if (r.finishing) {
- continue;
- }
- if (mStack == null) {
+ // Broken down into to cases to avoid object create due to capturing mStack.
+ if (mStack == null) {
+ forAllActivities((r) -> {
+ if (r.finishing) return;
// Task was restored from persistent storage.
r.takeFromHistory();
removeChild(r);
- --activityNdx;
- --numActivities;
- } else if (r.finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason,
- false /* oomAdj */)
- == FINISH_RESULT_REMOVED) {
- --activityNdx;
- --numActivities;
- }
+ });
+ } else {
+ forAllActivities((r) -> {
+ if (r.finishing) return;
+ // TODO: figure-out how to avoid object creation due to capture of reason variable.
+ r.finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason,
+ false /* oomAdj */);
+ });
}
}
@@ -1383,50 +1341,43 @@
* @return Returns the old activity that should be continued to be used,
* or {@code null} if none was found.
*/
- final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
- int numActivities = getChildCount();
- for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
- ActivityRecord r = getChildAt(activityNdx);
- if (r.finishing) {
- continue;
- }
- if (r.mActivityComponent.equals(newR.mActivityComponent)) {
- // Here it is! Now finish everything in front...
- final ActivityRecord ret = r;
+ private ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
+ final ActivityRecord r = findActivityInHistory(newR.mActivityComponent);
+ if (r == null) return null;
- for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
- r = getChildAt(activityNdx);
- if (r.finishing) {
- continue;
- }
- ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */);
- if (opts != null) {
- ret.updateOptionsLocked(opts);
- }
- if (r.finishIfPossible("clear-task-stack", false /* oomAdj */)
- == FINISH_RESULT_REMOVED) {
- --activityNdx;
- --numActivities;
- }
- }
+ final PooledFunction f = PooledLambda.obtainFunction(Task::finishActivityAbove,
+ PooledLambda.__(ActivityRecord.class), r);
+ forAllActivities(f);
+ f.recycle();
- // Finally, if this is a normal launch mode (that is, not
- // expecting onNewIntent()), then we will finish the current
- // instance of the activity so a new fresh one can be started.
- if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
- && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
- && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
- if (!ret.finishing) {
- ret.finishIfPossible("clear-task-top", false /* oomAdj */);
- return null;
- }
- }
-
- return ret;
+ // Finally, if this is a normal launch mode (that is, not expecting onNewIntent()), then we
+ // will finish the current instance of the activity so a new fresh one can be started.
+ if (r.launchMode == ActivityInfo.LAUNCH_MULTIPLE
+ && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
+ && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
+ if (!r.finishing) {
+ r.finishIfPossible("clear-task-top", false /* oomAdj */);
+ return null;
}
}
- return null;
+ return r;
+ }
+
+ private static boolean finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity) {
+ // Stop operation once we reach the boundary activity.
+ if (r == boundaryActivity) return true;
+
+ if (!r.finishing) {
+ final ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */);
+ if (opts != null) {
+ // TODO: Why is this updating the boundary activity vs. the current activity???
+ boundaryActivity.updateOptionsLocked(opts);
+ }
+ r.finishIfPossible("clear-task-stack", false /* oomAdj */);
+ }
+
+ return false;
}
void removeTaskActivitiesLocked(String reason) {
@@ -1537,140 +1488,83 @@
* Find the activity in the history stack within the given task. Returns
* the index within the history at which it's found, or < 0 if not found.
*/
- final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
- final ComponentName realActivity = r.mActivityComponent;
- for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- ActivityRecord candidate = getChildAt(activityNdx);
- if (candidate.finishing) {
- continue;
- }
- if (candidate.mActivityComponent.equals(realActivity)) {
- return candidate;
- }
- }
- return null;
+ ActivityRecord findActivityInHistory(ComponentName component) {
+ final PooledPredicate p = PooledLambda.obtainPredicate(Task::matchesActivityInHistory,
+ PooledLambda.__(ActivityRecord.class), component);
+ final ActivityRecord r = getActivity(p);
+ p.recycle();
+ return r;
+ }
+
+ private static boolean matchesActivityInHistory(
+ ActivityRecord r, ComponentName activityComponent) {
+ return !r.finishing && r.mActivityComponent.equals(activityComponent);
}
/** Updates the last task description values. */
void updateTaskDescription() {
- // TODO(AM refactor): Cleanup to use findRootIndex()
- // Traverse upwards looking for any break between main task activities and
- // utility activities.
- int activityNdx;
- final int numActivities = getChildCount();
- final boolean relinquish = numActivities != 0
- && (getChildAt(0).info.flags & FLAG_RELINQUISH_TASK_IDENTITY) != 0;
- for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities; ++activityNdx) {
- final ActivityRecord r = getChildAt(activityNdx);
- if (relinquish && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
- // This will be the top activity for determining taskDescription. Pre-inc to
- // overcome initial decrement below.
- ++activityNdx;
- break;
- }
- if (r.intent != null
- && (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
- break;
- }
+ final ActivityRecord root = getRootActivity(true);
+ if (root == null) return;
+
+ final TaskDescription taskDescription = new TaskDescription();
+ final PooledFunction f = PooledLambda.obtainFunction(
+ Task::setTaskDescriptionFromActivityAboveRoot,
+ PooledLambda.__(ActivityRecord.class), root, taskDescription);
+ forAllActivities(f);
+ f.recycle();
+ taskDescription.setResizeMode(mResizeMode);
+ taskDescription.setMinWidth(mMinWidth);
+ taskDescription.setMinHeight(mMinHeight);
+ setTaskDescription(taskDescription);
+ // Update the task affiliation color if we are the parent of the group
+ if (mTaskId == mAffiliatedTaskId) {
+ mAffiliatedTaskColor = taskDescription.getPrimaryColor();
}
- if (activityNdx > 0) {
- // Traverse downwards starting below break looking for set label, icon.
- // Note that if there are activities in the task but none of them set the
- // recent activity values, then we do not fall back to the last set
- // values in the Task.
- String label = null;
- String iconFilename = null;
- int iconResource = -1;
- int colorPrimary = 0;
- int colorBackground = 0;
- int statusBarColor = 0;
- int navigationBarColor = 0;
- boolean statusBarContrastWhenTransparent = false;
- boolean navigationBarContrastWhenTransparent = false;
- boolean topActivity = true;
- for (--activityNdx; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = getChildAt(activityNdx);
- if (r.mTaskOverlay) {
- continue;
- }
- if (r.taskDescription != null) {
- if (label == null) {
- label = r.taskDescription.getLabel();
- }
- if (iconResource == -1) {
- iconResource = r.taskDescription.getIconResource();
- }
- if (iconFilename == null) {
- iconFilename = r.taskDescription.getIconFilename();
- }
- if (colorPrimary == 0) {
- colorPrimary = r.taskDescription.getPrimaryColor();
- }
- if (topActivity) {
- colorBackground = r.taskDescription.getBackgroundColor();
- statusBarColor = r.taskDescription.getStatusBarColor();
- navigationBarColor = r.taskDescription.getNavigationBarColor();
- statusBarContrastWhenTransparent =
- r.taskDescription.getEnsureStatusBarContrastWhenTransparent();
- navigationBarContrastWhenTransparent =
- r.taskDescription.getEnsureNavigationBarContrastWhenTransparent();
- }
- }
- topActivity = false;
- }
- final TaskDescription taskDescription = new TaskDescription(label, null, iconResource,
- iconFilename, colorPrimary, colorBackground, statusBarColor, navigationBarColor,
- statusBarContrastWhenTransparent, navigationBarContrastWhenTransparent,
- mResizeMode, mMinWidth, mMinHeight);
- setTaskDescription(taskDescription);
- // Update the task affiliation color if we are the parent of the group
- if (mTaskId == mAffiliatedTaskId) {
- mAffiliatedTaskColor = taskDescription.getPrimaryColor();
- }
- mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged(
- getTaskInfo());
- }
+ mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged(
+ getTaskInfo());
}
- /**
- * Find the index of the root activity in the task. It will be the first activity from the
- * bottom that is not finishing.
- *
- * @param effectiveRoot Flag indicating whether 'effective root' should be returned - an
- * activity that defines the task identity (its base intent). It's the
- * first one that does not have
- * {@link ActivityInfo#FLAG_RELINQUISH_TASK_IDENTITY}.
- * @return index of the 'root' or 'effective' root in the list of activities, -1 if no eligible
- * activity was found.
- */
- int findRootIndex(boolean effectiveRoot) {
- int effectiveNdx = -1;
- final int topActivityNdx = getChildCount() - 1;
- for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) {
- final ActivityRecord r = getChildAt(activityNdx);
- if (r.finishing) {
- continue;
+ private static boolean setTaskDescriptionFromActivityAboveRoot(
+ ActivityRecord r, ActivityRecord root, TaskDescription td) {
+ if (!r.mTaskOverlay && r.taskDescription != null) {
+ final TaskDescription atd = r.taskDescription;
+ if (td.getLabel() == null) {
+ td.setLabel(atd.getLabel());
}
- effectiveNdx = activityNdx;
- if (!effectiveRoot || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
- break;
+ if (td.getIconResource() == 0) {
+ td.setIcon(atd.getIconResource());
}
+ if (td.getIconFilename() == null) {
+ td.setIconFilename(atd.getIconFilename());
+ }
+ if (td.getPrimaryColor() == 0) {
+ td.setPrimaryColor(atd.getPrimaryColor());
+ }
+ if (td.getBackgroundColor() == 0) {
+ td.setBackgroundColor(atd.getBackgroundColor());
+ }
+ if (td.getStatusBarColor() == 0) {
+ td.setStatusBarColor(atd.getStatusBarColor());
+ td.setEnsureStatusBarContrastWhenTransparent(
+ atd.getEnsureStatusBarContrastWhenTransparent());
+ }
+ if (td.getNavigationBarColor() == 0) {
+ td.setNavigationBarColor(atd.getNavigationBarColor());
+ td.setEnsureNavigationBarContrastWhenTransparent(
+ atd.getEnsureNavigationBarContrastWhenTransparent());
+ }
+
}
- return effectiveNdx;
+
+ // End search once we get to root.
+ return r == root;
}
// TODO (AM refactor): Invoke automatically when there is a change in children
@VisibleForTesting
void updateEffectiveIntent() {
- int effectiveRootIndex = findRootIndex(true /* effectiveRoot */);
- if (effectiveRootIndex == -1) {
- // All activities in the task are either finishing or relinquish task identity.
- // But we still want to update the intent, so let's use the bottom activity.
- effectiveRootIndex = 0;
- }
- final ActivityRecord r = getChildAt(effectiveRootIndex);
- setIntent(r);
-
+ final ActivityRecord root = getRootActivity(true /*setToBottomIfNone*/);
+ setIntent(root);
// Update the task description when the activities change
updateTaskDescription();
}
@@ -2220,15 +2114,6 @@
return mLastNonFullscreenBounds;
}
- void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
- for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = getChildAt(activityNdx);
- if (r.mVisibleRequested) {
- r.showStartingWindow(null /* prev */, false /* newTask */, taskSwitch);
- }
- }
- }
-
void setRootProcess(WindowProcessController proc) {
clearRootProcess();
if (intent != null
@@ -2245,12 +2130,6 @@
}
}
- void clearAllPendingOptions() {
- for (int i = getChildCount() - 1; i >= 0; i--) {
- getChildAt(i).clearOptionsLocked(false /* withAbort */);
- }
- }
-
@Override
DisplayContent getDisplayContent() {
return getTaskStack() != null ? getTaskStack().getDisplayContent() : null;
@@ -2260,20 +2139,14 @@
return (ActivityStack) getParent();
}
+ // TODO(task-hierarchy): Needs to take a generic WindowManager when task contains other tasks.
int getAdjustedAddPosition(ActivityRecord r, int suggestedPosition) {
int maxPosition = mChildren.size();
if (!r.mTaskOverlay) {
// We want to place all non-overlay activities below overlays.
- while (maxPosition > 0) {
- final ActivityRecord current = mChildren.get(maxPosition - 1);
- if (current.mTaskOverlay) {
- --maxPosition;
- continue;
- }
- break;
- }
- if (maxPosition < 0) {
- maxPosition = 0;
+ final ActivityRecord bottomMostOverlay = getActivity((ar) -> ar.mTaskOverlay, false);
+ if (bottomMostOverlay != null) {
+ maxPosition = Math.max(mChildren.indexOf(bottomMostOverlay) - 1, 0);
}
}
@@ -2281,18 +2154,13 @@
}
@Override
- void positionChildAt(int position, ActivityRecord child, boolean includingParents) {
- position = getAdjustedAddPosition(child, position);
+ void positionChildAt(int position, WindowContainer child, boolean includingParents) {
+ position = getAdjustedAddPosition((ActivityRecord) child, position);
super.positionChildAt(position, child, includingParents);
}
private boolean hasWindowsAlive() {
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- if (mChildren.get(i).hasWindowsAlive()) {
- return true;
- }
- }
- return false;
+ return getActivity(ActivityRecord::hasWindowsAlive) != null;
}
@VisibleForTesting
@@ -2522,26 +2390,21 @@
* @param out Rect containing the max visible bounds.
* @return true if the task has some visible app windows; false otherwise.
*/
- private boolean getMaxVisibleBounds(Rect out) {
- boolean foundTop = false;
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final ActivityRecord token = mChildren.get(i);
- // skip hidden (or about to hide) apps
- if (token.mIsExiting || !token.isClientVisible() || !token.mVisibleRequested) {
- continue;
- }
- final WindowState win = token.findMainWindow();
- if (win == null) {
- continue;
- }
- if (!foundTop) {
- foundTop = true;
- out.setEmpty();
- }
-
- win.getMaxVisibleBounds(out);
+ private static void getMaxVisibleBounds(ActivityRecord token, Rect out, boolean[] foundTop) {
+ // skip hidden (or about to hide) apps
+ if (token.mIsExiting || !token.isClientVisible() || !token.mVisibleRequested) {
+ return;
}
- return foundTop;
+ final WindowState win = token.findMainWindow();
+ if (win == null) {
+ return;
+ }
+ if (!foundTop[0]) {
+ foundTop[0] = true;
+ out.setEmpty();
+ }
+
+ win.getMaxVisibleBounds(out);
}
/** Bounds of the task to be used for dimming, as well as touch related tests. */
@@ -2551,8 +2414,14 @@
// a DimLayer anyway if we weren't visible.
final boolean dockedResizing = displayContent != null
&& displayContent.mDividerControllerLocked.isResizing();
- if (inFreeformWindowingMode() && getMaxVisibleBounds(out)) {
- return;
+ if (inFreeformWindowingMode()) {
+ boolean[] foundTop = { false };
+ final PooledConsumer c = PooledLambda.obtainConsumer(Task::getMaxVisibleBounds,
+ PooledLambda.__(ActivityRecord.class), out, foundTop);
+ c.recycle();
+ if (foundTop[0]) {
+ return;
+ }
}
if (!matchParentBounds()) {
@@ -2658,8 +2527,9 @@
}
boolean showForAllUsers() {
- final int tokensCount = mChildren.size();
- return (tokensCount != 0) && mChildren.get(tokensCount - 1).mShowForAllUsers;
+ if (mChildren.isEmpty()) return false;
+ final ActivityRecord r = getTopNonFinishingActivity();
+ return r != null && r.mShowForAllUsers;
}
/**
@@ -2733,24 +2603,17 @@
}
ActivityRecord getTopFullscreenActivity() {
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final ActivityRecord activity = mChildren.get(i);
- final WindowState win = activity.findMainWindow();
- if (win != null && win.mAttrs.isFullscreen()) {
- return activity;
- }
- }
- return null;
+ return getActivity((r) -> {
+ final WindowState win = r.findMainWindow();
+ return (win != null && win.mAttrs.isFullscreen());
+ });
}
ActivityRecord getTopVisibleActivity() {
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final ActivityRecord activity = mChildren.get(i);
- if (!activity.mIsExiting && activity.isClientVisible() && activity.mVisibleRequested) {
- return activity;
- }
- }
- return null;
+ return getActivity((r) -> {
+ // skip hidden (or about to hide) apps
+ return !r.mIsExiting && r.isClientVisible() && r.mVisibleRequested;
+ });
}
void positionChildAtTop(ActivityRecord child) {
@@ -2806,6 +2669,13 @@
return callback.apply(this);
}
+ @Override
+ Task getTask(Predicate<Task> callback, boolean traverseTopToBottom) {
+ // I'm a task!
+ // TODO(task-hierarchy): Change to traverse children when tasks can contain other tasks.
+ return callback.test(this) ? this : null;
+ }
+
/**
* @param canAffectSystemUiFlags If false, all windows in this task can not affect SystemUI
* flags. See {@link WindowState#canAffectSystemUiFlags()}.
@@ -2861,10 +2731,9 @@
final long token = proto.start(fieldId);
super.writeToProto(proto, WINDOW_CONTAINER, logLevel);
proto.write(TaskProto.ID, mTaskId);
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final ActivityRecord activity = mChildren.get(i);
- activity.writeToProto(proto, APP_WINDOW_TOKENS, logLevel);
- }
+ forAllActivities((r) -> {
+ r.writeToProto(proto, APP_WINDOW_TOKENS, logLevel);
+ });
proto.write(FILLS_PARENT, matchParentBounds());
getBounds().writeToProto(proto, TaskProto.BOUNDS);
mOverrideDisplayedBounds.writeToProto(proto, DISPLAYED_BOUNDS);
@@ -2888,11 +2757,11 @@
final String triplePrefix = doublePrefix + " ";
final String quadruplePrefix = triplePrefix + " ";
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final ActivityRecord activity = mChildren.get(i);
- pw.println(triplePrefix + "Activity #" + i + " " + activity);
- activity.dump(pw, quadruplePrefix, dumpAll);
- }
+ int[] index = { 0 };
+ forAllActivities((r) -> {
+ pw.println(triplePrefix + "Activity #" + index[0]++ + " " + r);
+ r.dump(pw, quadruplePrefix, dumpAll);
+ });
}
/**
@@ -3071,10 +2940,10 @@
final long token = proto.start(fieldId);
writeToProtoInnerTaskOnly(proto, TASK, logLevel);
proto.write(com.android.server.am.TaskRecordProto.ID, mTaskId);
- for (int i = getChildCount() - 1; i >= 0; i--) {
- final ActivityRecord activity = getChildAt(i);
- activity.writeToProto(proto, ACTIVITIES);
- }
+
+ forAllActivities((r) -> {
+ r.writeToProto(proto, ACTIVITIES);
+ });
proto.write(STACK_ID, getStackId());
if (mLastNonFullscreenBounds != null) {
mLastNonFullscreenBounds.writeToProto(proto, LAST_NON_FULLSCREEN_BOUNDS);
@@ -3100,7 +2969,7 @@
}
/** @see #getNumRunningActivities(TaskActivitiesReport) */
- static class TaskActivitiesReport {
+ static class TaskActivitiesReport implements Consumer<ActivityRecord> {
int numRunning;
int numActivities;
ActivityRecord top;
@@ -3110,12 +2979,35 @@
numRunning = numActivities = 0;
top = base = null;
}
+
+ @Override
+ public void accept(ActivityRecord r) {
+ if (r.finishing) {
+ return;
+ }
+
+ base = r;
+
+ // Increment the total number of non-finishing activities
+ numActivities++;
+
+ if (top == null || (top.isState(ActivityState.INITIALIZING))) {
+ top = r;
+ // Reset the number of running activities until we hit the first non-initializing
+ // activity
+ numRunning = 0;
+ }
+ if (r.attachedToProcess()) {
+ // Increment the number of actually running activities
+ numRunning++;
+ }
+ }
}
/**
* Saves this {@link Task} to XML using given serializer.
*/
- void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
+ void saveToXml(XmlSerializer out) throws Exception {
if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
out.attribute(null, ATTR_TASKID, String.valueOf(mTaskId));
@@ -3181,19 +3073,33 @@
out.endTag(null, TAG_INTENT);
}
- final int numActivities = getChildCount();
- for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
- final ActivityRecord r = getChildAt(activityNdx);
- if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable()
- || ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
- | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT)
- && activityNdx > 0) {
- // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
- break;
- }
+ sTmpException = null;
+ final PooledFunction f = PooledLambda.obtainFunction(Task::saveActivityToXml,
+ PooledLambda.__(ActivityRecord.class), getBottomMostActivity(), out);
+ forAllActivities(f);
+ f.recycle();
+ if (sTmpException != null) {
+ throw sTmpException;
+ }
+ }
+
+ private static boolean saveActivityToXml(
+ ActivityRecord r, ActivityRecord first, XmlSerializer out) {
+ if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable()
+ || ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
+ | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT)
+ && r != first) {
+ // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
+ return true;
+ }
+ try {
out.startTag(null, TAG_ACTIVITY);
r.saveToXml(out);
out.endTag(null, TAG_ACTIVITY);
+ return false;
+ } catch (Exception e) {
+ sTmpException = e;
+ return true;
}
}
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index 1e2f0d0..eb130a1 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -514,7 +514,7 @@
mService = service;
}
- private StringWriter saveToXml(Task task) throws IOException, XmlPullParserException {
+ private StringWriter saveToXml(Task task) throws Exception {
if (DEBUG) Slog.d(TAG, "saveToXml: task=" + task);
final XmlSerializer xmlSerializer = new FastXmlSerializer();
StringWriter stringWriter = new StringWriter();
@@ -550,8 +550,7 @@
try {
if (DEBUG) Slog.d(TAG, "Saving task=" + task);
stringWriter = saveToXml(task);
- } catch (IOException e) {
- } catch (XmlPullParserException e) {
+ } catch (Exception e) {
}
}
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
index d07516a..5cbab5d 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotCache.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
@@ -48,9 +48,9 @@
if (entry != null) {
mAppTaskMap.remove(entry.topApp);
}
- final ActivityRecord top = task.getTopChild();
+ final ActivityRecord top = task.getTopMostActivity();
mAppTaskMap.put(top, task.mTaskId);
- mRunningCache.put(task.mTaskId, new CacheEntry(snapshot, task.getTopChild()));
+ mRunningCache.put(task.mTaskId, new CacheEntry(snapshot, top));
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index f83ceb0..c1a36c4 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -235,23 +235,18 @@
* children, which should be ignored.
*/
@Nullable private ActivityRecord findAppTokenForSnapshot(Task task) {
- for (int i = task.getChildCount() - 1; i >= 0; --i) {
- final ActivityRecord activity = task.getChildAt(i);
- if (activity == null || !activity.isSurfaceShowing()
- || activity.findMainWindow() == null) {
- continue;
+ return task.getActivity((r) -> {
+ if (r == null || !r.isSurfaceShowing() || r.findMainWindow() == null) {
+ return false;
}
- final boolean hasVisibleChild = activity.forAllWindows(
+ return r.forAllWindows(
// Ensure at least one window for the top app is visible before attempting to
// take a screenshot. Visible here means that the WSA surface is shown and has
// an alpha greater than 0.
ws -> ws.mWinAnimator != null && ws.mWinAnimator.getShown()
&& ws.mWinAnimator.mLastAlpha > 0f, true /* traverseTopToBottom */);
- if (hasVisibleChild) {
- return activity;
- }
- }
- return null;
+
+ });
}
@Nullable
@@ -380,7 +375,7 @@
@VisibleForTesting
int getSnapshotMode(Task task) {
- final ActivityRecord topChild = task.getTopChild();
+ final ActivityRecord topChild = task.getTopMostActivity();
if (!task.isActivityTypeStandardOrUndefined() && !task.isActivityTypeAssistant()) {
return SNAPSHOT_MODE_NONE;
} else if (topChild != null && topChild.shouldUseAppThemeSnapshot()) {
@@ -395,7 +390,7 @@
* as possible by using the theme's window background.
*/
private TaskSnapshot drawAppThemeSnapshot(Task task) {
- final ActivityRecord topChild = task.getTopChild();
+ final ActivityRecord topChild = task.getTopMostActivity();
if (topChild == null) {
return null;
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 453514b2..5c1491e 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -310,6 +310,10 @@
final protected void setParent(WindowContainer<WindowContainer> parent) {
final WindowContainer oldParent = mParent;
mParent = parent;
+
+ if (mParent != null) {
+ mParent.onChildAdded(this);
+ }
if (!mReparenting) {
onParentChanged(mParent, oldParent);
}
@@ -389,7 +393,6 @@
} else {
mChildren.add(positionToAdd, child);
}
- onChildAdded(child);
// Set the parent after we've actually added a child in case a subclass depends on this.
child.setParent(this);
@@ -418,7 +421,6 @@
}
mChildren.add(index, child);
- onChildAdded(child);
// Set the parent after we've actually added a child in case a subclass depends on this.
child.setParent(this);
@@ -1096,11 +1098,22 @@
}
boolean forAllActivities(Function<ActivityRecord, Boolean> callback) {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- if (mChildren.get(i).forAllActivities(callback)) {
- return true;
+ return forAllActivities(callback, true /*traverseTopToBottom*/);
+ }
+
+ boolean forAllActivities(
+ Function<ActivityRecord, Boolean> callback, boolean traverseTopToBottom) {
+ if (traverseTopToBottom) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ if (mChildren.get(i).forAllActivities(callback, traverseTopToBottom)) return true;
+ }
+ } else {
+ final int count = mChildren.size();
+ for (int i = 0; i < count; i++) {
+ if (mChildren.get(i).forAllActivities(callback, traverseTopToBottom)) return true;
}
}
+
return false;
}
@@ -1121,6 +1134,61 @@
}
}
+ /**
+ * Process all activities in this branch of the tree.
+ *
+ * @param callback Called for each activity found.
+ * @param boundary We don't return activities via {@param callback} until we get to this node in
+ * the tree.
+ * @param includeBoundary If the boundary from be processed to return activities.
+ * @param traverseTopToBottom direction to traverse the tree.
+ * @return {@code true} if we ended the search before reaching the end of the tree.
+ */
+ final boolean forAllActivities(Function<ActivityRecord, Boolean> callback,
+ WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom) {
+ return forAllActivities(
+ callback, boundary, includeBoundary, traverseTopToBottom, new boolean[1]);
+ }
+
+ private boolean forAllActivities(Function<ActivityRecord, Boolean> callback,
+ WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
+ boolean[] boundaryFound) {
+ if (traverseTopToBottom) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ if (processForAllActivitiesWithBoundary(callback, boundary, includeBoundary,
+ traverseTopToBottom, boundaryFound, mChildren.get(i))) {
+ return true;
+ }
+ }
+ } else {
+ final int count = mChildren.size();
+ for (int i = 0; i < count; i++) {
+ if (processForAllActivitiesWithBoundary(callback, boundary, includeBoundary,
+ traverseTopToBottom, boundaryFound, mChildren.get(i))) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private boolean processForAllActivitiesWithBoundary(Function<ActivityRecord, Boolean> callback,
+ WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
+ boolean[] boundaryFound, WindowContainer wc) {
+ if (wc == boundary) {
+ boundaryFound[0] = true;
+ if (!includeBoundary) return false;
+ }
+
+ if (boundaryFound[0]) {
+ return wc.forAllActivities(callback, traverseTopToBottom);
+ }
+
+ return wc.forAllActivities(
+ callback, boundary, includeBoundary, traverseTopToBottom, boundaryFound);
+ }
+
/** @return {@code true} if this node or any of its children contains an activity. */
boolean hasActivity() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
@@ -1156,6 +1224,81 @@
return null;
}
+ /**
+ * Gets an activity in a branch of the tree.
+ *
+ * @param callback called to test if this is the activity that should be returned.
+ * @param boundary We don't return activities via {@param callback} until we get to this node in
+ * the tree.
+ * @param includeBoundary If the boundary from be processed to return activities.
+ * @param traverseTopToBottom direction to traverse the tree.
+ * @return The activity if found or null.
+ */
+ final ActivityRecord getActivity(Predicate<ActivityRecord> callback,
+ WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom) {
+ return getActivity(
+ callback, boundary, includeBoundary, traverseTopToBottom, new boolean[1]);
+ }
+
+ private ActivityRecord getActivity(Predicate<ActivityRecord> callback,
+ WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
+ boolean[] boundaryFound) {
+ if (traverseTopToBottom) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final ActivityRecord r = processGetActivityWithBoundary(callback, boundary,
+ includeBoundary, traverseTopToBottom, boundaryFound, mChildren.get(i));
+ if (r != null) {
+ return r;
+ }
+ }
+ } else {
+ final int count = mChildren.size();
+ for (int i = 0; i < count; i++) {
+ final ActivityRecord r = processGetActivityWithBoundary(callback, boundary,
+ includeBoundary, traverseTopToBottom, boundaryFound, mChildren.get(i));
+ if (r != null) {
+ return r;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private ActivityRecord processGetActivityWithBoundary(Predicate<ActivityRecord> callback,
+ WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
+ boolean[] boundaryFound, WindowContainer wc) {
+ if (wc == boundary || boundary == null) {
+ boundaryFound[0] = true;
+ if (!includeBoundary) return null;
+ }
+
+ if (boundaryFound[0]) {
+ return wc.getActivity(callback, traverseTopToBottom);
+ }
+
+ return wc.getActivity(
+ callback, boundary, includeBoundary, traverseTopToBottom, boundaryFound);
+ }
+
+ ActivityRecord getActivityAbove(ActivityRecord r) {
+ return getActivity((above) -> true, r,
+ false /*includeBoundary*/, false /*traverseTopToBottom*/);
+ }
+
+ ActivityRecord getActivityBelow(ActivityRecord r) {
+ return getActivity((below) -> true, r,
+ false /*includeBoundary*/, true /*traverseTopToBottom*/);
+ }
+
+ ActivityRecord getBottomMostActivity() {
+ return getActivity((r) -> true, false /*traverseTopToBottom*/);
+ }
+
+ ActivityRecord getTopMostActivity() {
+ return getActivity((r) -> true, true /*traverseTopToBottom*/);
+ }
+
ActivityRecord getTopActivity(boolean includeFinishing, boolean includeOverlays) {
// Break down into 4 calls to avoid object creation due to capturing input params.
if (includeFinishing) {
@@ -1187,6 +1330,31 @@
}
}
+ Task getTask(Predicate<Task> callback) {
+ return getTask(callback, true /*traverseTopToBottom*/);
+ }
+
+ Task getTask(Predicate<Task> callback, boolean traverseTopToBottom) {
+ if (traverseTopToBottom) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final Task t = mChildren.get(i).getTask(callback, traverseTopToBottom);
+ if (t != null) {
+ return t;
+ }
+ }
+ } else {
+ final int count = mChildren.size();
+ for (int i = 0; i < count; i++) {
+ final Task t = mChildren.get(i).getTask(callback, traverseTopToBottom);
+ if (t != null) {
+ return t;
+ }
+ }
+ }
+
+ return null;
+ }
+
/**
* For all tasks at or below this container call the callback.
*
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index c1783ef..e169037 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -722,11 +722,10 @@
return true;
}
- ArraySet<Task> getReleaseSomeActivitiesTasks() {
+ void releaseSomeActivities(String reason) {
// Examine all activities currently running in the process.
- Task firstTask = null;
- // Tasks is non-null only if two or more tasks are found.
- ArraySet<Task> tasks = null;
+ // Candidate activities that can be destroyed.
+ ArrayList<ActivityRecord> candidates = null;
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Trying to release some activities in " + this);
for (int i = 0; i < mActivities.size(); i++) {
final ActivityRecord r = mActivities.get(i);
@@ -735,33 +734,37 @@
// down before we try to prune more activities.
if (r.finishing || r.isState(DESTROYING, DESTROYED)) {
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Abort release; already destroying: " + r);
- return null;
+ return;
}
// Don't consider any activities that are currently not in a state where they
// can be destroyed.
- if (r.mVisibleRequested || !r.stopped || !r.hasSavedState()
+ if (r.mVisibleRequested || !r.stopped || !r.hasSavedState() || !r.isDestroyable()
|| r.isState(STARTED, RESUMED, PAUSING, PAUSED, STOPPING)) {
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r);
continue;
}
- final Task task = r.getTask();
- if (task != null) {
- if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Collecting release task " + task
- + " from " + r);
- if (firstTask == null) {
- firstTask = task;
- } else if (firstTask != task) {
- if (tasks == null) {
- tasks = new ArraySet<>();
- tasks.add(firstTask);
- }
- tasks.add(task);
+ if (r.getParent() != null) {
+ if (candidates == null) {
+ candidates = new ArrayList<>();
}
+ candidates.add(r);
}
}
- return tasks;
+ if (candidates != null) {
+ // Sort based on z-order in hierarchy.
+ candidates.sort(WindowContainer::compareTo);
+ // Release some older activities
+ int maxRelease = Math.max(candidates.size(), 1);
+ do {
+ final ActivityRecord r = candidates.remove(0);
+ if (DEBUG_RELEASE) Slog.v(TAG_RELEASE, "Destroying " + r
+ + " in state " + r.getState() + " for reason " + reason);
+ r.destroyImmediately(true /*removeFromApp*/, reason);
+ --maxRelease;
+ } while (maxRelease > 0);
+ }
}
public interface ComputeOomAdjCallback {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5a946f2..66f01f3 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1114,9 +1114,10 @@
SignedConfigService.registerUpdateReceiver(mSystemContext);
t.traceEnd();
- } catch (RuntimeException e) {
+ } catch (Throwable e) {
Slog.e("System", "******************************************");
- Slog.e("System", "************ Failure starting core service", e);
+ Slog.e("System", "************ Failure starting core service");
+ throw e;
}
// Before things start rolling, be sure we have decided whether
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java b/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
index 73279cb5..adef02e 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
@@ -19,75 +19,105 @@
import androidx.test.runner.AndroidJUnit4;
+import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.PropertyProto;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.List;
+
@RunWith(AndroidJUnit4.class)
public class FakeIcingTest {
@Test
public void query() {
FakeIcing icing = new FakeIcing();
- icing.put("uri:cat", "The cat said meow");
- icing.put("uri:dog", "The dog said woof");
+ icing.put(createDoc("uri:cat", "The cat said meow"));
+ icing.put(createDoc("uri:dog", "The dog said woof"));
- assertThat(icing.query("meow")).containsExactly("uri:cat");
- assertThat(icing.query("said")).containsExactly("uri:cat", "uri:dog");
- assertThat(icing.query("fred")).isEmpty();
+ assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
+ assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
+ assertThat(queryGetUris(icing, "fred")).isEmpty();
}
@Test
public void queryNorm() {
FakeIcing icing = new FakeIcing();
- icing.put("uri:cat", "The cat said meow");
- icing.put("uri:dog", "The dog said woof");
+ icing.put(createDoc("uri:cat", "The cat said meow"));
+ icing.put(createDoc("uri:dog", "The dog said woof"));
- assertThat(icing.query("the")).containsExactly("uri:cat", "uri:dog");
- assertThat(icing.query("The")).containsExactly("uri:cat", "uri:dog");
- assertThat(icing.query("tHe")).containsExactly("uri:cat", "uri:dog");
+ assertThat(queryGetUris(icing, "the")).containsExactly("uri:cat", "uri:dog");
+ assertThat(queryGetUris(icing, "The")).containsExactly("uri:cat", "uri:dog");
+ assertThat(queryGetUris(icing, "tHe")).containsExactly("uri:cat", "uri:dog");
}
@Test
public void get() {
+ DocumentProto cat = createDoc("uri:cat", "The cat said meow");
FakeIcing icing = new FakeIcing();
- icing.put("uri:cat", "The cat said meow");
- assertThat(icing.get("uri:cat")).isEqualTo("The cat said meow");
+ icing.put(cat);
+ assertThat(icing.get("uri:cat")).isEqualTo(cat);
}
@Test
public void replace() {
- FakeIcing icing = new FakeIcing();
- icing.put("uri:cat", "The cat said meow");
- icing.put("uri:dog", "The dog said woof");
+ DocumentProto cat = createDoc("uri:cat", "The cat said meow");
+ DocumentProto dog = createDoc("uri:dog", "The dog said woof");
- assertThat(icing.query("meow")).containsExactly("uri:cat");
- assertThat(icing.query("said")).containsExactly("uri:cat", "uri:dog");
- assertThat(icing.get("uri:cat")).isEqualTo("The cat said meow");
+ FakeIcing icing = new FakeIcing();
+ icing.put(cat);
+ icing.put(dog);
+
+ assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
+ assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
+ assertThat(icing.get("uri:cat")).isEqualTo(cat);
// Replace
- icing.put("uri:cat", "The cat said purr");
- icing.put("uri:bird", "The cat said tweet");
+ DocumentProto cat2 = createDoc("uri:cat", "The cat said purr");
+ DocumentProto bird = createDoc("uri:bird", "The cat said tweet");
+ icing.put(cat2);
+ icing.put(bird);
- assertThat(icing.query("meow")).isEmpty();
- assertThat(icing.query("said")).containsExactly("uri:cat", "uri:dog", "uri:bird");
- assertThat(icing.get("uri:cat")).isEqualTo("The cat said purr");
+ assertThat(queryGetUris(icing, "meow")).isEmpty();
+ assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog", "uri:bird");
+ assertThat(icing.get("uri:cat")).isEqualTo(cat2);
}
@Test
public void delete() {
- FakeIcing icing = new FakeIcing();
- icing.put("uri:cat", "The cat said meow");
- icing.put("uri:dog", "The dog said woof");
+ DocumentProto cat = createDoc("uri:cat", "The cat said meow");
+ DocumentProto dog = createDoc("uri:dog", "The dog said woof");
- assertThat(icing.query("meow")).containsExactly("uri:cat");
- assertThat(icing.query("said")).containsExactly("uri:cat", "uri:dog");
- assertThat(icing.get("uri:cat")).isEqualTo("The cat said meow");
+ FakeIcing icing = new FakeIcing();
+ icing.put(cat);
+ icing.put(dog);
+
+ assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
+ assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
+ assertThat(icing.get("uri:cat")).isEqualTo(cat);
// Delete
icing.delete("uri:cat");
icing.delete("uri:notreal");
- assertThat(icing.query("meow")).isEmpty();
- assertThat(icing.query("said")).containsExactly("uri:dog");
+ assertThat(queryGetUris(icing, "meow")).isEmpty();
+ assertThat(queryGetUris(icing, "said")).containsExactly("uri:dog");
assertThat(icing.get("uri:cat")).isNull();
}
+
+ private static DocumentProto createDoc(String uri, String body) {
+ return DocumentProto.newBuilder()
+ .setUri(uri)
+ .addProperties(PropertyProto.newBuilder().addStringValues(body))
+ .build();
+ }
+
+ private static List<String> queryGetUris(FakeIcing icing, String term) {
+ List<String> uris = new ArrayList<>();
+ for (DocumentProto result : icing.query(term)) {
+ uris.add(result.getUri());
+ }
+ return uris;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
new file mode 100644
index 0000000..269f918
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.display;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.SparseArray;
+import android.view.Display;
+
+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.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DisplayModeDirectorTest {
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ }
+
+ private DisplayModeDirector createDisplayModeDirectorWithDisplayFpsRange(
+ int minFps, int maxFps) {
+ DisplayModeDirector director =
+ new DisplayModeDirector(mContext, new Handler(Looper.getMainLooper()));
+ int displayId = 0;
+ int numModes = maxFps - minFps + 1;
+ Display.Mode[] modes = new Display.Mode[numModes];
+ for (int i = minFps; i <= maxFps; i++) {
+ modes[i - minFps] = new Display.Mode(
+ /*modeId=*/i, /*width=*/1000, /*height=*/1000, /*refreshRate=*/i);
+ }
+ SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<Display.Mode[]>();
+ supportedModesByDisplay.put(displayId, modes);
+ director.injectSupportedModesByDisplay(supportedModesByDisplay);
+ SparseArray<Display.Mode> defaultModesByDisplay = new SparseArray<Display.Mode>();
+ defaultModesByDisplay.put(displayId, modes[0]);
+ director.injectDefaultModeByDisplay(defaultModesByDisplay);
+ return director;
+ }
+
+ private int[] intRange(int min, int max) {
+ int[] range = new int[max - min + 1];
+ for (int i = min; i <= max; i++) {
+ range[i - min] = i;
+ }
+ return range;
+ }
+
+ @Test
+ public void testDisplayModeVoting() {
+ int displayId = 0;
+
+ // With no votes present, DisplayModeDirector should allow any refresh rate.
+ assertEquals(new DisplayModeDirector.DesiredDisplayConfigSpecs(/*defaultModeId=*/60,
+ new DisplayModeDirector.RefreshRateRange(0f, Float.POSITIVE_INFINITY),
+ intRange(60, 90)),
+ createDisplayModeDirectorWithDisplayFpsRange(60, 90).getDesiredDisplayConfigSpecs(
+ displayId));
+
+ int numPriorities =
+ DisplayModeDirector.Vote.MAX_PRIORITY - DisplayModeDirector.Vote.MIN_PRIORITY + 1;
+
+ // Ensure vote priority works as expected. As we add new votes with higher priority, they
+ // should take precedence over lower priority votes.
+ {
+ int minFps = 60;
+ int maxFps = 90;
+ DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
+ assertTrue(2 * numPriorities < maxFps - minFps + 1);
+ SparseArray<DisplayModeDirector.Vote> votes =
+ new SparseArray<DisplayModeDirector.Vote>();
+ SparseArray<SparseArray<DisplayModeDirector.Vote>> votesByDisplay =
+ new SparseArray<SparseArray<DisplayModeDirector.Vote>>();
+ votesByDisplay.put(displayId, votes);
+ for (int i = 0; i < numPriorities; i++) {
+ int priority = DisplayModeDirector.Vote.MIN_PRIORITY + i;
+ votes.put(
+ priority, DisplayModeDirector.Vote.forRefreshRates(minFps + i, maxFps - i));
+ director.injectVotesByDisplay(votesByDisplay);
+ assertEquals(
+ new DisplayModeDirector.DesiredDisplayConfigSpecs(
+ /*defaultModeId=*/minFps + i,
+ new DisplayModeDirector.RefreshRateRange(minFps + i, maxFps - i),
+ intRange(minFps + i, maxFps - i)),
+ director.getDesiredDisplayConfigSpecs(displayId));
+ }
+ }
+
+ // Ensure lower priority votes are able to influence the final decision, even in the
+ // presence of higher priority votes.
+ {
+ assertTrue(numPriorities >= 2);
+ DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
+ SparseArray<DisplayModeDirector.Vote> votes =
+ new SparseArray<DisplayModeDirector.Vote>();
+ SparseArray<SparseArray<DisplayModeDirector.Vote>> votesByDisplay =
+ new SparseArray<SparseArray<DisplayModeDirector.Vote>>();
+ votesByDisplay.put(displayId, votes);
+ votes.put(DisplayModeDirector.Vote.MAX_PRIORITY,
+ DisplayModeDirector.Vote.forRefreshRates(65, 85));
+ votes.put(DisplayModeDirector.Vote.MIN_PRIORITY,
+ DisplayModeDirector.Vote.forRefreshRates(70, 80));
+ director.injectVotesByDisplay(votesByDisplay);
+ assertEquals(
+ new DisplayModeDirector.DesiredDisplayConfigSpecs(/*defaultModeId=*/70,
+ new DisplayModeDirector.RefreshRateRange(70, 80), intRange(70, 80)),
+ director.getDesiredDisplayConfigSpecs(displayId));
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index 601e2e9..790f2b4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -24,6 +24,7 @@
import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT;
import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE;
import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE;
+import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA;
import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST;
import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_LOG;
@@ -394,33 +395,45 @@
assertFalse(mUserSystemPackageInstaller.isLogMode());
assertFalse(mUserSystemPackageInstaller.isEnforceMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+ assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_LOG);
assertTrue(mUserSystemPackageInstaller.isLogMode());
assertFalse(mUserSystemPackageInstaller.isEnforceMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+ assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
assertFalse(mUserSystemPackageInstaller.isLogMode());
assertTrue(mUserSystemPackageInstaller.isEnforceMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+ assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST);
assertFalse(mUserSystemPackageInstaller.isLogMode());
assertFalse(mUserSystemPackageInstaller.isEnforceMode());
assertTrue(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+ assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
+
+ setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA);
+ assertFalse(mUserSystemPackageInstaller.isLogMode());
+ assertFalse(mUserSystemPackageInstaller.isEnforceMode());
+ assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+ assertTrue(mUserSystemPackageInstaller.isIgnoreOtaMode());
setUserTypePackageWhitelistMode(
USER_TYPE_PACKAGE_WHITELIST_MODE_LOG | USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
assertTrue(mUserSystemPackageInstaller.isLogMode());
assertTrue(mUserSystemPackageInstaller.isEnforceMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+ assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST
| USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
assertFalse(mUserSystemPackageInstaller.isLogMode());
assertTrue(mUserSystemPackageInstaller.isEnforceMode());
assertTrue(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+ assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
}
/** Sets the whitelist mode to the desired value via adb's setprop. */
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index b1b386b..c2b8827 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -914,7 +914,7 @@
// Add another stack to become focused and make the activity there visible. This way it
// simulates finishing in non-focused stack in split-screen.
final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
- final ActivityRecord focusedActivity = stack.getChildAt(0).getChildAt(0);
+ final ActivityRecord focusedActivity = stack.getTopMostActivity();
focusedActivity.nowVisible = true;
focusedActivity.mVisibleRequested = true;
focusedActivity.setState(RESUMED, "test");
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index ba54859..c8795ce 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -241,7 +241,7 @@
final RootActivityContainer.FindTaskResult result =
new RootActivityContainer.FindTaskResult();
- mStack.findTaskLocked(r, result);
+ result.process(r, mStack);
assertEquals(r, task.getTopNonFinishingActivity(false /* includeOverlays */));
assertEquals(taskOverlay, task.getTopNonFinishingActivity(true /* includeOverlays */));
@@ -266,14 +266,14 @@
final ActivityRecord r1 = new ActivityBuilder(mService).setComponent(
target).setTargetActivity(targetActivity).build();
RootActivityContainer.FindTaskResult result = new RootActivityContainer.FindTaskResult();
- mStack.findTaskLocked(r1, result);
+ result.process(r1, mStack);
assertThat(result.mRecord).isNotNull();
// Using alias activity to find task.
final ActivityRecord r2 = new ActivityBuilder(mService).setComponent(
alias).setTargetActivity(targetActivity).build();
result = new RootActivityContainer.FindTaskResult();
- mStack.findTaskLocked(r2, result);
+ result.process(r2, mStack);
assertThat(result.mRecord).isNotNull();
}
@@ -846,9 +846,9 @@
mStack.mResumedActivity = secondActivity;
// Note the activities have non-null ActivityRecord.app, so it won't remove directly.
- mStack.finishDisabledPackageActivitiesLocked(firstActivity.packageName,
- null /* filterByClasses */, true /* doit */, true /* evenPersistent */,
- UserHandle.USER_ALL);
+ mRootActivityContainer.mFinishDisabledPackageActivitiesHelper.process(
+ firstActivity.packageName, null /* filterByClasses */, true /* doit */,
+ true /* evenPersistent */, UserHandle.USER_ALL);
// If the activity is disabled with {@link android.content.pm.PackageManager#DONT_KILL_APP}
// the activity should still follow the normal flow to finish and destroy.
@@ -875,9 +875,9 @@
assertEquals(2, mTask.getChildCount());
- mStack.finishDisabledPackageActivitiesLocked(activity.packageName,
- null /* filterByClasses */, true /* doit */, true /* evenPersistent */,
- UserHandle.USER_ALL);
+ mRootActivityContainer.mFinishDisabledPackageActivitiesHelper.process(
+ activity.packageName, null /* filterByClasses */, true /* doit */,
+ true /* evenPersistent */, UserHandle.USER_ALL);
// Although the overlay activity is in another package, the non-overlay activities are
// removed from the task. Since the overlay activity should be removed as well, the task
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index ae1bb8e..c712d6d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -962,4 +962,19 @@
}
assertThat(exceptionCaught).isTrue();
}
+
+ @Test
+ public void testRecycleTaskFromAnotherUser() {
+ final ActivityStarter starter = prepareStarter(0 /* flags */);
+ starter.mStartActivity = new ActivityBuilder(mService).build();
+ final Task task = new TaskBuilder(mService.mStackSupervisor)
+ .setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
+ .setUserId(10)
+ .build();
+
+ final int result = starter.recycleTask(task, null, null);
+ assertThat(result == START_SUCCESS).isTrue();
+ assertThat(starter.mAddingToTask).isTrue();
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index e2bdf87..4257249 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -73,6 +73,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.function.Consumer;
/**
* Tests for the {@link RootActivityContainer} class.
@@ -149,9 +150,7 @@
final Task task = stack.getAllTasks().get(0);
final ArrayList<ActivityRecord> stackActivities = new ArrayList<>();
- for (int i = 0; i < task.getChildCount(); i++) {
- stackActivities.add(task.getChildAt(i));
- }
+ task.forAllActivities((Consumer<ActivityRecord>) stackActivities::add, false);
assertEquals("Expecting " + Arrays.deepToString(activities) + " got " + stackActivities,
stackActivities.size(), activities != null ? activities.length : 0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index c8f81f4..d756f9a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -471,8 +471,9 @@
// Add an extra activity on top of the root one
new ActivityBuilder(mService).setTask(task).build();
- assertEquals("The root activity in the task must be reported.",
- 0, task.findRootIndex(false /* effectiveRoot*/));
+ assertEquals("The root activity in the task must be reported.", task.getChildAt(0),
+ task.getRootActivity(
+ true /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
}
/**
@@ -483,14 +484,15 @@
public void testFindRootIndex_finishing() {
final Task task = getTestTask();
// Add extra two activities and mark the two on the bottom as finishing.
- final ActivityRecord activity0 = task.getChildAt(0);
+ final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.finishing = true;
final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
activity1.finishing = true;
new ActivityBuilder(mService).setTask(task).build();
assertEquals("The first non-finishing activity in the task must be reported.",
- 2, task.findRootIndex(false /* effectiveRoot*/));
+ task.getChildAt(2), task.getRootActivity(
+ true /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
}
/**
@@ -504,7 +506,8 @@
new ActivityBuilder(mService).setTask(task).build();
assertEquals("The root activity in the task must be reported.",
- 0, task.findRootIndex(true /* effectiveRoot*/));
+ task.getChildAt(0), task.getRootActivity(
+ false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
}
/**
@@ -516,14 +519,15 @@
final Task task = getTestTask();
// Add extra two activities. Mark the one on the bottom with "relinquishTaskIdentity" and
// one above as finishing.
- final ActivityRecord activity0 = task.getChildAt(0);
+ final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
activity1.finishing = true;
new ActivityBuilder(mService).setTask(task).build();
assertEquals("The first non-finishing activity and non-relinquishing task identity "
- + "must be reported.", 2, task.findRootIndex(true /* effectiveRoot*/));
+ + "must be reported.", task.getChildAt(2), task.getRootActivity(
+ false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
}
/**
@@ -534,10 +538,11 @@
public void testFindRootIndex_effectiveRoot_relinquishingAndSingleActivity() {
final Task task = getTestTask();
// Set relinquishTaskIdentity for the only activity in the task
- task.getChildAt(0).info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+ task.getBottomMostActivity().info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
assertEquals("The root activity in the task must be reported.",
- 0, task.findRootIndex(true /* effectiveRoot*/));
+ task.getChildAt(0), task.getRootActivity(
+ false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
}
/**
@@ -548,13 +553,14 @@
public void testFindRootIndex_effectiveRoot_relinquishingMultipleActivities() {
final Task task = getTestTask();
// Set relinquishTaskIdentity for all activities in the task
- final ActivityRecord activity0 = task.getChildAt(0);
+ final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
assertEquals("The topmost activity in the task must be reported.",
- task.getChildCount() - 1, task.findRootIndex(true /* effectiveRoot*/));
+ task.getChildAt(task.getChildCount() - 1), task.getRootActivity(
+ false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
}
/** Test that bottom-most activity is reported in {@link Task#getRootActivity()}. */
@@ -565,7 +571,7 @@
new ActivityBuilder(mService).setTask(task).build();
assertEquals("The root activity in the task must be reported.",
- task.getChildAt(0), task.getRootActivity());
+ task.getBottomMostActivity(), task.getRootActivity());
}
/**
@@ -577,7 +583,7 @@
// Add an extra activity on top of the root one
new ActivityBuilder(mService).setTask(task).build();
// Mark the root as finishing
- task.getChildAt(0).finishing = true;
+ task.getBottomMostActivity().finishing = true;
assertEquals("The first non-finishing activity in the task must be reported.",
task.getChildAt(1), task.getRootActivity());
@@ -590,13 +596,13 @@
public void testGetRootActivity_relinquishTaskIdentity() {
final Task task = getTestTask();
// Mark the bottom-most activity with FLAG_RELINQUISH_TASK_IDENTITY.
- final ActivityRecord activity0 = task.getChildAt(0);
+ final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
// Add an extra activity on top of the root one.
new ActivityBuilder(mService).setTask(task).build();
assertEquals("The root activity in the task must be reported.",
- task.getChildAt(0), task.getRootActivity());
+ task.getBottomMostActivity(), task.getRootActivity());
}
/**
@@ -607,7 +613,7 @@
public void testGetRootActivity_allFinishing() {
final Task task = getTestTask();
// Mark the bottom-most activity as finishing.
- final ActivityRecord activity0 = task.getChildAt(0);
+ final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.finishing = true;
// Add an extra activity on top of the root one and mark it as finishing
final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
@@ -623,7 +629,7 @@
public void testIsRootActivity() {
final Task task = getTestTask();
// Mark the bottom-most activity as finishing.
- final ActivityRecord activity0 = task.getChildAt(0);
+ final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.finishing = true;
// Add an extra activity on top of the root one.
final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
@@ -640,7 +646,7 @@
public void testIsRootActivity_allFinishing() {
final Task task = getTestTask();
// Mark the bottom-most activity as finishing.
- final ActivityRecord activity0 = task.getChildAt(0);
+ final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.finishing = true;
// Add an extra activity on top of the root one and mark it as finishing
final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
@@ -657,10 +663,10 @@
@Test
public void testGetTaskForActivity() {
final Task task0 = getTestTask();
- final ActivityRecord activity0 = task0.getChildAt(0);
+ final ActivityRecord activity0 = task0.getBottomMostActivity();
final Task task1 = getTestTask();
- final ActivityRecord activity1 = task1.getChildAt(0);
+ final ActivityRecord activity1 = task1.getBottomMostActivity();
assertEquals(task0.mTaskId,
ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */));
@@ -676,7 +682,7 @@
public void testGetTaskForActivity_onlyRoot_finishing() {
final Task task = getTestTask();
// Make the current root activity finishing
- final ActivityRecord activity0 = task.getChildAt(0);
+ final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.finishing = true;
// Add an extra activity on top - this will be the new root
final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
@@ -699,7 +705,7 @@
public void testGetTaskForActivity_onlyRoot_relinquishTaskIdentity() {
final Task task = getTestTask();
// Make the current root activity relinquish task identity
- final ActivityRecord activity0 = task.getChildAt(0);
+ final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
// Add an extra activity on top - this will be the new root
final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
@@ -722,7 +728,7 @@
public void testGetTaskForActivity_notOnlyRoot() {
final Task task = getTestTask();
// Mark the bottom-most activity as finishing.
- final ActivityRecord activity0 = task.getChildAt(0);
+ final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.finishing = true;
// Add an extra activity on top of the root one and make it relinquish task identity
@@ -747,7 +753,7 @@
public void testUpdateEffectiveIntent() {
// Test simple case with a single activity.
final Task task = getTestTask();
- final ActivityRecord activity0 = task.getChildAt(0);
+ final ActivityRecord activity0 = task.getBottomMostActivity();
spyOn(task);
task.updateEffectiveIntent();
@@ -762,7 +768,7 @@
public void testUpdateEffectiveIntent_rootFinishing() {
// Test simple case with a single activity.
final Task task = getTestTask();
- final ActivityRecord activity0 = task.getChildAt(0);
+ final ActivityRecord activity0 = task.getBottomMostActivity();
// Mark the bottom-most activity as finishing.
activity0.finishing = true;
// Add an extra activity on top of the root one
@@ -782,7 +788,7 @@
public void testUpdateEffectiveIntent_allFinishing() {
// Test simple case with a single activity.
final Task task = getTestTask();
- final ActivityRecord activity0 = task.getChildAt(0);
+ final ActivityRecord activity0 = task.getBottomMostActivity();
// Mark the bottom-most activity as finishing.
activity0.finishing = true;
// Add an extra activity on top of the root one and make it relinquish task identity
@@ -818,7 +824,7 @@
task.getResolvedOverrideConfiguration().windowConfiguration.getAppBounds());
}
- private byte[] serializeToBytes(Task r) throws IOException, XmlPullParserException {
+ private byte[] serializeToBytes(Task r) throws Exception {
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
final XmlSerializer serializer = Xml.newSerializer();
serializer.setOutput(os, "UTF-8");
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index b428530..221f8f1 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -16,6 +16,10 @@
package android.telecom;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
@@ -32,6 +36,7 @@
* Builder class for {@link ConnectionRequest}
* @hide
*/
+ @TestApi // For convenience in CTS tests
public static final class Builder {
private PhoneAccountHandle mAccountHandle;
private Uri mAddress;
@@ -48,7 +53,7 @@
* Sets the phone account handle for the resulting {@link ConnectionRequest}
* @param accountHandle The accountHandle which should be used to place the call.
*/
- public Builder setAccountHandle(PhoneAccountHandle accountHandle) {
+ public @NonNull Builder setAccountHandle(@NonNull PhoneAccountHandle accountHandle) {
this.mAccountHandle = accountHandle;
return this;
}
@@ -58,7 +63,7 @@
* @param address The address(e.g., phone number) to which the {@link Connection} is to
* connect.
*/
- public Builder setAddress(Uri address) {
+ public @NonNull Builder setAddress(@NonNull Uri address) {
this.mAddress = address;
return this;
}
@@ -67,7 +72,7 @@
* Sets the extras bundle for the resulting {@link ConnectionRequest}
* @param extras Application-specific extra data.
*/
- public Builder setExtras(Bundle extras) {
+ public @NonNull Builder setExtras(@NonNull Bundle extras) {
this.mExtras = extras;
return this;
}
@@ -76,7 +81,7 @@
* Sets the video state for the resulting {@link ConnectionRequest}
* @param videoState Determines the video state for the connection.
*/
- public Builder setVideoState(int videoState) {
+ public @NonNull Builder setVideoState(int videoState) {
this.mVideoState = videoState;
return this;
}
@@ -85,7 +90,7 @@
* Sets the Telecom call ID for the resulting {@link ConnectionRequest}
* @param telecomCallId The telecom call ID.
*/
- public Builder setTelecomCallId(String telecomCallId) {
+ public @NonNull Builder setTelecomCallId(@NonNull String telecomCallId) {
this.mTelecomCallId = telecomCallId;
return this;
}
@@ -97,7 +102,7 @@
* its own incoming call UI for an incoming call. When
* {@code false}, Telecom shows the incoming call UI.
*/
- public Builder setShouldShowIncomingCallUi(boolean shouldShowIncomingCallUi) {
+ public @NonNull Builder setShouldShowIncomingCallUi(boolean shouldShowIncomingCallUi) {
this.mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
return this;
}
@@ -107,7 +112,8 @@
* resulting {@link ConnectionRequest}
* @param rttPipeFromInCall The data pipe to read from.
*/
- public Builder setRttPipeFromInCall(ParcelFileDescriptor rttPipeFromInCall) {
+ public @NonNull Builder setRttPipeFromInCall(
+ @NonNull ParcelFileDescriptor rttPipeFromInCall) {
this.mRttPipeFromInCall = rttPipeFromInCall;
return this;
}
@@ -117,12 +123,16 @@
* resulting {@link ConnectionRequest}
* @param rttPipeToInCall The data pipe to write to.
*/
- public Builder setRttPipeToInCall(ParcelFileDescriptor rttPipeToInCall) {
+ public @NonNull Builder setRttPipeToInCall(@NonNull ParcelFileDescriptor rttPipeToInCall) {
this.mRttPipeToInCall = rttPipeToInCall;
return this;
}
- public ConnectionRequest build() {
+ /**
+ * Build the {@link ConnectionRequest}
+ * @return Result of the builder
+ */
+ public @NonNull ConnectionRequest build() {
return new ConnectionRequest(
mAccountHandle,
mAddress,
@@ -261,7 +271,9 @@
* @return The Telecom ID.
* @hide
*/
- public String getTelecomCallId() {
+ @SystemApi
+ @TestApi
+ public @Nullable String getTelecomCallId() {
return mTelecomCallId;
}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 4016943..39d741c 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1029,12 +1029,16 @@
* by the user.
*
* @param includeDisabledAccounts When {@code true}, disabled phone accounts will be included,
- * when {@code false}, only
+ * when {@code false}, only enabled phone accounts will be
+ * included.
* @return A list of {@code PhoneAccountHandle} objects.
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 119305590)
- public List<PhoneAccountHandle> getCallCapablePhoneAccounts(boolean includeDisabledAccounts) {
+ @SystemApi
+ @TestApi
+ @RequiresPermission(READ_PRIVILEGED_PHONE_STATE)
+ public @NonNull List<PhoneAccountHandle> getCallCapablePhoneAccounts(
+ boolean includeDisabledAccounts) {
try {
if (isServiceConnected()) {
return getTelecomService().getCallCapablePhoneAccounts(
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 1dd1185..fc26122 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -86,7 +86,6 @@
import com.android.ims.internal.IImsServiceFeatureCallback;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telecom.ITelecomService;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.INumberVerificationCallback;
import com.android.internal.telephony.IOns;
@@ -5176,13 +5175,11 @@
* @return the current call state.
*/
public @CallState int getCallState() {
- try {
- ITelecomService telecom = getTelecomService();
- if (telecom != null) {
- return telecom.getCallState();
+ if (mContext != null) {
+ TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
+ if (telecomManager != null) {
+ return telecomManager.getCallState();
}
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelecomService#getCallState", e);
}
return CALL_STATE_IDLE;
}
@@ -5341,13 +5338,6 @@
return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
}
- /**
- * @hide
- */
- private ITelecomService getTelecomService() {
- return ITelecomService.Stub.asInterface(ServiceManager.getService(TELECOM_SERVICE));
- }
-
private ITelephonyRegistry getTelephonyRegistry() {
return ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 6e20621..96ddf22 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -390,7 +390,6 @@
private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
int uid, String callingPackage, String message) {
boolean isPreinstalled = false;
- boolean isPrivApp = false;
ApplicationInfo callingPackageInfo = null;
try {
callingPackageInfo = context.getPackageManager().getApplicationInfoAsUser(
@@ -398,9 +397,6 @@
if (callingPackageInfo != null) {
if (callingPackageInfo.isSystemApp()) {
isPreinstalled = true;
- if (callingPackageInfo.isPrivilegedApp()) {
- isPrivApp = true;
- }
}
}
} catch (PackageManager.NameNotFoundException e) {
@@ -423,10 +419,10 @@
}
invokedMethods.add(message);
StatsLog.write(StatsLog.DEVICE_IDENTIFIER_ACCESS_DENIED, callingPackage, message,
- isPreinstalled, isPrivApp);
+ isPreinstalled, false);
}
Log.w(LOG_TAG, "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message
- + ":isPreinstalled=" + isPreinstalled + ":isPrivApp=" + isPrivApp);
+ + ":isPreinstalled=" + isPreinstalled);
// if the target SDK is pre-Q then check if the calling package would have previously
// had access to device identifiers.
if (callingPackageInfo != null && (
diff --git a/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java
new file mode 100644
index 0000000..a28d65c
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.telephony.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+
+import java.io.PrintWriter;
+
+/**
+ * This class provides various util functions
+ */
+public final class TelephonyUtils {
+ public static boolean IS_USER = "user".equals(android.os.Build.TYPE);
+ public static boolean IS_DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1;
+
+ /**
+ * Verify that caller holds {@link android.Manifest.permission#DUMP}.
+ *
+ * @return true if access should be granted.
+ */
+ public static 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=" + Binder.getCallingUid()
+ + " due to missing android.permission.DUMP permission");
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /** Returns an empty string if the input is {@code null}. */
+ public static String emptyIfNull(@Nullable String str) {
+ return str == null ? "" : str;
+ }
+
+ /** Throws a {@link RuntimeException} that wrapps the {@link RemoteException}. */
+ public static RuntimeException rethrowAsRuntimeException(RemoteException remoteException) {
+ throw new RuntimeException(remoteException);
+ }
+
+ /**
+ * Returns a {@link ComponentInfo} from the {@link ResolveInfo},
+ * or throws an {@link IllegalStateException} if not available.
+ */
+ public static ComponentInfo getComponentInfo(@NonNull ResolveInfo resolveInfo) {
+ if (resolveInfo.activityInfo != null) return resolveInfo.activityInfo;
+ if (resolveInfo.serviceInfo != null) return resolveInfo.serviceInfo;
+ if (resolveInfo.providerInfo != null) return resolveInfo.providerInfo;
+ throw new IllegalStateException("Missing ComponentInfo!");
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 2a09f64..c4e353b 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -96,6 +96,7 @@
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeastOnce;
@@ -198,6 +199,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.app.IBatteryStats;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
import com.android.internal.util.ArrayUtils;
@@ -305,6 +307,7 @@
@Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
@Mock INetworkManagementService mNetworkManagementService;
@Mock INetworkStatsService mStatsService;
+ @Mock IBatteryStats mBatteryStatsService;
@Mock INetworkPolicyManager mNpm;
@Mock IDnsResolver mMockDnsResolver;
@Mock INetd mMockNetd;
@@ -1135,6 +1138,7 @@
doReturn(mMetricsService).when(deps).getMetricsLogger();
doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
doReturn(mIpConnectivityMetrics).when(deps).getIpConnectivityMetrics();
+ doReturn(mBatteryStatsService).when(deps).getBatteryStatsService();
doReturn(true).when(deps).hasService(Context.ETHERNET_SERVICE);
doAnswer(inv -> {
mPolicyTracker = new WrappedMultinetworkPolicyTracker(
@@ -5640,6 +5644,36 @@
mCm.unregisterNetworkCallback(defaultCallback);
}
+ @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(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
+ TYPE_MOBILE);
+ reset(mBatteryStatsService);
+
+ final LinkProperties wifiLp = new LinkProperties();
+ wifiLp.setInterfaceName("wifi0");
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
+ mWiFiNetworkAgent.connect(true);
+ waitForIdle();
+ verify(mBatteryStatsService).noteNetworkInterfaceType(wifiLp.getInterfaceName(),
+ TYPE_WIFI);
+ reset(mBatteryStatsService);
+
+ mCellNetworkAgent.disconnect();
+
+ cellLp.setInterfaceName("wifi0");
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+ mCellNetworkAgent.connect(true);
+ waitForIdle();
+ verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
+ TYPE_MOBILE);
+ }
+
/**
* Make simulated InterfaceConfig for Nat464Xlat to query clat lower layer info.
*/
@@ -5680,25 +5714,28 @@
mCm.registerNetworkCallback(networkRequest, networkCallback);
// Prepare ipv6 only link properties.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- final int cellNetId = mCellNetworkAgent.getNetwork().netId;
final LinkProperties cellLp = new LinkProperties();
cellLp.setInterfaceName(MOBILE_IFNAME);
cellLp.addLinkAddress(myIpv6);
cellLp.addRoute(new RouteInfo((IpPrefix) null, myIpv6.getAddress(), MOBILE_IFNAME));
cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME));
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
reset(mNetworkManagementService);
reset(mMockDnsResolver);
reset(mMockNetd);
+ reset(mBatteryStatsService);
when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
.thenReturn(getClatInterfaceConfig(myIpv4));
// Connect with ipv6 link properties. Expect prefix discovery to be started.
- mCellNetworkAgent.sendLinkProperties(cellLp);
mCellNetworkAgent.connect(true);
+ final int cellNetId = mCellNetworkAgent.getNetwork().netId;
+ waitForIdle();
verify(mMockNetd, times(1)).networkCreatePhysical(eq(cellNetId), anyInt());
verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
+ verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
+ TYPE_MOBILE);
networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
@@ -5714,6 +5751,11 @@
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(mBatteryStatsService, never()).noteNetworkInterfaceType(startsWith("v4-"), anyInt());
+
verifyNoMoreInteractions(mMockNetd);
verifyNoMoreInteractions(mMockDnsResolver);
reset(mMockNetd);
@@ -5760,6 +5802,11 @@
assertEquals(1, resolvrParams.servers.length);
assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8"));
+ for (final LinkProperties stackedLp : stackedLpsAfterChange) {
+ verify(mBatteryStatsService).noteNetworkInterfaceType(stackedLp.getInterfaceName(),
+ TYPE_MOBILE);
+ }
+
// Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
// linkproperties are cleaned up.
cellLp.addLinkAddress(myIpv4);
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 4a89c66..032f66a 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -142,6 +142,8 @@
boolean startSoftAp(in WifiConfiguration wifiConfig);
+ boolean startTetheredHotspot(in SoftApConfiguration softApConfig);
+
boolean stopSoftAp();
int startLocalOnlyHotspot(in ILocalOnlyHotspotCallback callback, String packageName,
@@ -159,8 +161,14 @@
@UnsupportedAppUsage
WifiConfiguration getWifiApConfiguration();
+ SoftApConfiguration getSoftApConfiguration();
+
boolean setWifiApConfiguration(in WifiConfiguration wifiConfig, String packageName);
+ boolean setSoftApConfiguration(in SoftApConfiguration softApConfig, String packageName);
+
+ void notifyUserOfApBandConversion(String packageName);
+
void enableTdls(String remoteIPAddress, boolean enable);
void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable);
@@ -184,6 +192,10 @@
void restoreBackupData(in byte[] data);
+ byte[] retrieveSoftApBackupData();
+
+ void restoreSoftApBackupData(in byte[] data);
+
void restoreSupplicantBackupData(in byte[] supplicantData, in byte[] ipConfigData);
void startSubscriptionProvisioning(in OsuProvider provider, in IProvisioningCallback callback);
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index 4cc8653..8030bd6 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -16,28 +16,34 @@
package android.net.wifi;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.MacAddress;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import com.android.internal.util.Preconditions;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.concurrent.Executor;
/**
- * WiFi configuration for a soft access point (a.k.a. Soft AP, SAP, Hotspot).
+ * Configuration for a soft access point (a.k.a. Soft AP, SAP, Hotspot).
*
* This is input for the framework provided by a client app, i.e. it exposes knobs to instruct the
- * framework how it should open a hotspot. It is not meant to describe the network as it will be
- * seen by clients; this role is currently served by {@link WifiConfiguration} (see
- * {@link WifiManager.LocalOnlyHotspotReservation#getWifiConfiguration()}).
+ * framework how it should configure a hotspot.
*
- * System apps can use this to configure a local-only hotspot using
+ * System apps can use this to configure a tethered hotspot using
+ * {@link WifiManager#startTetheredHotspot(SoftApConfiguration)} and
+ * {@link WifiManager#setSoftApConfiguration(SoftApConfiguration)}
+ * or local-only hotspot using
* {@link WifiManager#startLocalOnlyHotspot(SoftApConfiguration, Executor,
* WifiManager.LocalOnlyHotspotCallback)}.
*
@@ -48,25 +54,106 @@
*/
@SystemApi
public final class SoftApConfiguration implements Parcelable {
+
+ /**
+ * 2GHz band.
+ * @hide
+ */
+ @SystemApi
+ public static final int BAND_2GHZ = 0;
+
+ /**
+ * 5GHz band.
+ * @hide
+ */
+ @SystemApi
+ public static final int BAND_5GHZ = 1;
+
+ /**
+ * Device is allowed to choose the optimal band (2Ghz or 5Ghz) based on device capability,
+ * operating country code and current radio conditions.
+ * @hide
+ */
+ @SystemApi
+ public static final int BAND_ANY = -1;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "BAND_TYPE_" }, value = {
+ BAND_2GHZ,
+ BAND_5GHZ,
+ BAND_ANY,
+ })
+ public @interface BandType {}
+
/**
* SSID for the AP, or null for a framework-determined SSID.
*/
private final @Nullable String mSsid;
+
/**
* BSSID for the AP, or null to use a framework-determined BSSID.
*/
private final @Nullable MacAddress mBssid;
+
/**
* Pre-shared key for WPA2-PSK encryption (non-null enables WPA2-PSK).
*/
private final @Nullable String mWpa2Passphrase;
+ /**
+ * This is a network that does not broadcast its SSID, so an
+ * SSID-specific probe request must be used for scans.
+ */
+ private final boolean mHiddenSsid;
+
+ /**
+ * The operating band of the AP.
+ * One of the band types from {@link @BandType}.
+ */
+ private final @BandType int mBand;
+
+ /**
+ * The operating channel of the AP.
+ */
+ private final int mChannel;
+
+ /**
+ * The operating security type of the AP.
+ * One of the security types from {@link @SecurityType}
+ */
+ private final @SecurityType int mSecurityType;
+
+ /**
+ * Security types we support.
+ */
+ /** @hide */
+ @SystemApi
+ public static final int SECURITY_TYPE_OPEN = 0;
+
+ /** @hide */
+ @SystemApi
+ public static final int SECURITY_TYPE_WPA2_PSK = 1;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "SECURITY_TYPE" }, value = {
+ SECURITY_TYPE_OPEN,
+ SECURITY_TYPE_WPA2_PSK,
+ })
+ public @interface SecurityType {}
+
/** Private constructor for Builder and Parcelable implementation. */
- private SoftApConfiguration(
- @Nullable String ssid, @Nullable MacAddress bssid, String wpa2Passphrase) {
+ private SoftApConfiguration(@Nullable String ssid, @Nullable MacAddress bssid,
+ @Nullable String wpa2Passphrase, boolean hiddenSsid, @BandType int band, int channel,
+ @SecurityType int securityType) {
mSsid = ssid;
mBssid = bssid;
mWpa2Passphrase = wpa2Passphrase;
+ mHiddenSsid = hiddenSsid;
+ mBand = band;
+ mChannel = channel;
+ mSecurityType = securityType;
}
@Override
@@ -80,12 +167,31 @@
SoftApConfiguration other = (SoftApConfiguration) otherObj;
return Objects.equals(mSsid, other.mSsid)
&& Objects.equals(mBssid, other.mBssid)
- && Objects.equals(mWpa2Passphrase, other.mWpa2Passphrase);
+ && Objects.equals(mWpa2Passphrase, other.mWpa2Passphrase)
+ && mHiddenSsid == other.mHiddenSsid
+ && mBand == other.mBand
+ && mChannel == other.mChannel
+ && mSecurityType == other.mSecurityType;
}
@Override
public int hashCode() {
- return Objects.hash(mSsid, mBssid, mWpa2Passphrase);
+ return Objects.hash(mSsid, mBssid, mWpa2Passphrase, mHiddenSsid,
+ mBand, mChannel, mSecurityType);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sbuf = new StringBuilder();
+ sbuf.append("ssid=").append(mSsid);
+ if (mBssid != null) sbuf.append(" \n bssid=").append(mBssid.toString());
+ sbuf.append(" \n Wpa2Passphrase =").append(
+ TextUtils.isEmpty(mWpa2Passphrase) ? "<empty>" : "<non-empty>");
+ sbuf.append(" \n HiddenSsid =").append(mHiddenSsid);
+ sbuf.append(" \n Band =").append(mBand);
+ sbuf.append(" \n Channel =").append(mChannel);
+ sbuf.append(" \n SecurityType=").append(getSecurityType());
+ return sbuf.toString();
}
@Override
@@ -93,6 +199,10 @@
dest.writeString(mSsid);
dest.writeParcelable(mBssid, flags);
dest.writeString(mWpa2Passphrase);
+ dest.writeBoolean(mHiddenSsid);
+ dest.writeInt(mBand);
+ dest.writeInt(mChannel);
+ dest.writeInt(mSecurityType);
}
@Override
@@ -107,7 +217,7 @@
return new SoftApConfiguration(
in.readString(),
in.readParcelable(MacAddress.class.getClassLoader()),
- in.readString());
+ in.readString(), in.readBoolean(), in.readInt(), in.readInt(), in.readInt());
}
@Override
@@ -116,22 +226,68 @@
}
};
+ /**
+ * Return String set to be the SSID for the AP.
+ * {@link #setSsid(String)}.
+ */
@Nullable
public String getSsid() {
return mSsid;
}
+ /**
+ * Returns MAC address set to be BSSID for the AP.
+ * {@link #setBssid(MacAddress)}.
+ */
@Nullable
public MacAddress getBssid() {
return mBssid;
}
+ /**
+ * Returns String set to be passphrase for the WPA2-PSK AP.
+ * {@link #setWpa2Passphrase(String)}.
+ */
@Nullable
public String getWpa2Passphrase() {
return mWpa2Passphrase;
}
/**
+ * Returns Boolean set to be indicate hidden (true: doesn't broadcast its SSID) or
+ * not (false: broadcasts its SSID) for the AP.
+ * {@link #setHiddenSsid(boolean)}.
+ */
+ public boolean isHiddenSsid() {
+ return mHiddenSsid;
+ }
+
+ /**
+ * Returns {@link BandType} set to be the band for the AP.
+ * {@link #setBand(@BandType int)}.
+ */
+ public @BandType int getBand() {
+ return mBand;
+ }
+
+ /**
+ * Returns Integer set to be the channel for the AP.
+ * {@link #setChannel(int)}.
+ */
+ public int getChannel() {
+ return mChannel;
+ }
+
+ /**
+ * Get security type params which depends on which security passphrase to set.
+ *
+ * @return One of the security types from {@link SecurityType}.
+ */
+ public @SecurityType int getSecurityType() {
+ return mSecurityType;
+ }
+
+ /**
* Builds a {@link SoftApConfiguration}, which allows an app to configure various aspects of a
* Soft AP.
*
@@ -142,6 +298,21 @@
private String mSsid;
private MacAddress mBssid;
private String mWpa2Passphrase;
+ private boolean mHiddenSsid;
+ private int mBand;
+ private int mChannel;
+
+ private int setSecurityType() {
+ int securityType = SECURITY_TYPE_OPEN;
+ if (!TextUtils.isEmpty(mWpa2Passphrase)) { // WPA2-PSK network.
+ securityType = SECURITY_TYPE_WPA2_PSK;
+ }
+ return securityType;
+ }
+
+ private void clearAllPassphrase() {
+ mWpa2Passphrase = null;
+ }
/**
* Constructs a Builder with default values (see {@link Builder}).
@@ -150,6 +321,9 @@
mSsid = null;
mBssid = null;
mWpa2Passphrase = null;
+ mHiddenSsid = false;
+ mBand = BAND_2GHZ;
+ mChannel = 0;
}
/**
@@ -161,6 +335,9 @@
mSsid = other.mSsid;
mBssid = other.mBssid;
mWpa2Passphrase = other.mWpa2Passphrase;
+ mHiddenSsid = other.mHiddenSsid;
+ mBand = other.mBand;
+ mChannel = other.mChannel;
}
/**
@@ -170,11 +347,16 @@
*/
@NonNull
public SoftApConfiguration build() {
- return new SoftApConfiguration(mSsid, mBssid, mWpa2Passphrase);
+ return new SoftApConfiguration(mSsid, mBssid, mWpa2Passphrase,
+ mHiddenSsid, mBand, mChannel, setSecurityType());
}
/**
* Specifies an SSID for the AP.
+ * <p>
+ * Null SSID only support when configure a local-only hotspot.
+ * <p>
+ * <li>If not set, defaults to null.</li>
*
* @param ssid SSID of valid Unicode characters, or null to have the SSID automatically
* chosen by the framework.
@@ -193,7 +375,10 @@
/**
* Specifies a BSSID for the AP.
- *
+ * <p>
+ * Only supported when configuring a local-only hotspot.
+ * <p>
+ * <li>If not set, defaults to null.</li>
* @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is
* responsible for avoiding collisions.
* @return Builder for chaining.
@@ -211,8 +396,9 @@
}
/**
- * Specifies that this AP should use WPA2-PSK with the given passphrase. When set to null
- * and no other encryption method is configured, an open network is created.
+ * Specifies that this AP should use WPA2-PSK with the given ASCII WPA2 passphrase.
+ * When set to null, an open network is created.
+ * <p>
*
* @param passphrase The passphrase to use, or null to unset a previously-set WPA2-PSK
* configuration.
@@ -222,10 +408,72 @@
@NonNull
public Builder setWpa2Passphrase(@Nullable String passphrase) {
if (passphrase != null) {
+ final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
+ if (!asciiEncoder.canEncode(passphrase)) {
+ throw new IllegalArgumentException("passphrase not ASCII encodable");
+ }
Preconditions.checkStringNotEmpty(passphrase);
}
+ clearAllPassphrase();
mWpa2Passphrase = passphrase;
return this;
}
+
+ /**
+ * Specifies whether the AP is hidden (doesn't broadcast its SSID) or
+ * not (broadcasts its SSID).
+ * <p>
+ * <li>If not set, defaults to false (i.e not a hidden network).</li>
+ *
+ * @param hiddenSsid true for a hidden SSID, false otherwise.
+ * @return Builder for chaining.
+ */
+ @NonNull
+ public Builder setHiddenSsid(boolean hiddenSsid) {
+ mHiddenSsid = hiddenSsid;
+ return this;
+ }
+
+ /**
+ * Specifies the band for the AP.
+ * <p>
+ * <li>If not set, defaults to BAND_2GHZ {@link @BandType}.</li>
+ *
+ * @param band One of the band types from {@link @BandType}.
+ * @return Builder for chaining.
+ */
+ @NonNull
+ public Builder setBand(@BandType int band) {
+ switch (band) {
+ case BAND_2GHZ:
+ break;
+ case BAND_5GHZ:
+ break;
+ case BAND_ANY:
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid band type");
+ }
+ mBand = band;
+ return this;
+ }
+
+ /**
+ * Specifies the channel for the AP.
+ *
+ * The channel which AP resides on. Valid channels are country dependent.
+ * Use the special channel value 0 to have the framework auto-select a valid channel
+ * from the band configured with {@link #setBand(@BandType int)}.
+ *
+ * <p>
+ * <li>If not set, defaults to 0.</li>
+ * @param channel operating channel of the AP.
+ * @return Builder for chaining.
+ */
+ @NonNull
+ public Builder setChannel(int channel) {
+ mChannel = channel;
+ return this;
+ }
}
}
diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
index 0f7fc2d..f0f31fa 100644
--- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
+++ b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
@@ -16,10 +16,14 @@
package android.net.wifi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Arrays;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* Record of energy and activity information from controller and
@@ -27,179 +31,197 @@
* real-time.
* @hide
*/
+@SystemApi
public final class WifiActivityEnergyInfo implements Parcelable {
- /**
- * @hide
- */
- public long mTimestamp;
+ private long mTimeSinceBootMillis;
+ @StackState
+ private int mStackState;
+ private long mControllerTxDurationMillis;
+ private long mControllerRxDurationMillis;
+ private long mControllerScanDurationMillis;
+ private long mControllerIdleDurationMillis;
+ private long mControllerEnergyUsedMicroJoules;
- /**
- * @hide
- */
- public int mStackState;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"STACK_STATE_"}, value = {
+ STACK_STATE_INVALID,
+ STACK_STATE_STATE_ACTIVE,
+ STACK_STATE_STATE_SCANNING,
+ STACK_STATE_STATE_IDLE})
+ public @interface StackState {}
- /**
- * @hide
- */
- public long mControllerTxTimeMs;
-
- /**
- * @hide
- */
- public long[] mControllerTxTimePerLevelMs;
-
- /**
- * @hide
- */
- public long mControllerRxTimeMs;
-
- /**
- * @hide
- */
- public long mControllerScanTimeMs;
-
- /**
- * @hide
- */
- public long mControllerIdleTimeMs;
-
- /**
- * @hide
- */
- public long mControllerEnergyUsed;
-
+ /** Invalid Wifi stack state. */
public static final int STACK_STATE_INVALID = 0;
+ /** Wifi stack is active. */
public static final int STACK_STATE_STATE_ACTIVE = 1;
+ /** Wifi stack is scanning. */
public static final int STACK_STATE_STATE_SCANNING = 2;
+ /** Wifi stack is idle. */
public static final int STACK_STATE_STATE_IDLE = 3;
- public WifiActivityEnergyInfo(long timestamp, int stackState,
- long txTime, long[] txTimePerLevel, long rxTime, long scanTime,
- long idleTime, long energyUsed) {
- mTimestamp = timestamp;
+ /**
+ * Constructor.
+ *
+ * @param timeSinceBootMillis the time since boot, in milliseconds.
+ * @param stackState The current state of the Wifi Stack. One of {@link #STACK_STATE_INVALID},
+ * {@link #STACK_STATE_STATE_ACTIVE}, {@link #STACK_STATE_STATE_SCANNING},
+ * or {@link #STACK_STATE_STATE_IDLE}.
+ * @param txDurationMillis Cumulative milliseconds of active transmission.
+ * @param rxDurationMillis Cumulative milliseconds of active receive.
+ * @param scanDurationMillis Cumulative milliseconds when radio is awake due to scan.
+ * @param idleDurationMillis Cumulative milliseconds when radio is awake but not transmitting or
+ * receiving.
+ * @param energyUsedMicroJoules Cumulative energy consumed by Wifi, in microjoules.
+ */
+ public WifiActivityEnergyInfo(
+ long timeSinceBootMillis,
+ @StackState int stackState,
+ long txDurationMillis,
+ long rxDurationMillis,
+ long scanDurationMillis,
+ long idleDurationMillis,
+ long energyUsedMicroJoules) {
+ mTimeSinceBootMillis = timeSinceBootMillis;
mStackState = stackState;
- mControllerTxTimeMs = txTime;
- mControllerTxTimePerLevelMs = txTimePerLevel;
- mControllerRxTimeMs = rxTime;
- mControllerScanTimeMs = scanTime;
- mControllerIdleTimeMs = idleTime;
- mControllerEnergyUsed = energyUsed;
+ mControllerTxDurationMillis = txDurationMillis;
+ mControllerRxDurationMillis = rxDurationMillis;
+ mControllerScanDurationMillis = scanDurationMillis;
+ mControllerIdleDurationMillis = idleDurationMillis;
+ mControllerEnergyUsedMicroJoules = energyUsedMicroJoules;
}
@Override
public String toString() {
return "WifiActivityEnergyInfo{"
- + " timestamp=" + mTimestamp
- + " mStackState=" + mStackState
- + " mControllerTxTimeMs=" + mControllerTxTimeMs
- + " mControllerTxTimePerLevelMs=" + Arrays.toString(mControllerTxTimePerLevelMs)
- + " mControllerRxTimeMs=" + mControllerRxTimeMs
- + " mControllerScanTimeMs=" + mControllerScanTimeMs
- + " mControllerIdleTimeMs=" + mControllerIdleTimeMs
- + " mControllerEnergyUsed=" + mControllerEnergyUsed
- + " }";
+ + " mTimeSinceBootMillis=" + mTimeSinceBootMillis
+ + " mStackState=" + mStackState
+ + " mControllerTxDurationMillis=" + mControllerTxDurationMillis
+ + " mControllerRxDurationMillis=" + mControllerRxDurationMillis
+ + " mControllerScanDurationMillis=" + mControllerScanDurationMillis
+ + " mControllerIdleDurationMillis=" + mControllerIdleDurationMillis
+ + " mControllerEnergyUsedMicroJoules=" + mControllerEnergyUsedMicroJoules
+ + " }";
}
- public static final @android.annotation.NonNull Parcelable.Creator<WifiActivityEnergyInfo> CREATOR =
+ public static final @NonNull Parcelable.Creator<WifiActivityEnergyInfo> CREATOR =
new Parcelable.Creator<WifiActivityEnergyInfo>() {
public WifiActivityEnergyInfo createFromParcel(Parcel in) {
long timestamp = in.readLong();
int stackState = in.readInt();
long txTime = in.readLong();
- long[] txTimePerLevel = in.createLongArray();
long rxTime = in.readLong();
long scanTime = in.readLong();
long idleTime = in.readLong();
long energyUsed = in.readLong();
return new WifiActivityEnergyInfo(timestamp, stackState,
- txTime, txTimePerLevel, rxTime, scanTime, idleTime, energyUsed);
+ txTime, rxTime, scanTime, idleTime, energyUsed);
}
public WifiActivityEnergyInfo[] newArray(int size) {
return new WifiActivityEnergyInfo[size];
}
};
- public void writeToParcel(Parcel out, int flags) {
- out.writeLong(mTimestamp);
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeLong(mTimeSinceBootMillis);
out.writeInt(mStackState);
- out.writeLong(mControllerTxTimeMs);
- out.writeLongArray(mControllerTxTimePerLevelMs);
- out.writeLong(mControllerRxTimeMs);
- out.writeLong(mControllerScanTimeMs);
- out.writeLong(mControllerIdleTimeMs);
- out.writeLong(mControllerEnergyUsed);
+ out.writeLong(mControllerTxDurationMillis);
+ out.writeLong(mControllerRxDurationMillis);
+ out.writeLong(mControllerScanDurationMillis);
+ out.writeLong(mControllerIdleDurationMillis);
+ out.writeLong(mControllerEnergyUsedMicroJoules);
}
+ @Override
public int describeContents() {
return 0;
}
+ /** Get the timestamp (milliseconds since boot) of record creation. */
+ public long getTimeSinceBootMillis() {
+ return mTimeSinceBootMillis;
+ }
+
+ /** Set the timestamp (milliseconds since boot) of record creation. */
+ public void setTimeSinceBootMillis(long timeSinceBootMillis) {
+ mTimeSinceBootMillis = timeSinceBootMillis;
+ }
+
/**
- * @return bt stack reported state
+ * Get the Wifi stack reported state. One of {@link #STACK_STATE_INVALID},
+ * {@link #STACK_STATE_STATE_ACTIVE}, {@link #STACK_STATE_STATE_SCANNING},
+ * {@link #STACK_STATE_STATE_IDLE}.
*/
+ @StackState
public int getStackState() {
return mStackState;
}
/**
- * @return tx time in ms
+ * Set the Wifi stack reported state. One of {@link #STACK_STATE_INVALID},
+ * {@link #STACK_STATE_STATE_ACTIVE}, {@link #STACK_STATE_STATE_SCANNING},
+ * {@link #STACK_STATE_STATE_IDLE}.
*/
- public long getControllerTxTimeMillis() {
- return mControllerTxTimeMs;
+ public void setStackState(@StackState int stackState) {
+ mStackState = stackState;
}
- /**
- * @return tx time at power level provided in ms
- */
- public long getControllerTxTimeMillisAtLevel(int level) {
- if (level < mControllerTxTimePerLevelMs.length) {
- return mControllerTxTimePerLevelMs[level];
- }
- return 0;
+ /** Get the Wifi transmission duration, in milliseconds. */
+ public long getControllerTxDurationMillis() {
+ return mControllerTxDurationMillis;
}
- /**
- * @return rx time in ms
- */
- public long getControllerRxTimeMillis() {
- return mControllerRxTimeMs;
+ /** Set the Wifi transmission duration, in milliseconds. */
+ public void setControllerTxDurationMillis(long controllerTxDurationMillis) {
+ mControllerTxDurationMillis = controllerTxDurationMillis;
}
- /**
- * @return scan time in ms
- */
- public long getControllerScanTimeMillis() {
- return mControllerScanTimeMs;
+ /** Get the Wifi receive duration, in milliseconds. */
+ public long getControllerRxDurationMillis() {
+ return mControllerRxDurationMillis;
}
- /**
- * @return idle time in ms
- */
- public long getControllerIdleTimeMillis() {
- return mControllerIdleTimeMs;
+ /** Set the Wifi receive duration, in milliseconds. */
+ public void setControllerRxDurationMillis(long controllerRxDurationMillis) {
+ mControllerRxDurationMillis = controllerRxDurationMillis;
}
- /**
- * product of current(mA), voltage(V) and time(ms)
- * @return energy used
- */
- public long getControllerEnergyUsed() {
- return mControllerEnergyUsed;
- }
- /**
- * @return timestamp(wall clock) of record creation
- */
- public long getTimeStamp() {
- return mTimestamp;
+ /** Get the Wifi scan duration, in milliseconds. */
+ public long getControllerScanDurationMillis() {
+ return mControllerScanDurationMillis;
}
- /**
- * @return if the record is valid
- */
+ /** Set the Wifi scan duration, in milliseconds. */
+ public void setControllerScanDurationMillis(long controllerScanDurationMillis) {
+ mControllerScanDurationMillis = controllerScanDurationMillis;
+ }
+
+ /** Get the Wifi idle duration, in milliseconds. */
+ public long getControllerIdleDurationMillis() {
+ return mControllerIdleDurationMillis;
+ }
+
+ /** Set the Wifi idle duration, in milliseconds. */
+ public void setControllerIdleDurationMillis(long controllerIdleDurationMillis) {
+ mControllerIdleDurationMillis = controllerIdleDurationMillis;
+ }
+
+ /** Get the energy consumed by Wifi, in microjoules. */
+ public long getControllerEnergyUsedMicroJoules() {
+ return mControllerEnergyUsedMicroJoules;
+ }
+
+ /** Set the energy consumed by Wifi, in microjoules. */
+ public void setControllerEnergyUsedMicroJoules(long controllerEnergyUsedMicroJoules) {
+ mControllerEnergyUsedMicroJoules = controllerEnergyUsedMicroJoules;
+ }
+
+ /** Returns true if the record is valid, false otherwise. */
public boolean isValid() {
- return ((mControllerTxTimeMs >=0) &&
- (mControllerRxTimeMs >=0) &&
- (mControllerScanTimeMs >=0) &&
- (mControllerIdleTimeMs >=0));
+ return mControllerTxDurationMillis >= 0
+ && mControllerRxDurationMillis >= 0
+ && mControllerScanDurationMillis >= 0
+ && mControllerIdleDurationMillis >= 0;
}
-}
\ No newline at end of file
+}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index e08a11e..d068fc6 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -39,7 +39,6 @@
import android.util.BackupUtils;
import android.util.Log;
import android.util.SparseArray;
-import android.util.TimeUtils;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
@@ -49,6 +48,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.BitSet;
+import java.util.Calendar;
import java.util.HashMap;
/**
@@ -2006,6 +2006,16 @@
&& enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
}
+ private static String logTimeOfDay(long millis) {
+ Calendar c = Calendar.getInstance();
+ if (millis >= 0) {
+ c.setTimeInMillis(millis);
+ return String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c);
+ } else {
+ return Long.toString(millis);
+ }
+ }
+
@Override
public String toString() {
StringBuilder sbuf = new StringBuilder();
@@ -2042,7 +2052,7 @@
if (mNetworkSelectionStatus.getConnectChoice() != null) {
sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice());
sbuf.append(" connect choice set time: ")
- .append(TimeUtils.logTimeOfDay(
+ .append(logTimeOfDay(
mNetworkSelectionStatus.getConnectChoiceTimestamp()));
}
sbuf.append(" hasEverConnected: ")
@@ -2081,7 +2091,7 @@
sbuf.append(" mRandomizedMacAddress: ").append(mRandomizedMacAddress).append("\n");
sbuf.append(" randomizedMacExpirationTimeMs: ")
.append(randomizedMacExpirationTimeMs == 0 ? "<none>"
- : TimeUtils.logTimeOfDay(randomizedMacExpirationTimeMs)).append("\n");
+ : logTimeOfDay(randomizedMacExpirationTimeMs)).append("\n");
sbuf.append(" KeyMgmt:");
for (int k = 0; k < this.allowedKeyManagement.size(); k++) {
if (this.allowedKeyManagement.get(k)) {
@@ -2205,7 +2215,7 @@
if (this.lastConnected != 0) {
sbuf.append('\n');
- sbuf.append("lastConnected: ").append(TimeUtils.logTimeOfDay(this.lastConnected));
+ sbuf.append("lastConnected: ").append(logTimeOfDay(this.lastConnected));
sbuf.append(" ");
}
sbuf.append('\n');
@@ -2355,7 +2365,7 @@
? getSsidAndSecurityTypeString()
: FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
if (!shared) {
- key += "-" + UserHandle.getUserId(creatorUid);
+ key += "-" + UserHandle.getUserHandleForUid(creatorUid).getIdentifier();
}
return key;
}
@@ -2426,13 +2436,13 @@
@NonNull
@SystemApi
public IpConfiguration.IpAssignment getIpAssignment() {
- return mIpConfiguration.ipAssignment;
+ return mIpConfiguration.getIpAssignment();
}
/** @hide */
@UnsupportedAppUsage
public void setIpAssignment(IpConfiguration.IpAssignment ipAssignment) {
- mIpConfiguration.ipAssignment = ipAssignment;
+ mIpConfiguration.setIpAssignment(ipAssignment);
}
/**
@@ -2442,13 +2452,13 @@
@NonNull
@SystemApi
public IpConfiguration.ProxySettings getProxySettings() {
- return mIpConfiguration.proxySettings;
+ return mIpConfiguration.getProxySettings();
}
/** @hide */
@UnsupportedAppUsage
public void setProxySettings(IpConfiguration.ProxySettings proxySettings) {
- mIpConfiguration.proxySettings = proxySettings;
+ mIpConfiguration.setProxySettings(proxySettings);
}
/**
@@ -2457,10 +2467,10 @@
* WifiConfiguration, or {@code null} if no proxy is specified.
*/
public ProxyInfo getHttpProxy() {
- if (mIpConfiguration.proxySettings == IpConfiguration.ProxySettings.NONE) {
+ if (mIpConfiguration.getProxySettings() == IpConfiguration.ProxySettings.NONE) {
return null;
}
- return new ProxyInfo(mIpConfiguration.httpProxy);
+ return new ProxyInfo(mIpConfiguration.getHttpProxy());
}
/**
@@ -2485,12 +2495,12 @@
if (!Uri.EMPTY.equals(httpProxy.getPacFileUrl())) {
proxySettingCopy = IpConfiguration.ProxySettings.PAC;
// Construct a new PAC URL Proxy
- httpProxyCopy = new ProxyInfo(httpProxy.getPacFileUrl(), httpProxy.getPort());
+ httpProxyCopy = ProxyInfo.buildPacProxy(httpProxy.getPacFileUrl(), httpProxy.getPort());
} else {
proxySettingCopy = IpConfiguration.ProxySettings.STATIC;
// Construct a new HTTP Proxy
- httpProxyCopy = new ProxyInfo(httpProxy.getHost(), httpProxy.getPort(),
- httpProxy.getExclusionListAsString());
+ httpProxyCopy = ProxyInfo.buildDirectProxy(httpProxy.getHost(), httpProxy.getPort(),
+ Arrays.asList(httpProxy.getExclusionList()));
}
if (!httpProxyCopy.isValid()) {
throw new IllegalArgumentException("Invalid ProxyInfo: " + httpProxyCopy.toString());
@@ -2505,8 +2515,8 @@
*/
@SystemApi
public void setProxy(@NonNull ProxySettings settings, @NonNull ProxyInfo proxy) {
- mIpConfiguration.proxySettings = settings;
- mIpConfiguration.httpProxy = proxy;
+ mIpConfiguration.setProxySettings(settings);
+ mIpConfiguration.setHttpProxy(proxy);
}
/** Implement the Parcelable interface {@hide} */
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 6557bbe..e2e6728 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -36,15 +36,12 @@
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
import android.net.NetworkStack;
import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.hotspot2.ProvisioningCallback;
import android.os.Binder;
-import android.os.Build;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
@@ -57,7 +54,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.net.NetworkPinner;
import dalvik.system.CloseGuard;
@@ -2022,28 +2018,11 @@
*/
@Deprecated
public boolean enableNetwork(int netId, boolean attemptConnect) {
- final boolean pin = attemptConnect && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
- if (pin) {
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .build();
- NetworkPinner.pin(mContext, request);
- }
-
- boolean success;
try {
- success = mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
+ return mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
-
- if (pin && !success) {
- NetworkPinner.unpin();
- }
-
- return success;
}
/**
@@ -2760,7 +2739,6 @@
*
* @hide
*/
- @SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_STACK,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
@@ -2774,6 +2752,31 @@
}
/**
+ * Start Soft AP (hotspot) mode for tethering purposes with the specified configuration.
+ * Note that starting Soft AP mode may disable station mode operation if the device does not
+ * support concurrency.
+ * @param softApConfig A valid SoftApConfiguration specifying the configuration of the SAP,
+ * or null to use the persisted Soft AP configuration that was previously
+ * set using {@link #setSoftApConfiguration(softApConfiguration)}.
+ * @return {@code true} if the operation succeeded, {@code false} otherwise
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+ })
+ public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
+ try {
+ return mService.startTetheredHotspot(softApConfig);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+
+ /**
* Stop SoftAp mode.
* Note that stopping softap mode will restore the previous wifi mode.
* @return {@code true} if the operation succeeds, {@code false} otherwise
@@ -3057,10 +3060,12 @@
* Gets the Wi-Fi AP Configuration.
* @return AP details in WifiConfiguration
*
+ * @deprecated This API is deprecated. Use {@link #getSoftApConfiguration()} instead.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
+ @Deprecated
public WifiConfiguration getWifiApConfiguration() {
try {
return mService.getWifiApConfiguration();
@@ -3070,17 +3075,56 @@
}
/**
- * Sets the Wi-Fi AP Configuration. The AP configuration must either be open or
- * WPA2 PSK networks.
+ * Gets the Wi-Fi AP Configuration.
+ * @return AP details in {@link SoftApConfiguration}
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
+ public SoftApConfiguration getSoftApConfiguration() {
+ try {
+ return mService.getSoftApConfiguration();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets the Wi-Fi AP Configuration.
+ * @return {@code true} if the operation succeeded, {@code false} otherwise
+ *
+ * @deprecated This API is deprecated. Use {@link #setSoftApConfiguration(SoftApConfiguration)}
+ * instead.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
+ @Deprecated
+ public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
+ try {
+ return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets the Wi-Fi AP Configuration.
+ *
+ * @param softApConfig A valid SoftApConfiguration specifying the configuration of the SAP.
+
* @return {@code true} if the operation succeeded, {@code false} otherwise
*
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
- public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public boolean setSoftApConfiguration(@NonNull SoftApConfiguration softApConfig) {
try {
- return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
+ return mService.setSoftApConfiguration(
+ softApConfig, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4569,6 +4613,36 @@
}
/**
+ * Retrieve the soft ap config data to be backed to save current config data.
+ * @hide
+ */
+ @Nullable
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public byte[] retrieveSoftApBackupData() {
+ try {
+ return mService.retrieveSoftApBackupData();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Restore soft ap config from the backed up data.
+ * @hide
+ */
+ @Nullable
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void restoreSoftApBackupData(@NonNull byte[] data) {
+ try {
+ mService.restoreSoftApBackupData(data);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Restore state from the older version of back up data.
* The old backup data was essentially a backup of wpa_supplicant.conf
* and ipconfig.txt file.
@@ -5105,9 +5179,9 @@
Log.v(TAG, "OnWifiUsabilityStatsListener: "
+ "onWifiUsabilityStats: seqNum=" + seqNum);
}
- Binder.withCleanCallingIdentity(() ->
- executor.execute(() -> listener.onWifiUsabilityStats(seqNum,
- isSameBssidAndFreq, stats)));
+ Binder.clearCallingIdentity();
+ executor.execute(() -> listener.onWifiUsabilityStats(
+ seqNum, isSameBssidAndFreq, stats));
}
},
listener.hashCode()
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 77f7b9e..b293077 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -59,6 +59,60 @@
public class WifiScanner {
/** @hide */
+ public static final int WIFI_BAND_INDEX_24_GHZ = 0;
+ /** @hide */
+ public static final int WIFI_BAND_INDEX_5_GHZ = 1;
+ /** @hide */
+ public static final int WIFI_BAND_INDEX_5_GHZ_DFS_ONLY = 2;
+ /** @hide */
+ public static final int WIFI_BAND_COUNT = 3;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"WIFI_BAND_INDEX_"}, value = {
+ WIFI_BAND_INDEX_24_GHZ,
+ WIFI_BAND_INDEX_5_GHZ,
+ WIFI_BAND_INDEX_5_GHZ_DFS_ONLY})
+ public @interface WifiBandIndex {}
+
+ /** no band specified; use channel list instead */
+ public static final int WIFI_BAND_UNSPECIFIED = 0;
+ /** 2.4 GHz band */
+ public static final int WIFI_BAND_24_GHZ = 1 << WIFI_BAND_INDEX_24_GHZ;
+ /** 5 GHz band excluding DFS channels */
+ public static final int WIFI_BAND_5_GHZ = 1 << WIFI_BAND_INDEX_5_GHZ;
+ /** DFS channels from 5 GHz band only */
+ public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 1 << WIFI_BAND_INDEX_5_GHZ_DFS_ONLY;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"WIFI_BAND_"}, value = {
+ WIFI_BAND_UNSPECIFIED,
+ WIFI_BAND_24_GHZ,
+ WIFI_BAND_5_GHZ,
+ WIFI_BAND_5_GHZ_DFS_ONLY})
+ public @interface WifiBandBasic {}
+
+ /**
+ * Combination of bands
+ * Note that those are only the common band combinations,
+ * other combinations can be created by combining any of the basic bands above
+ */
+ /** Both 2.4 GHz band and 5 GHz band; no DFS channels */
+ public static final int WIFI_BAND_BOTH = WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ;
+ /**
+ * 2.4Ghz band + DFS channels from 5 GHz band only
+ * @hide
+ */
+ public static final int WIFI_BAND_24_GHZ_WITH_5GHZ_DFS =
+ WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
+ /** 5 GHz band including DFS channels */
+ public static final int WIFI_BAND_5_GHZ_WITH_DFS = WIFI_BAND_5_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
+ /** Both 2.4 GHz band and 5 GHz band; with DFS channels */
+ public static final int WIFI_BAND_BOTH_WITH_DFS =
+ WIFI_BAND_24_GHZ | WIFI_BAND_5_GHZ | WIFI_BAND_5_GHZ_DFS_ONLY;
+
+ /** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"WIFI_BAND_"}, value = {
WIFI_BAND_UNSPECIFIED,
@@ -71,25 +125,6 @@
WIFI_BAND_BOTH_WITH_DFS})
public @interface WifiBand {}
- /** no band specified; use channel list instead */
- public static final int WIFI_BAND_UNSPECIFIED = 0;
- /** 2.4 GHz band */
- public static final int WIFI_BAND_24_GHZ = 1;
- /** 5 GHz band excluding DFS channels */
- public static final int WIFI_BAND_5_GHZ = 2;
- /** Both 2.4 GHz band and 5 GHz band; no DFS channels */
- public static final int WIFI_BAND_BOTH = 3;
- /** DFS channels from 5 GHz band only */
- public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4;
- /**
- * 2.4Ghz band + DFS channels from 5 GHz band only
- * @hide
- */
- public static final int WIFI_BAND_24_GHZ_WITH_5GHZ_DFS = 5;
- /** 5 GHz band including DFS channels */
- public static final int WIFI_BAND_5_GHZ_WITH_DFS = 6;
- /** Both 2.4 GHz band and 5 GHz band; with DFS channels */
- public static final int WIFI_BAND_BOTH_WITH_DFS = 7;
/**
* Max band value
* @hide
@@ -398,7 +433,6 @@
return new ScanSettings[size];
}
};
-
}
/**
diff --git a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
index b3b5b29..2d3cc1e 100644
--- a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
+++ b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
@@ -18,8 +18,6 @@
import android.annotation.Nullable;
-import libcore.io.Memory;
-
import java.nio.BufferOverflowException;
import java.nio.ByteOrder;
import java.util.ArrayList;
@@ -266,7 +264,7 @@
public TlvConstructor putShort(int type, short data) {
checkLength(2);
addHeader(type, 2);
- Memory.pokeShort(mArray, mPosition, data, mByteOrder);
+ pokeShort(mArray, mPosition, data, mByteOrder);
mPosition += 2;
return this;
}
@@ -284,7 +282,7 @@
public TlvConstructor putInt(int type, int data) {
checkLength(4);
addHeader(type, 4);
- Memory.pokeInt(mArray, mPosition, data, mByteOrder);
+ pokeInt(mArray, mPosition, data, mByteOrder);
mPosition += 4;
return this;
}
@@ -349,14 +347,14 @@
if (mTypeSize == 1) {
mArray[mPosition] = (byte) type;
} else if (mTypeSize == 2) {
- Memory.pokeShort(mArray, mPosition, (short) type, mByteOrder);
+ pokeShort(mArray, mPosition, (short) type, mByteOrder);
}
mPosition += mTypeSize;
if (mLengthSize == 1) {
mArray[mPosition] = (byte) length;
} else if (mLengthSize == 2) {
- Memory.pokeShort(mArray, mPosition, (short) length, mByteOrder);
+ pokeShort(mArray, mPosition, (short) length, mByteOrder);
}
mPosition += mLengthSize;
}
@@ -445,7 +443,7 @@
throw new IllegalArgumentException(
"Accesing a short from a TLV element of length " + length);
}
- return Memory.peekShort(mRefArray, offset, byteOrder);
+ return peekShort(mRefArray, offset, byteOrder);
}
/**
@@ -460,7 +458,7 @@
throw new IllegalArgumentException(
"Accesing an int from a TLV element of length " + length);
}
- return Memory.peekInt(mRefArray, offset, byteOrder);
+ return peekInt(mRefArray, offset, byteOrder);
}
/**
@@ -590,7 +588,7 @@
if (mTypeSize == 1) {
type = mArray[mOffset];
} else if (mTypeSize == 2) {
- type = Memory.peekShort(mArray, mOffset, mByteOrder);
+ type = peekShort(mArray, mOffset, mByteOrder);
}
mOffset += mTypeSize;
@@ -598,7 +596,7 @@
if (mLengthSize == 1) {
length = mArray[mOffset];
} else if (mLengthSize == 2) {
- length = Memory.peekShort(mArray, mOffset, mByteOrder);
+ length = peekShort(mArray, mOffset, mByteOrder);
}
mOffset += mLengthSize;
@@ -661,10 +659,56 @@
if (lengthSize == 1) {
nextTlvIndex += lengthSize + array[nextTlvIndex];
} else {
- nextTlvIndex += lengthSize + Memory.peekShort(array, nextTlvIndex, byteOrder);
+ nextTlvIndex += lengthSize + peekShort(array, nextTlvIndex, byteOrder);
}
}
return nextTlvIndex == array.length;
}
+
+ private static void pokeShort(byte[] dst, int offset, short value, ByteOrder order) {
+ if (order == ByteOrder.BIG_ENDIAN) {
+ dst[offset++] = (byte) ((value >> 8) & 0xff);
+ dst[offset ] = (byte) ((value >> 0) & 0xff);
+ } else {
+ dst[offset++] = (byte) ((value >> 0) & 0xff);
+ dst[offset ] = (byte) ((value >> 8) & 0xff);
+ }
+ }
+
+ private static void pokeInt(byte[] dst, int offset, int value, ByteOrder order) {
+ if (order == ByteOrder.BIG_ENDIAN) {
+ dst[offset++] = (byte) ((value >> 24) & 0xff);
+ dst[offset++] = (byte) ((value >> 16) & 0xff);
+ dst[offset++] = (byte) ((value >> 8) & 0xff);
+ dst[offset ] = (byte) ((value >> 0) & 0xff);
+ } else {
+ dst[offset++] = (byte) ((value >> 0) & 0xff);
+ dst[offset++] = (byte) ((value >> 8) & 0xff);
+ dst[offset++] = (byte) ((value >> 16) & 0xff);
+ dst[offset ] = (byte) ((value >> 24) & 0xff);
+ }
+ }
+
+ private static short peekShort(byte[] src, int offset, ByteOrder order) {
+ if (order == ByteOrder.BIG_ENDIAN) {
+ return (short) ((src[offset] << 8) | (src[offset + 1] & 0xff));
+ } else {
+ return (short) ((src[offset + 1] << 8) | (src[offset] & 0xff));
+ }
+ }
+
+ private static int peekInt(byte[] src, int offset, ByteOrder order) {
+ if (order == ByteOrder.BIG_ENDIAN) {
+ return ((src[offset++] & 0xff) << 24)
+ | ((src[offset++] & 0xff) << 16)
+ | ((src[offset++] & 0xff) << 8)
+ | ((src[offset ] & 0xff) << 0);
+ } else {
+ return ((src[offset++] & 0xff) << 0)
+ | ((src[offset++] & 0xff) << 8)
+ | ((src[offset++] & 0xff) << 16)
+ | ((src[offset ] & 0xff) << 24);
+ }
+ }
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
index 9164d04..5ec4c8b 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
@@ -207,14 +207,14 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeBlob(mData);
+ dest.writeByteArray(mData);
}
public static final @android.annotation.NonNull Creator<ByteArrayWrapper> CREATOR =
new Creator<ByteArrayWrapper>() {
@Override
public ByteArrayWrapper createFromParcel(Parcel in) {
- return new ByteArrayWrapper(in.readBlob());
+ return new ByteArrayWrapper(in.createByteArray());
}
@Override
diff --git a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
index 3bef502..f0a0607 100644
--- a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
+++ b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.graphics.drawable.Icon;
import android.net.Uri;
import android.net.wifi.WifiSsid;
import android.os.Bundle;
@@ -86,23 +85,16 @@
*/
private final List<Integer> mMethodList;
- /**
- * Icon data for the OSU (Online Sign-Up) provider.
- */
- private final Icon mIcon;
-
/** @hide */
public OsuProvider(String osuSsid, Map<String, String> friendlyNames,
- String serviceDescription, Uri serverUri, String nai, List<Integer> methodList,
- Icon icon) {
+ String serviceDescription, Uri serverUri, String nai, List<Integer> methodList) {
this(WifiSsid.createFromByteArray(osuSsid.getBytes(StandardCharsets.UTF_8)),
- friendlyNames, serviceDescription, serverUri, nai, methodList, icon);
+ friendlyNames, serviceDescription, serverUri, nai, methodList);
}
/** @hide */
public OsuProvider(WifiSsid osuSsid, Map<String, String> friendlyNames,
- String serviceDescription, Uri serverUri, String nai, List<Integer> methodList,
- Icon icon) {
+ String serviceDescription, Uri serverUri, String nai, List<Integer> methodList) {
mOsuSsid = osuSsid;
mFriendlyNames = friendlyNames;
mServiceDescription = serviceDescription;
@@ -113,7 +105,6 @@
} else {
mMethodList = new ArrayList<>(methodList);
}
- mIcon = icon;
}
/**
@@ -130,7 +121,6 @@
mServerUri = null;
mNetworkAccessIdentifier = null;
mMethodList = new ArrayList<>();
- mIcon = null;
return;
}
@@ -144,7 +134,6 @@
} else {
mMethodList = new ArrayList<>(source.mMethodList);
}
- mIcon = source.mIcon;
}
/** @hide */
@@ -205,11 +194,6 @@
return mMethodList;
}
- /** @hide */
- public Icon getIcon() {
- return mIcon;
- }
-
@Override
public int describeContents() {
return 0;
@@ -222,7 +206,6 @@
dest.writeParcelable(mServerUri, flags);
dest.writeString(mNetworkAccessIdentifier);
dest.writeList(mMethodList);
- dest.writeParcelable(mIcon, flags);
Bundle bundle = new Bundle();
bundle.putSerializable("friendlyNameMap", (HashMap<String, String>) mFriendlyNames);
dest.writeBundle(bundle);
@@ -237,21 +220,16 @@
return false;
}
OsuProvider that = (OsuProvider) thatObject;
- return (mOsuSsid == null ? that.mOsuSsid == null : mOsuSsid.equals(that.mOsuSsid))
- && (mFriendlyNames == null) ? that.mFriendlyNames == null
- : mFriendlyNames.equals(that.mFriendlyNames)
+ return Objects.equals(mOsuSsid, that.mOsuSsid)
+ && Objects.equals(mFriendlyNames, that.mFriendlyNames)
&& TextUtils.equals(mServiceDescription, that.mServiceDescription)
- && (mServerUri == null ? that.mServerUri == null
- : mServerUri.equals(that.mServerUri))
+ && Objects.equals(mServerUri, that.mServerUri)
&& TextUtils.equals(mNetworkAccessIdentifier, that.mNetworkAccessIdentifier)
- && (mMethodList == null ? that.mMethodList == null
- : mMethodList.equals(that.mMethodList))
- && (mIcon == null ? that.mIcon == null : mIcon.sameAs(that.mIcon));
+ && Objects.equals(mMethodList, that.mMethodList);
}
@Override
public int hashCode() {
- // mIcon is not hashable, skip the variable.
return Objects.hash(mOsuSsid, mServiceDescription, mFriendlyNames,
mServerUri, mNetworkAccessIdentifier, mMethodList);
}
@@ -264,8 +242,7 @@
+ " mServiceDescription=" + mServiceDescription
+ " mServerUri=" + mServerUri
+ " mNetworkAccessIdentifier=" + mNetworkAccessIdentifier
- + " mMethodList=" + mMethodList
- + " mIcon=" + mIcon;
+ + " mMethodList=" + mMethodList;
}
public static final @android.annotation.NonNull Creator<OsuProvider> CREATOR =
@@ -278,12 +255,11 @@
String nai = in.readString();
List<Integer> methodList = new ArrayList<>();
in.readList(methodList, null);
- Icon icon = in.readParcelable(null);
Bundle bundle = in.readBundle();
Map<String, String> friendlyNamesMap = (HashMap) bundle.getSerializable(
"friendlyNameMap");
return new OsuProvider(osuSsid, friendlyNamesMap, serviceDescription,
- serverUri, nai, methodList, icon);
+ serverUri, nai, methodList);
}
@Override
diff --git a/wifi/java/android/net/wifi/rtt/package.html b/wifi/java/android/net/wifi/rtt/package.html
index e639282..4a32f52 100644
--- a/wifi/java/android/net/wifi/rtt/package.html
+++ b/wifi/java/android/net/wifi/rtt/package.html
@@ -37,5 +37,9 @@
<pre>
getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)
</pre>
+
+<p>For an example of this functionality, see
+<a href="{@docRoot}guide/topics/connectivity/wifi-rtt" class="external">Wi-Fi location: ranging
+with RTT</a>.</p>
</BODY>
</HTML>
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index 534e609..bc86839 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -285,6 +285,11 @@
}
@Override
+ public boolean startTetheredHotspot(SoftApConfiguration softApConfig) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean stopSoftAp() {
throw new UnsupportedOperationException();
}
@@ -321,10 +326,21 @@
}
@Override
+ public SoftApConfiguration getSoftApConfiguration() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public boolean setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName) {
throw new UnsupportedOperationException();
}
+ @Override
+ public boolean setSoftApConfiguration(SoftApConfiguration softApConfig, String packageName) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public void notifyUserOfApBandConversion(String packageName) {
throw new UnsupportedOperationException();
}
@@ -385,6 +401,16 @@
}
@Override
+ public byte[] retrieveSoftApBackupData() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void restoreSoftApBackupData(byte[] data) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
throw new UnsupportedOperationException();
}
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
index 949b479..b8d3e41 100644
--- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -46,6 +46,10 @@
assertThat(original.getSsid()).isEqualTo("ssid");
assertThat(original.getBssid()).isEqualTo(MacAddress.fromString("11:22:33:44:55:66"));
assertThat(original.getWpa2Passphrase()).isNull();
+ assertThat(original.getSecurityType()).isEqualTo(SoftApConfiguration.SECURITY_TYPE_OPEN);
+ assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
+ assertThat(original.getChannel()).isEqualTo(0);
+ assertThat(original.isHiddenSsid()).isEqualTo(false);
SoftApConfiguration unparceled = parcelUnparcel(original);
assertThat(unparceled).isNotSameAs(original);
@@ -64,6 +68,39 @@
.setWpa2Passphrase("secretsecret")
.build();
assertThat(original.getWpa2Passphrase()).isEqualTo("secretsecret");
+ assertThat(original.getSecurityType()).isEqualTo(
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+ assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
+ assertThat(original.getChannel()).isEqualTo(0);
+ assertThat(original.isHiddenSsid()).isEqualTo(false);
+
+
+ SoftApConfiguration unparceled = parcelUnparcel(original);
+ assertThat(unparceled).isNotSameAs(original);
+ assertThat(unparceled).isEqualTo(original);
+ assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());
+
+ SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
+ assertThat(copy).isNotSameAs(original);
+ assertThat(copy).isEqualTo(original);
+ assertThat(copy.hashCode()).isEqualTo(original.hashCode());
+ }
+
+ @Test
+ public void testWpa2WithBandAndChannelAndHiddenNetwork() {
+ SoftApConfiguration original = new SoftApConfiguration.Builder()
+ .setWpa2Passphrase("secretsecret")
+ .setBand(SoftApConfiguration.BAND_ANY)
+ .setChannel(149)
+ .setHiddenSsid(true)
+ .build();
+ assertThat(original.getWpa2Passphrase()).isEqualTo("secretsecret");
+ assertThat(original.getSecurityType()).isEqualTo(
+ SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
+ assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_ANY);
+ assertThat(original.getChannel()).isEqualTo(149);
+ assertThat(original.isHiddenSsid()).isEqualTo(true);
+
SoftApConfiguration unparceled = parcelUnparcel(original);
assertThat(unparceled).isNotSameAs(original);
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index d326201..d22dbd3 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -181,6 +181,33 @@
}
/**
+ * Check the call to startSoftAp calls WifiService to startSoftAp with the provided
+ * WifiConfiguration. Verify that the return value is propagated to the caller.
+ */
+ @Test
+ public void testStartTetheredHotspotCallsServiceWithSoftApConfig() throws Exception {
+ SoftApConfiguration mSoftApConfig = new SoftApConfiguration.Builder().build();
+ when(mWifiService.startTetheredHotspot(eq(mSoftApConfig))).thenReturn(true);
+ assertTrue(mWifiManager.startTetheredHotspot(mSoftApConfig));
+
+ when(mWifiService.startTetheredHotspot(eq(mSoftApConfig))).thenReturn(false);
+ assertFalse(mWifiManager.startTetheredHotspot(mSoftApConfig));
+ }
+
+ /**
+ * Check the call to startSoftAp calls WifiService to startSoftAp with a null config. Verify
+ * that the return value is propagated to the caller.
+ */
+ @Test
+ public void testStartTetheredHotspotCallsServiceWithNullConfig() throws Exception {
+ when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(true);
+ assertTrue(mWifiManager.startTetheredHotspot(null));
+
+ when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(false);
+ assertFalse(mWifiManager.startTetheredHotspot(null));
+ }
+
+ /**
* Test creation of a LocalOnlyHotspotReservation and verify that close properly calls
* WifiService.stopLocalOnlyHotspot.
*/
@@ -1148,6 +1175,43 @@
}
/**
+ * Verify that a successful call properly returns true.
+ */
+ @Test
+ public void testSetSoftApConfigurationSuccessReturnsTrue() throws Exception {
+ SoftApConfiguration apConfig = new SoftApConfiguration.Builder().build();
+
+ when(mWifiService.setSoftApConfiguration(eq(apConfig), eq(TEST_PACKAGE_NAME)))
+ .thenReturn(true);
+ assertTrue(mWifiManager.setSoftApConfiguration(apConfig));
+ }
+
+ /**
+ * Verify that a failed call properly returns false.
+ */
+ @Test
+ public void testSetSoftApConfigurationFailureReturnsFalse() throws Exception {
+ SoftApConfiguration apConfig = new SoftApConfiguration.Builder().build();
+
+ when(mWifiService.setSoftApConfiguration(eq(apConfig), eq(TEST_PACKAGE_NAME)))
+ .thenReturn(false);
+ assertFalse(mWifiManager.setSoftApConfiguration(apConfig));
+ }
+
+ /**
+ * Verify Exceptions are rethrown when underlying calls to WifiService throw exceptions.
+ */
+ @Test
+ public void testSetSoftApConfigurationRethrowsException() throws Exception {
+ doThrow(new SecurityException()).when(mWifiService).setSoftApConfiguration(any(), any());
+
+ try {
+ mWifiManager.setSoftApConfiguration(new SoftApConfiguration.Builder().build());
+ fail("setWifiApConfiguration should rethrow Exceptions from WifiService");
+ } catch (SecurityException e) { }
+ }
+
+ /**
* Check the call to startScan calls WifiService.
*/
@Test
@@ -1620,7 +1684,7 @@
@Test
public void testGetControllerActivityEnergyInfo() throws Exception {
WifiActivityEnergyInfo activityEnergyInfo =
- new WifiActivityEnergyInfo(5, 3, 3, new long[]{5L, 5L, 5L}, 5, 5, 5, 5);
+ new WifiActivityEnergyInfo(5, 3, 3, 5, 5, 5, 5);
when(mWifiService.reportActivityInfo()).thenReturn(activityEnergyInfo);
assertEquals(activityEnergyInfo, mWifiManager.getControllerActivityEnergyInfo());
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java b/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
index 43ee249..2ded849 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
@@ -19,7 +19,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import android.graphics.drawable.Icon;
import android.net.Uri;
import android.net.wifi.WifiSsid;
import android.os.Parcel;
@@ -56,7 +55,6 @@
private static final String TEST_NAI = "test.access.com";
private static final List<Integer> TEST_METHOD_LIST =
Arrays.asList(OsuProvider.METHOD_SOAP_XML_SPP);
- private static final Icon TEST_ICON = Icon.createWithData(new byte[10], 0, 10);
/**
* Verify parcel write and read consistency for the given {@link OsuProvider}.
@@ -82,7 +80,7 @@
*/
@Test
public void verifyParcelWithEmptyProviderInfo() throws Exception {
- verifyParcel(new OsuProvider((WifiSsid) null, null, null, null, null, null, null));
+ verifyParcel(new OsuProvider((WifiSsid) null, null, null, null, null, null));
}
/**
@@ -93,7 +91,7 @@
@Test
public void verifyParcelWithFullProviderInfo() throws Exception {
verifyParcel(new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES,
- TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON));
+ TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST));
}
/**
@@ -102,7 +100,7 @@
*/
@Test
public void verifyCopyConstructorWithNullSource() throws Exception {
- OsuProvider expected = new OsuProvider((WifiSsid) null, null, null, null, null, null, null);
+ OsuProvider expected = new OsuProvider((WifiSsid) null, null, null, null, null, null);
assertEquals(expected, new OsuProvider(null));
}
@@ -114,7 +112,7 @@
@Test
public void verifyCopyConstructorWithValidSource() throws Exception {
OsuProvider source = new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES,
- TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON);
+ TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST);
assertEquals(source, new OsuProvider(source));
}
@@ -126,7 +124,7 @@
@Test
public void verifyGetters() throws Exception {
OsuProvider provider = new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES,
- TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON);
+ TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST);
assertTrue(TEST_SSID.equals(provider.getOsuSsid()));
assertTrue(TEST_FRIENDLY_NAME.equals(provider.getFriendlyName()));
@@ -135,6 +133,5 @@
assertTrue(TEST_SERVER_URI.equals(provider.getServerUri()));
assertTrue(TEST_NAI.equals(provider.getNetworkAccessIdentifier()));
assertTrue(TEST_METHOD_LIST.equals(provider.getMethodList()));
- assertTrue(TEST_ICON.sameAs(provider.getIcon()));
}
}