Merge "Remove CONNECTIVITY_ACTION and INET_CONDITION_ACTION"
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 3bdd4ad..4b0df44 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -485,29 +485,3 @@
":hwbinder-stubs-docs",
],
}
-
-/////////////////////////////////////////////////////////////////////
-// api/*-current.txt files for use by modules in other directories
-// like the CTS test
-/////////////////////////////////////////////////////////////////////
-
-filegroup {
- name: "frameworks-base-api-current.txt",
- srcs: [
- "api/current.txt",
- ],
-}
-
-filegroup {
- name: "frameworks-base-api-system-current.txt",
- srcs: [
- "api/system-current.txt",
- ],
-}
-
-filegroup {
- name: "frameworks-base-api-system-removed.txt",
- srcs: [
- "api/system-removed.txt",
- ],
-}
diff --git a/apex/extservices/apex_manifest.json b/apex/extservices/apex_manifest.json
index b4acf128..c0b59cc 100644
--- a/apex/extservices/apex_manifest.json
+++ b/apex/extservices/apex_manifest.json
@@ -1,4 +1,4 @@
{
"name": "com.android.extservices",
- "version": 300000000
+ "version": 300900700
}
diff --git a/apex/permission/apex_manifest.json b/apex/permission/apex_manifest.json
index 7960598..ab57930 100644
--- a/apex/permission/apex_manifest.json
+++ b/apex/permission/apex_manifest.json
@@ -1,4 +1,4 @@
{
"name": "com.android.permission",
- "version": 300000000
+ "version": 300900700
}
diff --git a/apex/statsd/apex_manifest.json b/apex/statsd/apex_manifest.json
index e2972e7..7bf1493 100644
--- a/apex/statsd/apex_manifest.json
+++ b/apex/statsd/apex_manifest.json
@@ -1,5 +1,5 @@
{
"name": "com.android.os.statsd",
- "version": 300000000
+ "version": 300900700
}
diff --git a/api/Android.bp b/api/Android.bp
index 54ff82c..cb6d448 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -1,7 +1,97 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_visibility: ["//visibility:private"],
+}
+
+// *-current.txt files for use by modules in other directories like cts
+filegroup {
+ name: "frameworks-base-api-current.txt",
+ srcs: ["current.txt"],
+ visibility: ["//visibility:public"],
+}
+
+filegroup {
+ name: "frameworks-base-api-system-current.txt",
+ srcs: ["system-current.txt"],
+ visibility: ["//visibility:public"],
+}
+
+filegroup {
+ name: "frameworks-base-api-system-removed.txt",
+ srcs: ["system-removed.txt"],
+ visibility: ["//visibility:public"],
+}
+
genrule {
name: "current-api-xml",
tools: ["metalava"],
srcs: ["current.txt"],
out: ["current.api"],
cmd: "$(location metalava) --no-banner -convert2xmlnostrip $(in) $(out)",
+ visibility: ["//visibility:public"],
+}
+
+genrule {
+ name: "frameworks-base-api-current-merged.txt",
+ srcs: [
+ ":conscrypt.module.public.api{.public.api.txt}",
+ ":framework-media{.public.api.txt}",
+ ":framework-mediaprovider{.public.api.txt}",
+ ":framework-permission{.public.api.txt}",
+ ":framework-sdkextensions{.public.api.txt}",
+ ":framework-statsd{.public.api.txt}",
+ ":framework-tethering{.public.api.txt}",
+ ":framework-wifi{.public.api.txt}",
+ ":non-updatable-current.txt",
+ ],
+ out: ["current.txt"],
+ tools: ["metalava"],
+ cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
+}
+
+genrule {
+ name: "frameworks-base-api-system-current-merged.txt",
+ srcs: [
+ ":framework-media{.system.api.txt}",
+ ":framework-mediaprovider{.system.api.txt}",
+ ":framework-permission{.system.api.txt}",
+ ":framework-sdkextensions{.system.api.txt}",
+ ":framework-statsd{.system.api.txt}",
+ ":framework-tethering{.system.api.txt}",
+ ":framework-wifi{.system.api.txt}",
+ ":non-updatable-system-current.txt",
+ ],
+ out: ["system-current.txt"],
+ tools: ["metalava"],
+ cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
+}
+
+genrule {
+ name: "frameworks-base-api-module-lib-current-merged.txt",
+ srcs: [
+ ":framework-media{.module-lib.api.txt}",
+ ":framework-mediaprovider{.module-lib.api.txt}",
+ ":framework-permission{.module-lib.api.txt}",
+ ":framework-sdkextensions{.module-lib.api.txt}",
+ ":framework-statsd{.module-lib.api.txt}",
+ ":framework-tethering{.module-lib.api.txt}",
+ ":framework-wifi{.module-lib.api.txt}",
+ ":non-updatable-module-lib-current.txt",
+ ],
+ out: ["module-lib-current.txt"],
+ tools: ["metalava"],
+ cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
}
diff --git a/api/current.txt b/api/current.txt
index 87b0cc8..68a22f2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -45970,6 +45970,8 @@
field public static final int MISSED = 5; // 0x5
field public static final int OTHER = 9; // 0x9
field public static final String REASON_EMERGENCY_CALL_PLACED = "REASON_EMERGENCY_CALL_PLACED";
+ field public static final String REASON_IMS_ACCESS_BLOCKED = "REASON_IMS_ACCESS_BLOCKED";
+ field public static final String REASON_WIFI_ON_BUT_WFC_OFF = "REASON_WIFI_ON_BUT_WFC_OFF";
field public static final int REJECTED = 6; // 0x6
field public static final int REMOTE = 3; // 0x3
field public static final int RESTRICTED = 8; // 0x8
@@ -46064,6 +46066,7 @@
field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
field public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 256; // 0x100
field @NonNull public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
+ field public static final String EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE = "android.telecom.extra.ALWAYS_USE_VOIP_AUDIO_MODE";
field public static final String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
field public static final String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
field public static final String EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
@@ -46630,6 +46633,7 @@
field public static final String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
field public static final String KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY = "apn_settings_default_apn_types_string_array";
field public static final String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
+ field public static final String KEY_CALL_BARRING_DEFAULT_SERVICE_CLASS_INT = "call_barring_default_service_class_int";
field public static final String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL = "call_barring_supports_deactivate_all_bool";
field public static final String KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL = "call_barring_supports_password_change_bool";
field public static final String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool";
@@ -46857,6 +46861,8 @@
field public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING = "wfc_emergency_address_carrier_app_string";
field public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool";
field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
+ field public static final int SERVICE_CLASS_NONE = 0; // 0x0
+ field public static final int SERVICE_CLASS_VOICE = 1; // 0x1
}
public static final class CarrierConfigManager.Apn {
diff --git a/api/system-current.txt b/api/system-current.txt
index c0364a3..7276b37 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1578,12 +1578,16 @@
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setBluetoothTethering(boolean);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
+ field public static final String ACTION_TETHERING_STATE_CHANGED = "android.bluetooth.action.TETHERING_STATE_CHANGED";
field public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
+ field public static final String EXTRA_TETHERING_STATE = "android.bluetooth.extra.TETHERING_STATE";
field public static final int LOCAL_NAP_ROLE = 1; // 0x1
field public static final int LOCAL_PANU_ROLE = 2; // 0x2
field public static final int PAN_ROLE_NONE = 0; // 0x0
field public static final int REMOTE_NAP_ROLE = 1; // 0x1
field public static final int REMOTE_PANU_ROLE = 2; // 0x2
+ field public static final int TETHERING_STATE_OFF = 1; // 0x1
+ field public static final int TETHERING_STATE_ON = 2; // 0x2
}
public class BluetoothPbap implements android.bluetooth.BluetoothProfile {
@@ -9239,6 +9243,7 @@
field public static final String APN_SET_ID = "apn_set_id";
field public static final int CARRIER_EDITED = 4; // 0x4
field public static final String EDITED_STATUS = "edited";
+ field public static final int MATCH_ALL_APN_SET_ID = -1; // 0xffffffff
field public static final String MAX_CONNECTIONS = "max_conns";
field public static final String MODEM_PERSIST = "modem_cognitive";
field public static final String MTU = "mtu";
@@ -10249,6 +10254,10 @@
method public final void addExistingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.Connection, @NonNull android.telecom.Conference);
}
+ public final class DisconnectCause implements android.os.Parcelable {
+ field public static final String REASON_EMULATING_SINGLE_CALL = "EMULATING_SINGLE_CALL";
+ }
+
public abstract class InCallService extends android.app.Service {
method @Deprecated public android.telecom.Phone getPhone();
method @Deprecated public void onPhoneCreated(android.telecom.Phone);
@@ -10377,7 +10386,12 @@
}
public final class PhoneAccount implements android.os.Parcelable {
+ field public static final int CAPABILITY_EMERGENCY_CALLS_ONLY = 128; // 0x80
+ field public static final int CAPABILITY_EMERGENCY_PREFERRED = 8192; // 0x2000
+ field public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 512; // 0x200
field public static final int CAPABILITY_MULTI_USER = 32; // 0x20
+ field public static final String EXTRA_PLAY_CALL_RECORDING_TONE = "android.telecom.extra.PLAY_CALL_RECORDING_TONE";
+ field public static final String EXTRA_SORT_ORDER = "android.telecom.extra.SORT_ORDER";
}
public static class PhoneAccount.Builder {
@@ -10463,10 +10477,20 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(@Nullable android.telecom.PhoneAccountHandle);
+ field public static final String ACTION_CURRENT_TTY_MODE_CHANGED = "android.telecom.action.CURRENT_TTY_MODE_CHANGED";
+ field public static final String ACTION_TTY_PREFERRED_MODE_CHANGED = "android.telecom.action.TTY_PREFERRED_MODE_CHANGED";
+ field public static final int CALL_SOURCE_EMERGENCY_DIALPAD = 1; // 0x1
+ field public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2; // 0x2
+ field public static final int CALL_SOURCE_UNSPECIFIED = 0; // 0x0
field public static final String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT";
+ field public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE";
+ field public static final String EXTRA_CALL_TECHNOLOGY_TYPE = "android.telecom.extra.CALL_TECHNOLOGY_TYPE";
field public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT";
field public static final String EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE";
+ field public static final String EXTRA_CURRENT_TTY_MODE = "android.telecom.extra.CURRENT_TTY_MODE";
field public static final String EXTRA_IS_USER_INTENT_EMERGENCY_CALL = "android.telecom.extra.IS_USER_INTENT_EMERGENCY_CALL";
+ field public static final String EXTRA_TTY_PREFERRED_MODE = "android.telecom.extra.TTY_PREFERRED_MODE";
+ field public static final String EXTRA_UNKNOWN_CALL_HANDLE = "android.telecom.extra.UNKNOWN_CALL_HANDLE";
field public static final int TTY_MODE_FULL = 1; // 0x1
field public static final int TTY_MODE_HCO = 2; // 0x2
field public static final int TTY_MODE_OFF = 0; // 0x0
diff --git a/api/test-current.txt b/api/test-current.txt
index 1576b94..415ed03 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -17,6 +17,7 @@
field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
field public static final String NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK";
+ field public static final String OVERRIDE_DISPLAY_MODE_REQUESTS = "android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS";
field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
@@ -3928,6 +3929,10 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(@Nullable android.telecom.PhoneAccountHandle);
+ field public static final String ACTION_CURRENT_TTY_MODE_CHANGED = "android.telecom.action.CURRENT_TTY_MODE_CHANGED";
+ field public static final String ACTION_TTY_PREFERRED_MODE_CHANGED = "android.telecom.action.TTY_PREFERRED_MODE_CHANGED";
+ field public static final String EXTRA_CURRENT_TTY_MODE = "android.telecom.extra.CURRENT_TTY_MODE";
+ field public static final String EXTRA_TTY_PREFERRED_MODE = "android.telecom.extra.TTY_PREFERRED_MODE";
field public static final int TTY_MODE_FULL = 1; // 0x1
field public static final int TTY_MODE_HCO = 2; // 0x2
field public static final int TTY_MODE_OFF = 0; // 0x0
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index bfc28fa..4698b07 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -89,6 +89,33 @@
@SuppressLint("ActionValue")
public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
+ /**
+ * Intent used to broadcast the change in tethering state of the Pan
+ * Profile
+ *
+ * <p>This intent will have 1 extra:
+ * <ul>
+ * <li> {@link #EXTRA_TETHERING_STATE} - The current state of Bluetooth
+ * tethering. </li>
+ * </ul>
+ *
+ * <p> {@link #EXTRA_TETHERING_STATE} can be any of {@link #TETHERING_STATE_OFF} or
+ * {@link #TETHERING_STATE_ON}
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+ * receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_TETHERING_STATE_CHANGED =
+ "android.bluetooth.action.TETHERING_STATE_CHANGED";
+
+ /**
+ * Extra for {@link #ACTION_TETHERING_STATE_CHANGED} intent
+ * The tethering state of the PAN profile.
+ * It can be one of {@link #TETHERING_STATE_OFF} or {@link #TETHERING_STATE_ON}.
+ */
+ public static final String EXTRA_TETHERING_STATE =
+ "android.bluetooth.extra.TETHERING_STATE";
+
/** @hide */
@IntDef({PAN_ROLE_NONE, LOCAL_NAP_ROLE, LOCAL_PANU_ROLE})
@Retention(RetentionPolicy.SOURCE)
@@ -114,6 +141,14 @@
public static final int REMOTE_PANU_ROLE = 2;
+ /** @hide **/
+ @IntDef({TETHERING_STATE_OFF, TETHERING_STATE_ON})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TetheringState{}
+
+ public static final int TETHERING_STATE_OFF = 1;
+
+ public static final int TETHERING_STATE_ON = 2;
/**
* Return codes for the connect and disconnect Bluez / Dbus calls.
*
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index bd02210..31c77ee 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -963,7 +963,7 @@
/** @hide */
public static final int LOCK_TASK_LAUNCH_MODE_ALWAYS = 2;
/** @hide */
- public static final int LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED = 3;
+ public static final int LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED = 3;
/** @hide */
public static final String lockTaskLaunchModeToString(int lockTaskLaunchMode) {
@@ -974,8 +974,8 @@
return "LOCK_TASK_LAUNCH_MODE_NEVER";
case LOCK_TASK_LAUNCH_MODE_ALWAYS:
return "LOCK_TASK_LAUNCH_MODE_ALWAYS";
- case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
- return "LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED";
+ case LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED:
+ return "LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED";
default:
return "unknown=" + lockTaskLaunchMode;
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 2a78eb9..8f4fc26 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -146,8 +146,15 @@
public int uiOptions = 0;
/**
- * Value for {@link #flags}: if set, this application is installed in the
- * device's system image.
+ * Value for {@link #flags}: if set, this application is installed in the device's system image.
+ * This should not be used to make security decisions. Instead, rely on
+ * {@linkplain android.content.pm.PackageManager#checkSignatures(java.lang.String,java.lang.String)
+ * signature checks} or
+ * <a href="https://developer.android.com/training/articles/security-tips#Permissions">permissions</a>.
+ *
+ * <p><b>Warning:</b> Note that does flag not behave the same as
+ * {@link android.R.attr#protectionLevel android:protectionLevel} {@code system} or
+ * {@code signatureOrSystem}.
*/
public static final int FLAG_SYSTEM = 1<<0;
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index cc4c456..a6e8c13 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -1245,6 +1245,7 @@
return true;
case TYPE_HINGE_ANGLE:
mStringType = STRING_TYPE_HINGE_ANGLE;
+ return true;
default:
return false;
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 4b2cfe2..a2e53e2 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -2551,14 +2551,16 @@
public static native long getZramFreeKb();
/**
- * Return memory size in kilobytes allocated for ION heaps.
+ * Return memory size in kilobytes allocated for ION heaps or -1 if
+ * /sys/kernel/ion/total_heaps_kb could not be read.
*
* @hide
*/
public static native long getIonHeapsSizeKb();
/**
- * Return memory size in kilobytes allocated for ION pools.
+ * Return memory size in kilobytes allocated for ION pools or -1 if
+ * /sys/kernel/ion/total_pools_kb could not be read.
*
* @hide
*/
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 784119f..2c2d127 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3948,8 +3948,7 @@
/**
* The APN set id. When the user manually selects an APN or the framework sets an APN as
- * preferred, all APNs with the same set id as the selected APN should be prioritized over
- * APNs in other sets.
+ * preferred, the device can only use APNs with the same set id as the selected APN.
* <p>Type: INTEGER</p>
* @hide
*/
@@ -3957,9 +3956,7 @@
public static final String APN_SET_ID = "apn_set_id";
/**
- * Possible value for the {@link #APN_SET_ID} field. By default APNs will not belong to a
- * set. If the user manually selects an APN without apn set id, there is no need to
- * prioritize any specific APN set ids.
+ * Possible value for the {@link #APN_SET_ID} field. By default APNs are added to set 0.
* <p>Type: INTEGER</p>
* @hide
*/
@@ -3967,6 +3964,16 @@
public static final int NO_APN_SET_ID = 0;
/**
+ * Possible value for the {@link #APN_SET_ID} field.
+ * APNs with MATCH_ALL_APN_SET_ID will be used regardless of any set ids of
+ * the selected APN.
+ * <p>Type: INTEGER</p>
+ * @hide
+ */
+ @SystemApi
+ public static final int MATCH_ALL_APN_SET_ID = -1;
+
+ /**
* A unique carrier id associated with this APN
* {@see TelephonyManager#getSimCarrierId()}
* <p>Type: STRING</p>
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 0a47032..2dbce7b 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -104,6 +104,10 @@
public void addOnSubscriptionsChangedListener(
@NonNull SubscriptionManager.OnSubscriptionsChangedListener listener,
@NonNull Executor executor) {
+ if (mSubscriptionChangedListenerMap.get(listener) != null) {
+ Log.d(TAG, "addOnSubscriptionsChangedListener listener already present");
+ return;
+ }
IOnSubscriptionsChangedListener callback = new IOnSubscriptionsChangedListener.Stub() {
@Override
public void onSubscriptionsChanged () {
@@ -153,6 +157,10 @@
public void addOnOpportunisticSubscriptionsChangedListener(
@NonNull SubscriptionManager.OnOpportunisticSubscriptionsChangedListener listener,
@NonNull Executor executor) {
+ if (mOpportunisticSubscriptionChangedListenerMap.get(listener) != null) {
+ Log.d(TAG, "addOnOpportunisticSubscriptionsChangedListener listener already present");
+ return;
+ }
/**
* The callback methods need to be called on the executor thread where
* this object was created. If the binder did that for us it'd be nice.
@@ -188,6 +196,9 @@
*/
public void removeOnOpportunisticSubscriptionsChangedListener(
@NonNull SubscriptionManager.OnOpportunisticSubscriptionsChangedListener listener) {
+ if (mOpportunisticSubscriptionChangedListenerMap.get(listener) == null) {
+ return;
+ }
try {
sRegistry.removeOnSubscriptionsChangedListener(mContext.getOpPackageName(),
mOpportunisticSubscriptionChangedListenerMap.get(listener));
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index bb4623b..92ed904 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -151,7 +151,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- static final int VERSION = 186 + (USE_OLD_HISTORY ? 1000 : 0);
+ static final int VERSION = 188 + (USE_OLD_HISTORY ? 1000 : 0);
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -13596,6 +13596,7 @@
mDailyStartTime = in.readLong();
mNextMinDailyDeadline = in.readLong();
mNextMaxDailyDeadline = in.readLong();
+ mBatteryTimeToFullSeconds = in.readLong();
mStartCount++;
@@ -14086,6 +14087,7 @@
out.writeLong(mDailyStartTime);
out.writeLong(mNextMinDailyDeadline);
out.writeLong(mNextMaxDailyDeadline);
+ out.writeLong(mBatteryTimeToFullSeconds);
mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mScreenDozeTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -14669,6 +14671,7 @@
mDischargeLightDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase, in);
mDischargeDeepDozeCounter = new LongSamplingCounter(mOnBatteryTimeBase, in);
mLastWriteTime = in.readLong();
+ mBatteryTimeToFullSeconds = in.readLong();
mRpmStats.clear();
int NRPMS = in.readInt();
@@ -14861,6 +14864,7 @@
mDischargeLightDozeCounter.writeToParcel(out);
mDischargeDeepDozeCounter.writeToParcel(out);
out.writeLong(mLastWriteTime);
+ out.writeLong(mBatteryTimeToFullSeconds);
out.writeInt(mRpmStats.size());
for (Map.Entry<String, SamplingTimer> ent : mRpmStats.entrySet()) {
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index ef0eeec..5a859aa 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -792,7 +792,7 @@
}
static jlong android_os_Debug_getIonHeapsSizeKb(JNIEnv* env, jobject clazz) {
- jlong heapsSizeKb = 0;
+ jlong heapsSizeKb = -1;
uint64_t size;
if (meminfo::ReadIonHeapsSizeKb(&size)) {
@@ -803,7 +803,7 @@
}
static jlong android_os_Debug_getIonPoolsSizeKb(JNIEnv* env, jobject clazz) {
- jlong poolsSizeKb = 0;
+ jlong poolsSizeKb = -1;
uint64_t size;
if (meminfo::ReadIonPoolsSizeKb(&size)) {
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 7daefd3..26e862f 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -63,6 +63,7 @@
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
int32_t configId, nsecs_t vsyncPeriod) override;
+ void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {}
};
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 84e56b7..8656820 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -236,6 +236,8 @@
android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_DELIVERY" />
<protected-broadcast
android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
+ <protected-broadcast
+ android:name="android.bluetooth.action.TETHERING_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED" />
@@ -3907,6 +3909,13 @@
<permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS"
android:protectionLevel="signature" />
+ <!-- @TestApi Allows an application to override the display mode requests
+ so the app requested mode will be selected and user settings and display
+ policies will be ignored.
+ @hide -->
+ <permission android:name="android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows an application to control VPN.
<p>Not for use by third-party applications.</p>
@hide -->
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 1ba48ca..a1478cf 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1169,7 +1169,7 @@
<string name="Midnight" msgid="8176019203622191377">"منتصف الليل"</string>
<string name="elapsed_time_short_format_mm_ss" msgid="8689459651807876423">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="2302144714803345056">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
- <string name="selectAll" msgid="1532369154488982046">"تحديد الكل"</string>
+ <string name="selectAll" msgid="1532369154488982046">"اختيار الكل"</string>
<string name="cut" msgid="2561199725874745819">"قص"</string>
<string name="copy" msgid="5472512047143665218">"نسخ"</string>
<string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"تعذّر النسخ في الحافظة"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 5ac5770..52c2be0 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1548,7 +1548,7 @@
<string name="launchBrowserDefault" msgid="6328349989932924119">"ब्राउज़र लॉन्च करें?"</string>
<string name="SetupCallDefault" msgid="5581740063237175247">"कॉल स्वीकार करें?"</string>
<string name="activity_resolver_use_always" msgid="5575222334666843269">"हमेशा"</string>
- <string name="activity_resolver_use_once" msgid="948462794469672658">"सिर्फ़ एक बार"</string>
+ <string name="activity_resolver_use_once" msgid="948462794469672658">"केवल एक बार"</string>
<string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s वर्क प्रोफ़ाइल का समर्थन नहीं करता"</string>
<string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"टैबलेट"</string>
<string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"टीवी"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index c071fc7..bd85908 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1108,7 +1108,7 @@
<string name="inputMethod" msgid="1784759500516314751">"Киргизүү ыкмасы"</string>
<string name="editTextMenuTitle" msgid="857666911134482176">"Текст боюнча иштер"</string>
<string name="low_internal_storage_view_title" msgid="9024241779284783414">"Сактагычта орун калбай баратат"</string>
- <string name="low_internal_storage_view_text" msgid="8172166728369697835">"Айрым функциялар иштебеши мүмкүн"</string>
+ <string name="low_internal_storage_view_text" msgid="8172166728369697835">"Системанын кээ бир функциялары иштебеши мүмкүн"</string>
<string name="low_internal_storage_view_text_no_boot" msgid="7368968163411251788">"Тутумда сактагыч жетишсиз. 250МБ бош орун бар экенин текшерип туруп, өчүрүп күйгүзүңүз."</string>
<string name="app_running_notification_title" msgid="8985999749231486569">"<xliff:g id="APP_NAME">%1$s</xliff:g> иштөөдө"</string>
<string name="app_running_notification_text" msgid="5120815883400228566">"Көбүрөөк маалымат үчүн же колдонмону токтотуш үчүн таптап коюңуз."</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index faf1b3f..f05ee8a 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1547,7 +1547,7 @@
<string name="sending" msgid="206925243621664438">"അയയ്ക്കുന്നു…"</string>
<string name="launchBrowserDefault" msgid="6328349989932924119">"ബ്രൗസർ സമാരംഭിക്കണോ?"</string>
<string name="SetupCallDefault" msgid="5581740063237175247">"കോൾ സ്വീകരിക്കണോ?"</string>
- <string name="activity_resolver_use_always" msgid="5575222334666843269">"എല്ലായ്പ്പോഴും"</string>
+ <string name="activity_resolver_use_always" msgid="5575222334666843269">"എല്ലായ്പ്പോഴും"</string>
<string name="activity_resolver_use_once" msgid="948462794469672658">"ഒരിക്കൽ മാത്രം"</string>
<string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s, ഔദ്യോഗിക പ്രൊഫൈലിനെ പിന്തുണയ്ക്കുന്നില്ല"</string>
<string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"ടാബ്ലെറ്റ്"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 1a0ec2a..9c99bdd 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -536,7 +536,7 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Cho phép ứng dụng này sửa đổi bộ sưu tập ảnh của bạn."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"đọc vị trí từ bộ sưu tập phương tiện"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Cho phép ứng dụng này đọc vị trí từ bộ sưu tập phương tiện của bạn."</string>
- <string name="biometric_dialog_default_title" msgid="55026799173208210">"Xác minh danh tính của bạn"</string>
+ <string name="biometric_dialog_default_title" msgid="55026799173208210">"Xác minh đó là bạn"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Không có phần cứng sinh trắc học"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Đã hủy xác thực"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Không nhận dạng được"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index cba68d6..e0b58dd 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3420,7 +3420,7 @@
<string name="config_emergency_call_number" translatable="false">112</string>
<!-- Package name that provides Emergency Dialer -->
- <string name="config_emergency_dialer_package">com.android.phone</string>
+ <string name="config_emergency_dialer_package" translatable="false">com.android.phone</string>
<!-- Do not translate. Mcc codes whose existence trigger the presence of emergency
affordances-->
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 5c2841a..b39c89b 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -212,13 +212,6 @@
</intent-filter>
</activity>
- <activity android:name="android.widget.focus.ListOfButtons" android:label="ListOfButtons">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
- </intent-filter>
- </activity>
-
<activity android:name="android.widget.focus.LinearLayoutGrid" android:label="LinearLayoutGrid">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java b/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java
deleted file mode 100644
index 936c999..0000000
--- a/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget.focus;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.ListView;
-
-import com.google.android.collect.Lists;
-
-import java.util.List;
-
-public class ListOfEditTexts extends Activity {
-
- private int mLinesPerEditText = 12;
-
- private ListView mListView;
- private LinearLayout mLinearLayout;
-
- public ListView getListView() {
- return mListView;
- }
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- // create linear layout
- mLinearLayout = new LinearLayout(this);
- mLinearLayout.setOrientation(LinearLayout.VERTICAL);
- mLinearLayout.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- // add a button above
- Button buttonAbove = new Button(this);
- buttonAbove.setLayoutParams(
- new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- buttonAbove.setText("button above list");
- mLinearLayout.addView(buttonAbove);
-
- // add a list view to it
- mListView = new ListView(this);
- mListView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
- mListView.setDrawSelectorOnTop(false);
- mListView.setItemsCanFocus(true);
- mListView.setLayoutParams((new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- 0,
- 1f)));
-
- List<String> bodies = Lists.newArrayList(
- getBody("zero hello, my name is android"),
- getBody("one i'm a paranoid android"),
- getBody("two i robot. huh huh."),
- getBody("three not the g-phone!"));
-
- mListView.setAdapter(new MyAdapter(this, bodies));
- mLinearLayout.addView(mListView);
-
- // add button below
- Button buttonBelow = new Button(this);
- buttonBelow.setLayoutParams(
- new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- buttonBelow.setText("button below list");
- mLinearLayout.addView(buttonBelow);
-
- setContentView(mLinearLayout);
- }
-
- String getBody(String line) {
- StringBuilder sb = new StringBuilder((line.length() + 5) * mLinesPerEditText);
- for (int i = 0; i < mLinesPerEditText; i++) {
- sb.append(i + 1).append(' ').append(line);
- if (i < mLinesPerEditText - 1) {
- sb.append('\n'); // all but last line
- }
- }
- return sb.toString();
- }
-
-
- private static class MyAdapter extends ArrayAdapter<String> {
-
- public MyAdapter(Context context, List<String> bodies) {
- super(context, 0, bodies);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- String body = getItem(position);
-
- if (convertView != null) {
- ((EditText) convertView).setText(body);
- return convertView;
- }
-
- EditText editText = new EditText(getContext());
- editText.setText(body);
- return editText;
- }
- }
-}
diff --git a/core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java b/core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java
index 55d186c..469a4cc 100644
--- a/core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java
@@ -16,16 +16,17 @@
package com.android.internal.util;
-import com.android.internal.util.CharSequences;
import static com.android.internal.util.CharSequences.forAsciiBytes;
-import junit.framework.TestCase;
+
import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
public class CharSequencesTest extends TestCase {
@SmallTest
public void testCharSequences() {
- String s = "Crazy Bob";
+ String s = "Hello Bob";
byte[] bytes = s.getBytes();
String copy = toString(forAsciiBytes(bytes));
@@ -34,11 +35,11 @@
copy = toString(forAsciiBytes(bytes, 0, s.length()));
assertTrue(s.equals(copy));
- String crazy = toString(forAsciiBytes(bytes, 0, 5));
- assertTrue("Crazy".equals(crazy));
+ String hello = toString(forAsciiBytes(bytes, 0, 5));
+ assertTrue("Hello".equals(hello));
- String a = toString(forAsciiBytes(bytes, 0, 3).subSequence(2, 3));
- assertTrue("a".equals(a));
+ String l = toString(forAsciiBytes(bytes, 0, 3).subSequence(2, 3));
+ assertTrue("l".equals(l));
String empty = toString(forAsciiBytes(bytes, 0, 3).subSequence(3, 3));
assertTrue("".equals(empty));
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index cf31216..5f159a1 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -227,8 +227,7 @@
<library name="android.test.base"
file="/system/framework/android.test.base.jar" />
<library name="android.test.mock"
- file="/system/framework/android.test.mock.jar"
- dependency="android.test.base" />
+ file="/system/framework/android.test.mock.jar" />
<library name="android.test.runner"
file="/system/framework/android.test.runner.jar"
dependency="android.test.base:android.test.mock" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index c710bed..672b428 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -219,6 +219,7 @@
<permission name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
<permission name="android.permission.UPDATE_DEVICE_STATS"/>
+ <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
</privapp-permissions>
<privapp-permissions package="com.android.providers.media.module">
@@ -432,6 +433,13 @@
<permission name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
</privapp-permissions>
+ <privapp-permissions package="com.android.traceur">
+ <!-- Permissions required to receive BUGREPORT_STARTED intent -->
+ <permission name="android.permission.DUMP"/>
+ <!-- Permissions required for quick settings tile -->
+ <permission name="android.permission.STATUS_BAR"/>
+ </privapp-permissions>
+
<privapp-permissions package="com.android.tv">
<permission name="android.permission.CHANGE_HDMI_CEC_ACTIVE_SOURCE"/>
<permission name="android.permission.DVB_DEVICE"/>
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index c8f065a..71744ef 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -308,7 +308,7 @@
ImageDecoder decoder = null;
try {
- decoder = nCreate(fd, preferAnimation, source);
+ decoder = nCreate(fd, AssetFileDescriptor.UNKNOWN_LENGTH, preferAnimation, source);
} finally {
if (decoder == null) {
IoUtils.closeQuietly(stream);
@@ -356,7 +356,7 @@
try {
try {
Os.lseek(fd, offset, SEEK_SET);
- decoder = nCreate(fd, preferAnimation, source);
+ decoder = nCreate(fd, assetFd.getDeclaredLength(), preferAnimation, source);
} catch (ErrnoException e) {
decoder = createFromStream(new FileInputStream(fd), true, preferAnimation, source);
}
@@ -1995,7 +1995,7 @@
private static native ImageDecoder nCreate(InputStream is, byte[] storage,
boolean preferAnimation, Source src) throws IOException;
// The fd must be seekable.
- private static native ImageDecoder nCreate(FileDescriptor fd,
+ private static native ImageDecoder nCreate(FileDescriptor fd, long length,
boolean preferAnimation, Source src) throws IOException;
@NonNull
private static native Bitmap nDecodeBitmap(long nativePtr,
diff --git a/libs/androidfw/include/androidfw/ConfigDescription.h b/libs/androidfw/include/androidfw/ConfigDescription.h
index acf413a..61d10cd 100644
--- a/libs/androidfw/include/androidfw/ConfigDescription.h
+++ b/libs/androidfw/include/androidfw/ConfigDescription.h
@@ -177,9 +177,8 @@
return *this;
}
-inline bool ConfigDescription::MatchWithDensity(
- const ConfigDescription& o) const {
- return match(o) && (density == 0 || density == o.density);
+inline bool ConfigDescription::MatchWithDensity(const ConfigDescription& o) const {
+ return match(o) && (density == 0 || o.density != 0);
}
inline bool ConfigDescription::operator<(const ConfigDescription& o) const {
diff --git a/libs/hwui/OWNERS b/libs/hwui/OWNERS
index c232d13..bb93e66 100644
--- a/libs/hwui/OWNERS
+++ b/libs/hwui/OWNERS
@@ -5,3 +5,6 @@
reed@google.com
scroggo@google.com
stani@google.com
+
+# For text, e.g. Typeface, Font, Minikin, etc.
+nona@google.com
diff --git a/libs/hwui/jni/ImageDecoder.cpp b/libs/hwui/jni/ImageDecoder.cpp
index 41d939b..c8c3d3d 100644
--- a/libs/hwui/jni/ImageDecoder.cpp
+++ b/libs/hwui/jni/ImageDecoder.cpp
@@ -152,7 +152,7 @@
}
static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
- jobject fileDescriptor, jboolean preferAnimation, jobject source) {
+ jobject fileDescriptor, jlong length, jboolean preferAnimation, jobject source) {
#ifndef __ANDROID__ // LayoutLib for Windows does not support F_DUPFD_CLOEXEC
return throw_exception(env, kSourceException, "Only supported on Android", nullptr, source);
#else
@@ -172,7 +172,14 @@
nullptr, source);
}
- std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file));
+ std::unique_ptr<SkFILEStream> fileStream;
+ if (length == -1) {
+ // -1 corresponds to AssetFileDescriptor.UNKNOWN_LENGTH. Pass no length
+ // so SkFILEStream will figure out the size of the file on its own.
+ fileStream.reset(new SkFILEStream(file));
+ } else {
+ fileStream.reset(new SkFILEStream(file, length));
+ }
return native_create(env, std::move(fileStream), source, preferAnimation);
#endif
}
@@ -494,7 +501,7 @@
{ "nCreate", "(Ljava/nio/ByteBuffer;IIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
{ "nCreate", "([BIIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
{ "nCreate", "(Ljava/io/InputStream;[BZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
- { "nCreate", "(Ljava/io/FileDescriptor;ZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
+ { "nCreate", "(Ljava/io/FileDescriptor;JZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
{ "nDecodeBitmap", "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZJZ)Landroid/graphics/Bitmap;",
(void*) ImageDecoder_nDecodeBitmap },
{ "nGetSampledSize","(JI)Landroid/util/Size;", (void*) ImageDecoder_nGetSampledSize },
diff --git a/media/OWNERS b/media/OWNERS
index c95ac6c..36df3a0 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -9,6 +9,7 @@
hunga@google.com
insun@google.com
jaewan@google.com
+jinpark@google.com
jmtrivi@google.com
jsharkey@android.com
klhyun@google.com
@@ -17,6 +18,3 @@
philburk@google.com
sungsoo@google.com
wonsik@google.com
-
-# For maintaining sync with AndroidX code
-per-file ExifInterface.java = jinpark@google.com, sungsoo@google.com
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index ed566a5..5fce5ee 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -16,6 +16,12 @@
package android.media;
+import static android.media.ExifInterfaceUtils.byteArrayToHexString;
+import static android.media.ExifInterfaceUtils.closeQuietly;
+import static android.media.ExifInterfaceUtils.convertToLongArray;
+import static android.media.ExifInterfaceUtils.copy;
+import static android.media.ExifInterfaceUtils.startsWith;
+
import android.annotation.CurrentTimeMillisLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -32,10 +38,6 @@
import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.ArrayUtils;
-
-import libcore.io.IoUtils;
-import libcore.io.Streams;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -73,11 +75,11 @@
import java.util.zip.CRC32;
/**
- * This is a class for reading and writing Exif tags in a JPEG file or a RAW image file.
+ * This is a class for reading and writing Exif tags in various image file formats.
* <p>
- * Supported formats are: JPEG, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF and HEIF.
+ * Supported for reading: JPEG, PNG, WebP, HEIF, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF.
* <p>
- * Attribute mutation is supported for JPEG image files.
+ * Supported for writing: JPEG, PNG, WebP.
* <p>
* Note: It is recommended to use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
* <a href="{@docRoot}reference/androidx/exifinterface/media/ExifInterface.html">ExifInterface
@@ -583,6 +585,15 @@
private static final int WEBP_FILE_SIZE_BYTE_LENGTH = 4;
private static final byte[] WEBP_CHUNK_TYPE_EXIF = new byte[]{(byte) 0x45, (byte) 0x58,
(byte) 0x49, (byte) 0x46};
+ private static final byte[] WEBP_VP8_SIGNATURE = new byte[]{(byte) 0x9d, (byte) 0x01,
+ (byte) 0x2a};
+ private static final byte WEBP_VP8L_SIGNATURE = (byte) 0x2f;
+ private static final byte[] WEBP_CHUNK_TYPE_VP8X = "VP8X".getBytes(Charset.defaultCharset());
+ private static final byte[] WEBP_CHUNK_TYPE_VP8L = "VP8L".getBytes(Charset.defaultCharset());
+ private static final byte[] WEBP_CHUNK_TYPE_VP8 = "VP8 ".getBytes(Charset.defaultCharset());
+ private static final byte[] WEBP_CHUNK_TYPE_ANIM = "ANIM".getBytes(Charset.defaultCharset());
+ private static final byte[] WEBP_CHUNK_TYPE_ANMF = "ANMF".getBytes(Charset.defaultCharset());
+ private static final int WEBP_CHUNK_TYPE_VP8X_DEFAULT_LENGTH = 10;
private static final int WEBP_CHUNK_TYPE_BYTE_LENGTH = 4;
private static final int WEBP_CHUNK_SIZE_BYTE_LENGTH = 4;
@@ -1540,7 +1551,7 @@
in = new FileInputStream(fileDescriptor, isFdOwner);
loadAttributes(in);
} finally {
- IoUtils.closeQuietly(in);
+ closeQuietly(in);
}
}
@@ -1607,7 +1618,7 @@
}
/**
- * Returns whether ExifInterface currently supports parsing data from the specified mime type
+ * Returns whether ExifInterface currently supports reading data from the specified mime type
* or not.
*
* @param mimeType the string value of mime type
@@ -1631,6 +1642,8 @@
case "image/x-fuji-raf":
case "image/heic":
case "image/heif":
+ case "image/png":
+ case "image/webp":
return true;
default:
return false;
@@ -2044,18 +2057,21 @@
* {@link #setAttribute(String,String)} to set all attributes to write and
* make a single call rather than multiple calls for each attribute.
* <p>
- * This method is only supported for JPEG and PNG files.
+ * This method is supported for JPEG, PNG and WebP files.
* <p class="note">
* Note: after calling this method, any attempts to obtain range information
* from {@link #getAttributeRange(String)} or {@link #getThumbnailRange()}
* will throw {@link IllegalStateException}, since the offsets may have
* changed in the newly written file.
+ * <p>
+ * For WebP format, the Exif data will be stored as an Extended File Format, and it may not be
+ * supported for older readers.
* </p>
*/
public void saveAttributes() throws IOException {
- if (!mIsSupportedFile || (mMimeType != IMAGE_TYPE_JPEG && mMimeType != IMAGE_TYPE_PNG)) {
- throw new IOException("ExifInterface only supports saving attributes on JPEG or PNG "
- + "formats.");
+ if (!isSupportedFormatForSavingAttributes()) {
+ throw new IOException("ExifInterface only supports saving attributes on JPEG, PNG, "
+ + "or WebP formats.");
}
if (mIsInputStream || (mSeekableFileDescriptor == null && mFilename == null)) {
throw new IOException(
@@ -2084,21 +2100,17 @@
throw new IOException("Couldn't rename to " + tempFile.getAbsolutePath());
}
} else if (mSeekableFileDescriptor != null) {
- if (mMimeType == IMAGE_TYPE_JPEG) {
- tempFile = File.createTempFile("temp", "jpg");
- } else if (mMimeType == IMAGE_TYPE_PNG) {
- tempFile = File.createTempFile("temp", "png");
- }
+ tempFile = File.createTempFile("temp", "tmp");
Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
in = new FileInputStream(mSeekableFileDescriptor);
out = new FileOutputStream(tempFile);
- Streams.copy(in, out);
+ copy(in, out);
}
} catch (Exception e) {
throw new IOException("Failed to copy original file to temp file", e);
} finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(out);
+ closeQuietly(in);
+ closeQuietly(out);
}
in = null;
@@ -2118,6 +2130,8 @@
saveJpegAttributes(bufferedIn, bufferedOut);
} else if (mMimeType == IMAGE_TYPE_PNG) {
savePngAttributes(bufferedIn, bufferedOut);
+ } else if (mMimeType == IMAGE_TYPE_WEBP) {
+ saveWebpAttributes(bufferedIn, bufferedOut);
}
}
} catch (Exception e) {
@@ -2129,8 +2143,8 @@
}
throw new IOException("Failed to save new file", e);
} finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(out);
+ closeQuietly(in);
+ closeQuietly(out);
tempFile.delete();
}
@@ -2215,7 +2229,7 @@
// Couldn't get a thumbnail image.
Log.d(TAG, "Encountered exception while getting thumbnail", e);
} finally {
- IoUtils.closeQuietly(in);
+ closeQuietly(in);
}
return null;
}
@@ -2536,7 +2550,7 @@
}
loadAttributes(in);
} finally {
- IoUtils.closeQuietly(in);
+ closeQuietly(in);
}
}
@@ -2599,7 +2613,6 @@
ByteOrderedDataInputStream signatureInputStream = null;
try {
signatureInputStream = new ByteOrderedDataInputStream(signatureCheckBytes);
- signatureInputStream.setByteOrder(ByteOrder.BIG_ENDIAN);
long chunkSize = signatureInputStream.readInt();
byte[] chunkType = new byte[4];
@@ -2839,14 +2852,14 @@
bytesRead += length;
length = 0;
- if (ArrayUtils.startsWith(bytes, IDENTIFIER_EXIF_APP1)) {
+ if (startsWith(bytes, IDENTIFIER_EXIF_APP1)) {
final long offset = start + IDENTIFIER_EXIF_APP1.length;
final byte[] value = Arrays.copyOfRange(bytes,
IDENTIFIER_EXIF_APP1.length, bytes.length);
// Save offset values for handleThumbnailFromJfif() function
mExifOffset = (int) offset;
readExifSegment(value, imageType);
- } else if (ArrayUtils.startsWith(bytes, IDENTIFIER_XMP_APP1)) {
+ } else if (startsWith(bytes, IDENTIFIER_XMP_APP1)) {
// See XMP Specification Part 3: Storage in Files, 1.1.3 JPEG, Table 6
final long offset = start + IDENTIFIER_XMP_APP1.length;
final byte[] value = Arrays.copyOfRange(bytes,
@@ -3390,6 +3403,9 @@
bytesRead += in.skipBytes(WEBP_SIGNATURE_2.length);
try {
while (true) {
+ // TODO: Check the first Chunk Type, and if it is VP8X, check if the chunks are
+ // ordered properly.
+
// Each chunk is made up of three parts:
// 1) Chunk FourCC: 4-byte concatenating four ASCII characters.
// 2) Chunk Size: 4-byte unsigned integer indicating the size of the chunk.
@@ -3415,6 +3431,9 @@
// Save offset values for handling thumbnail and attribute offsets.
mExifOffset = bytesRead;
readExifSegment(payload, IFD_TYPE_PRIMARY);
+
+ // Save offset values for handleThumbnailFromJfif() function
+ mExifOffset = bytesRead;
break;
} else {
// Add a single padding byte at end if chunk size is odd
@@ -3527,7 +3546,7 @@
dataOutputStream.writeByte(MARKER);
dataOutputStream.writeByte(marker);
// Copy all the remaining data
- Streams.copy(dataInputStream, dataOutputStream);
+ copy(dataInputStream, dataOutputStream);
return;
}
default: {
@@ -3605,7 +3624,264 @@
dataOutputStream.writeInt((int) crc.getValue());
}
// Copy the rest of the file
- Streams.copy(dataInputStream, dataOutputStream);
+ copy(dataInputStream, dataOutputStream);
+ }
+
+ // A WebP file has a header and a series of chunks.
+ // The header is composed of:
+ // "RIFF" + File Size + "WEBP"
+ //
+ // The structure of the chunks can be divided largely into two categories:
+ // 1) Contains only image data,
+ // 2) Contains image data and extra data.
+ // In the first category, there is only one chunk: type "VP8" (compression with loss) or "VP8L"
+ // (lossless compression).
+ // In the second category, the first chunk will be of type "VP8X", which contains flags
+ // indicating which extra data exist in later chunks. The proceeding chunks must conform to
+ // the following order based on type (if they exist):
+ // Color Profile ("ICCP") + Animation Control Data ("ANIM") + Image Data ("VP8"/"VP8L")
+ // + Exif metadata ("EXIF") + XMP metadata ("XMP")
+ //
+ // And in order to have EXIF data, a WebP file must be of the second structure and thus follow
+ // the following rules:
+ // 1) "VP8X" chunk as the first chunk,
+ // 2) flag for EXIF inside "VP8X" chunk set to 1, and
+ // 3) contain the "EXIF" chunk in the correct order amongst other chunks.
+ //
+ // Based on these rules, this API will support three different cases depending on the contents
+ // of the original file:
+ // 1) "EXIF" chunk already exists
+ // -> replace it with the new "EXIF" chunk
+ // 2) "EXIF" chunk does not exist and the first chunk is "VP8" or "VP8L"
+ // -> add "VP8X" before the "VP8"/"VP8L" chunk (with EXIF flag set to 1), and add new
+ // "EXIF" chunk after the "VP8"/"VP8L" chunk.
+ // 3) "EXIF" chunk does not exist and the first chunk is "VP8X"
+ // -> set EXIF flag in "VP8X" chunk to 1, and add new "EXIF" chunk at the proper location.
+ //
+ // See https://developers.google.com/speed/webp/docs/riff_container for more details.
+ private void saveWebpAttributes(InputStream inputStream, OutputStream outputStream)
+ throws IOException {
+ if (DEBUG) {
+ Log.d(TAG, "saveWebpAttributes starting with (inputStream: " + inputStream
+ + ", outputStream: " + outputStream + ")");
+ }
+ ByteOrderedDataInputStream totalInputStream =
+ new ByteOrderedDataInputStream(inputStream, ByteOrder.LITTLE_ENDIAN);
+ ByteOrderedDataOutputStream totalOutputStream =
+ new ByteOrderedDataOutputStream(outputStream, ByteOrder.LITTLE_ENDIAN);
+
+ // WebP signature
+ copy(totalInputStream, totalOutputStream, WEBP_SIGNATURE_1.length);
+ // File length will be written after all the chunks have been written
+ totalInputStream.skipBytes(WEBP_FILE_SIZE_BYTE_LENGTH + WEBP_SIGNATURE_2.length);
+
+ // Create a separate byte array to calculate file length
+ ByteArrayOutputStream nonHeaderByteArrayOutputStream = null;
+ try {
+ nonHeaderByteArrayOutputStream = new ByteArrayOutputStream();
+ ByteOrderedDataOutputStream nonHeaderOutputStream =
+ new ByteOrderedDataOutputStream(nonHeaderByteArrayOutputStream,
+ ByteOrder.LITTLE_ENDIAN);
+
+ if (mExifOffset != 0) {
+ // EXIF chunk exists in the original file
+ // Tested by webp_with_exif.webp
+ int bytesRead = WEBP_SIGNATURE_1.length + WEBP_FILE_SIZE_BYTE_LENGTH
+ + WEBP_SIGNATURE_2.length;
+ copy(totalInputStream, nonHeaderOutputStream,
+ mExifOffset - bytesRead - WEBP_CHUNK_TYPE_BYTE_LENGTH
+ - WEBP_CHUNK_SIZE_BYTE_LENGTH);
+
+ // Skip input stream to the end of the EXIF chunk
+ totalInputStream.skipBytes(WEBP_CHUNK_TYPE_BYTE_LENGTH);
+ int exifChunkLength = totalInputStream.readInt();
+ totalInputStream.skipBytes(exifChunkLength);
+
+ // Write new EXIF chunk to output stream
+ int exifSize = writeExifSegment(nonHeaderOutputStream);
+ } else {
+ // EXIF chunk does not exist in the original file
+ byte[] firstChunkType = new byte[WEBP_CHUNK_TYPE_BYTE_LENGTH];
+ if (totalInputStream.read(firstChunkType) != firstChunkType.length) {
+ throw new IOException("Encountered invalid length while parsing WebP chunk "
+ + "type");
+ }
+
+ if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8X)) {
+ // Original file already includes other extra data
+ int size = totalInputStream.readInt();
+ // WebP files have a single padding byte at the end if the chunk size is odd.
+ byte[] data = new byte[(size % 2) == 1 ? size + 1 : size];
+ totalInputStream.read(data);
+
+ // Set the EXIF flag to 1
+ data[0] = (byte) (data[0] | (1 << 3));
+
+ // Retrieve Animation flag--in order to check where EXIF data should start
+ boolean containsAnimation = ((data[0] >> 1) & 1) == 1;
+
+ // Write the original VP8X chunk
+ nonHeaderOutputStream.write(WEBP_CHUNK_TYPE_VP8X);
+ nonHeaderOutputStream.writeInt(size);
+ nonHeaderOutputStream.write(data);
+
+ // Animation control data is composed of 1 ANIM chunk and multiple ANMF
+ // chunks and since the image data (VP8/VP8L) chunks are included in the ANMF
+ // chunks, EXIF data should come after the last ANMF chunk.
+ // Also, because there is no value indicating the amount of ANMF chunks, we need
+ // to keep iterating through chunks until we either reach the end of the file or
+ // the XMP chunk (if it exists).
+ // Tested by webp_with_anim_without_exif.webp
+ if (containsAnimation) {
+ copyChunksUpToGivenChunkType(totalInputStream, nonHeaderOutputStream,
+ WEBP_CHUNK_TYPE_ANIM, null);
+
+ while (true) {
+ byte[] type = new byte[WEBP_CHUNK_TYPE_BYTE_LENGTH];
+ int read = inputStream.read(type);
+ if (!Arrays.equals(type, WEBP_CHUNK_TYPE_ANMF)) {
+ // Either we have reached EOF or the start of a non-ANMF chunk
+ writeExifSegment(nonHeaderOutputStream);
+ break;
+ }
+ copyWebPChunk(totalInputStream, nonHeaderOutputStream, type);
+ }
+ } else {
+ // Skip until we find the VP8 or VP8L chunk
+ copyChunksUpToGivenChunkType(totalInputStream, nonHeaderOutputStream,
+ WEBP_CHUNK_TYPE_VP8, WEBP_CHUNK_TYPE_VP8L);
+ writeExifSegment(nonHeaderOutputStream);
+ }
+ } else if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8)
+ || Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8L)) {
+ int size = totalInputStream.readInt();
+ int bytesToRead = size;
+ // WebP files have a single padding byte at the end if the chunk size is odd.
+ if (size % 2 == 1) {
+ bytesToRead += 1;
+ }
+
+ // Retrieve image width/height
+ int widthAndHeight = 0;
+ int width = 0;
+ int height = 0;
+ int alpha = 0;
+ // Save VP8 frame data for later
+ byte[] vp8Frame = new byte[3];
+
+ if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8)) {
+ totalInputStream.read(vp8Frame);
+
+ // Check signature
+ byte[] vp8Signature = new byte[3];
+ if (totalInputStream.read(vp8Signature) != vp8Signature.length
+ || !Arrays.equals(WEBP_VP8_SIGNATURE, vp8Signature)) {
+ throw new IOException("Encountered error while checking VP8 "
+ + "signature");
+ }
+
+ // Retrieve image width/height
+ widthAndHeight = totalInputStream.readInt();
+ width = (widthAndHeight << 18) >> 18;
+ height = (widthAndHeight << 2) >> 18;
+ bytesToRead -= (vp8Frame.length + vp8Signature.length + 4);
+ } else if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8L)) {
+ // Check signature
+ byte vp8lSignature = totalInputStream.readByte();
+ if (vp8lSignature != WEBP_VP8L_SIGNATURE) {
+ throw new IOException("Encountered error while checking VP8L "
+ + "signature");
+ }
+
+ // Retrieve image width/height
+ widthAndHeight = totalInputStream.readInt();
+ // VP8L stores width - 1 and height - 1 values. See "2 RIFF Header" of
+ // "WebP Lossless Bitstream Specification"
+ width = ((widthAndHeight << 18) >> 18) + 1;
+ height = ((widthAndHeight << 4) >> 18) + 1;
+ // Retrieve alpha bit
+ alpha = widthAndHeight & (1 << 3);
+ bytesToRead -= (1 /* VP8L signature */ + 4);
+ }
+
+ // Create VP8X with Exif flag set to 1
+ nonHeaderOutputStream.write(WEBP_CHUNK_TYPE_VP8X);
+ nonHeaderOutputStream.writeInt(WEBP_CHUNK_TYPE_VP8X_DEFAULT_LENGTH);
+ byte[] data = new byte[WEBP_CHUNK_TYPE_VP8X_DEFAULT_LENGTH];
+ // EXIF flag
+ data[0] = (byte) (data[0] | (1 << 3));
+ // ALPHA flag
+ data[0] = (byte) (data[0] | (alpha << 4));
+ // VP8X stores Width - 1 and Height - 1 values
+ width -= 1;
+ height -= 1;
+ data[4] = (byte) width;
+ data[5] = (byte) (width >> 8);
+ data[6] = (byte) (width >> 16);
+ data[7] = (byte) height;
+ data[8] = (byte) (height >> 8);
+ data[9] = (byte) (height >> 16);
+ nonHeaderOutputStream.write(data);
+
+ // Write VP8 or VP8L data
+ nonHeaderOutputStream.write(firstChunkType);
+ nonHeaderOutputStream.writeInt(size);
+ if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8)) {
+ nonHeaderOutputStream.write(vp8Frame);
+ nonHeaderOutputStream.write(WEBP_VP8_SIGNATURE);
+ nonHeaderOutputStream.writeInt(widthAndHeight);
+ } else if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8L)) {
+ nonHeaderOutputStream.write(WEBP_VP8L_SIGNATURE);
+ nonHeaderOutputStream.writeInt(widthAndHeight);
+ }
+ copy(totalInputStream, nonHeaderOutputStream, bytesToRead);
+
+ // Write EXIF chunk
+ writeExifSegment(nonHeaderOutputStream);
+ }
+ }
+
+ // Copy the rest of the file
+ copy(totalInputStream, nonHeaderOutputStream);
+
+ // Write file length + second signature
+ totalOutputStream.writeInt(nonHeaderByteArrayOutputStream.size()
+ + WEBP_SIGNATURE_2.length);
+ totalOutputStream.write(WEBP_SIGNATURE_2);
+ nonHeaderByteArrayOutputStream.writeTo(totalOutputStream);
+ } catch (Exception e) {
+ throw new IOException("Failed to save WebP file", e);
+ } finally {
+ closeQuietly(nonHeaderByteArrayOutputStream);
+ }
+ }
+
+ private void copyChunksUpToGivenChunkType(ByteOrderedDataInputStream inputStream,
+ ByteOrderedDataOutputStream outputStream, byte[] firstGivenType,
+ byte[] secondGivenType) throws IOException {
+ while (true) {
+ byte[] type = new byte[WEBP_CHUNK_TYPE_BYTE_LENGTH];
+ if (inputStream.read(type) != type.length) {
+ throw new IOException("Encountered invalid length while copying WebP chunks up to"
+ + "chunk type " + new String(firstGivenType, ASCII)
+ + ((secondGivenType == null) ? "" : " or " + new String(secondGivenType,
+ ASCII)));
+ }
+ copyWebPChunk(inputStream, outputStream, type);
+ if (Arrays.equals(type, firstGivenType)
+ || (secondGivenType != null && Arrays.equals(type, secondGivenType))) {
+ break;
+ }
+ }
+ }
+
+ private void copyWebPChunk(ByteOrderedDataInputStream inputStream,
+ ByteOrderedDataOutputStream outputStream, byte[] type) throws IOException {
+ int size = inputStream.readInt();
+ outputStream.write(type);
+ outputStream.writeInt(size);
+ // WebP files have a single padding byte at the end if the chunk size is odd.
+ copy(inputStream, outputStream, (size % 2) == 1 ? size + 1 : size);
}
// Reads the given EXIF byte area and save its tag data into attributes.
@@ -4358,14 +4634,22 @@
ifdOffsets[IFD_TYPE_INTEROPERABILITY], mExifByteOrder));
}
- if (mMimeType == IMAGE_TYPE_JPEG) {
- // Write JPEG specific data (APP1 size, APP1 identifier)
- dataOutputStream.writeUnsignedShort(totalSize);
- dataOutputStream.write(IDENTIFIER_EXIF_APP1);
- } else if (mMimeType == IMAGE_TYPE_PNG) {
- // Write PNG specific data (chunk size, chunk type)
- dataOutputStream.writeInt(totalSize);
- dataOutputStream.write(PNG_CHUNK_TYPE_EXIF);
+ switch (mMimeType) {
+ case IMAGE_TYPE_JPEG:
+ // Write JPEG specific data (APP1 size, APP1 identifier)
+ dataOutputStream.writeUnsignedShort(totalSize);
+ dataOutputStream.write(IDENTIFIER_EXIF_APP1);
+ break;
+ case IMAGE_TYPE_PNG:
+ // Write PNG specific data (chunk size, chunk type)
+ dataOutputStream.writeInt(totalSize);
+ dataOutputStream.write(PNG_CHUNK_TYPE_EXIF);
+ break;
+ case IMAGE_TYPE_WEBP:
+ // Write WebP specific data (chunk type, chunk size)
+ dataOutputStream.write(WEBP_CHUNK_TYPE_EXIF);
+ dataOutputStream.writeInt(totalSize);
+ break;
}
// Write TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1.
@@ -4434,6 +4718,11 @@
dataOutputStream.write(getThumbnailBytes());
}
+ // For WebP files, add a single padding byte at end if chunk size is odd
+ if (mMimeType == IMAGE_TYPE_WEBP && totalSize % 2 == 1) {
+ dataOutputStream.writeByte(0);
+ }
+
// Reset the byte order to big endian in order to write remaining parts of the JPEG file.
dataOutputStream.setByteOrder(ByteOrder.BIG_ENDIAN);
@@ -4535,12 +4824,17 @@
private int mPosition;
public ByteOrderedDataInputStream(InputStream in) throws IOException {
+ this(in, ByteOrder.BIG_ENDIAN);
+ }
+
+ ByteOrderedDataInputStream(InputStream in, ByteOrder byteOrder) throws IOException {
mInputStream = in;
mDataInputStream = new DataInputStream(in);
mLength = mDataInputStream.available();
mPosition = 0;
// TODO (b/142218289): Need to handle case where input stream does not support mark
mDataInputStream.mark(mLength);
+ mByteOrder = byteOrder;
}
public ByteOrderedDataInputStream(byte[] bytes) throws IOException {
@@ -4866,63 +5160,11 @@
}
}
- // Checks if there is a match
- private boolean containsMatch(byte[] mainBytes, byte[] findBytes) {
- for (int i = 0; i < mainBytes.length - findBytes.length; i++) {
- for (int j = 0; j < findBytes.length; j++) {
- if (mainBytes[i + j] != findBytes[j]) {
- break;
- }
- if (j == findBytes.length - 1) {
- return true;
- }
- }
+ private boolean isSupportedFormatForSavingAttributes() {
+ if (mIsSupportedFile && (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_PNG
+ || mMimeType == IMAGE_TYPE_WEBP)) {
+ return true;
}
return false;
}
-
- /**
- * Copies the given number of the bytes from {@code in} to {@code out}. Neither stream is
- * closed.
- */
- private static void copy(InputStream in, OutputStream out, int numBytes) throws IOException {
- int remainder = numBytes;
- byte[] buffer = new byte[8192];
- while (remainder > 0) {
- int bytesToRead = Math.min(remainder, 8192);
- int bytesRead = in.read(buffer, 0, bytesToRead);
- if (bytesRead != bytesToRead) {
- throw new IOException("Failed to copy the given amount of bytes from the input"
- + "stream to the output stream.");
- }
- remainder -= bytesRead;
- out.write(buffer, 0, bytesRead);
- }
- }
-
- /**
- * Convert given int[] to long[]. If long[] is given, just return it.
- * Return null for other types of input.
- */
- private static long[] convertToLongArray(Object inputObj) {
- if (inputObj instanceof int[]) {
- int[] input = (int[]) inputObj;
- long[] result = new long[input.length];
- for (int i = 0; i < input.length; i++) {
- result[i] = input[i];
- }
- return result;
- } else if (inputObj instanceof long[]) {
- return (long[]) inputObj;
- }
- return null;
- }
-
- private static String byteArrayToHexString(byte[] bytes) {
- StringBuilder sb = new StringBuilder(bytes.length * 2);
- for (int i = 0; i < bytes.length; i++) {
- sb.append(String.format("%02x", bytes[i]));
- }
- return sb.toString();
- }
}
diff --git a/media/java/android/media/ExifInterfaceUtils.java b/media/java/android/media/ExifInterfaceUtils.java
new file mode 100644
index 0000000..6ff706e
--- /dev/null
+++ b/media/java/android/media/ExifInterfaceUtils.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Package private utility class for ExifInterface.
+ */
+class ExifInterfaceUtils {
+ /**
+ * Copies all of the bytes from {@code in} to {@code out}. Neither stream is closed.
+ * Returns the total number of bytes transferred.
+ */
+ public static int copy(InputStream in, OutputStream out) throws IOException {
+ int total = 0;
+ byte[] buffer = new byte[8192];
+ int c;
+ while ((c = in.read(buffer)) != -1) {
+ total += c;
+ out.write(buffer, 0, c);
+ }
+ return total;
+ }
+
+ /**
+ * Copies the given number of the bytes from {@code in} to {@code out}. Neither stream is
+ * closed.
+ */
+ public static void copy(InputStream in, OutputStream out, int numBytes) throws IOException {
+ int remainder = numBytes;
+ byte[] buffer = new byte[8192];
+ while (remainder > 0) {
+ int bytesToRead = Math.min(remainder, 8192);
+ int bytesRead = in.read(buffer, 0, bytesToRead);
+ if (bytesRead != bytesToRead) {
+ throw new IOException("Failed to copy the given amount of bytes from the input"
+ + "stream to the output stream.");
+ }
+ remainder -= bytesRead;
+ out.write(buffer, 0, bytesRead);
+ }
+ }
+
+ /**
+ * Convert given int[] to long[]. If long[] is given, just return it.
+ * Return null for other types of input.
+ */
+ public static long[] convertToLongArray(Object inputObj) {
+ if (inputObj instanceof int[]) {
+ int[] input = (int[]) inputObj;
+ long[] result = new long[input.length];
+ for (int i = 0; i < input.length; i++) {
+ result[i] = input[i];
+ }
+ return result;
+ } else if (inputObj instanceof long[]) {
+ return (long[]) inputObj;
+ }
+ return null;
+ }
+
+ /**
+ * Convert given byte array to hex string.
+ */
+ public static String byteArrayToHexString(byte[] bytes) {
+ StringBuilder sb = new StringBuilder(bytes.length * 2);
+ for (int i = 0; i < bytes.length; i++) {
+ sb.append(String.format("%02x", bytes[i]));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Checks if the start of the first byte array is equal to the second byte array.
+ */
+ public static boolean startsWith(byte[] cur, byte[] val) {
+ if (cur == null || val == null) return false;
+ if (cur.length < val.length) return false;
+ if (cur.length == 0 || val.length == 0) return false;
+ for (int i = 0; i < val.length; i++) {
+ if (cur[i] != val[i]) return false;
+ }
+ return true;
+ }
+
+ /**
+ * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null.
+ */
+ public static void closeQuietly(Closeable closeable) {
+ if (closeable != null) {
+ try {
+ closeable.close();
+ } catch (RuntimeException rethrown) {
+ throw rethrown;
+ } catch (Exception ignored) {
+ }
+ }
+ }
+}
diff --git a/non-updatable-api/Android.bp b/non-updatable-api/Android.bp
new file mode 100644
index 0000000..4037781
--- /dev/null
+++ b/non-updatable-api/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_visibility: ["//visibility:private"],
+}
+
+filegroup {
+ name: "non-updatable-current.txt",
+ srcs: ["current.txt"],
+ visibility: ["//frameworks/base/api"],
+}
+
+filegroup {
+ name: "non-updatable-system-current.txt",
+ srcs: ["system-current.txt"],
+ visibility: ["//frameworks/base/api"],
+}
+
+filegroup {
+ name: "non-updatable-module-lib-current.txt",
+ srcs: ["module-lib-current.txt"],
+ visibility: ["//frameworks/base/api"],
+}
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index b1373de..0aa0605 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -44138,6 +44138,8 @@
field public static final int MISSED = 5; // 0x5
field public static final int OTHER = 9; // 0x9
field public static final String REASON_EMERGENCY_CALL_PLACED = "REASON_EMERGENCY_CALL_PLACED";
+ field public static final String REASON_IMS_ACCESS_BLOCKED = "REASON_IMS_ACCESS_BLOCKED";
+ field public static final String REASON_WIFI_ON_BUT_WFC_OFF = "REASON_WIFI_ON_BUT_WFC_OFF";
field public static final int REJECTED = 6; // 0x6
field public static final int REMOTE = 3; // 0x3
field public static final int RESTRICTED = 8; // 0x8
@@ -44232,6 +44234,7 @@
field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
field public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 256; // 0x100
field @NonNull public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
+ field public static final String EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE = "android.telecom.extra.ALWAYS_USE_VOIP_AUDIO_MODE";
field public static final String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING";
field public static final String EXTRA_CALL_SUBJECT_MAX_LENGTH = "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH";
field public static final String EXTRA_LOG_SELF_MANAGED_CALLS = "android.telecom.extra.LOG_SELF_MANAGED_CALLS";
@@ -44798,6 +44801,7 @@
field public static final String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
field public static final String KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY = "apn_settings_default_apn_types_string_array";
field public static final String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
+ field public static final String KEY_CALL_BARRING_DEFAULT_SERVICE_CLASS_INT = "call_barring_default_service_class_int";
field public static final String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL = "call_barring_supports_deactivate_all_bool";
field public static final String KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL = "call_barring_supports_password_change_bool";
field public static final String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool";
@@ -45025,6 +45029,8 @@
field public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING = "wfc_emergency_address_carrier_app_string";
field public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool";
field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
+ field public static final int SERVICE_CLASS_NONE = 0; // 0x0
+ field public static final int SERVICE_CLASS_VOICE = 1; // 0x1
}
public static final class CarrierConfigManager.Apn {
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index 31b71fb5..6a6914a 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -1526,12 +1526,16 @@
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public void setBluetoothTethering(boolean);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
+ field public static final String ACTION_TETHERING_STATE_CHANGED = "android.bluetooth.action.TETHERING_STATE_CHANGED";
field public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
+ field public static final String EXTRA_TETHERING_STATE = "android.bluetooth.extra.TETHERING_STATE";
field public static final int LOCAL_NAP_ROLE = 1; // 0x1
field public static final int LOCAL_PANU_ROLE = 2; // 0x2
field public static final int PAN_ROLE_NONE = 0; // 0x0
field public static final int REMOTE_NAP_ROLE = 1; // 0x1
field public static final int REMOTE_PANU_ROLE = 2; // 0x2
+ field public static final int TETHERING_STATE_OFF = 1; // 0x1
+ field public static final int TETHERING_STATE_ON = 2; // 0x2
}
public class BluetoothPbap implements android.bluetooth.BluetoothProfile {
@@ -8121,6 +8125,7 @@
field public static final String APN_SET_ID = "apn_set_id";
field public static final int CARRIER_EDITED = 4; // 0x4
field public static final String EDITED_STATUS = "edited";
+ field public static final int MATCH_ALL_APN_SET_ID = -1; // 0xffffffff
field public static final String MAX_CONNECTIONS = "max_conns";
field public static final String MODEM_PERSIST = "modem_cognitive";
field public static final String MTU = "mtu";
@@ -9131,6 +9136,10 @@
method public final void addExistingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.Connection, @NonNull android.telecom.Conference);
}
+ public final class DisconnectCause implements android.os.Parcelable {
+ field public static final String REASON_EMULATING_SINGLE_CALL = "EMULATING_SINGLE_CALL";
+ }
+
public abstract class InCallService extends android.app.Service {
method @Deprecated public android.telecom.Phone getPhone();
method @Deprecated public void onPhoneCreated(android.telecom.Phone);
@@ -9259,7 +9268,12 @@
}
public final class PhoneAccount implements android.os.Parcelable {
+ field public static final int CAPABILITY_EMERGENCY_CALLS_ONLY = 128; // 0x80
+ field public static final int CAPABILITY_EMERGENCY_PREFERRED = 8192; // 0x2000
+ field public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 512; // 0x200
field public static final int CAPABILITY_MULTI_USER = 32; // 0x20
+ field public static final String EXTRA_PLAY_CALL_RECORDING_TONE = "android.telecom.extra.PLAY_CALL_RECORDING_TONE";
+ field public static final String EXTRA_SORT_ORDER = "android.telecom.extra.SORT_ORDER";
}
public static class PhoneAccount.Builder {
@@ -9345,10 +9359,20 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(@Nullable android.telecom.PhoneAccountHandle);
+ field public static final String ACTION_CURRENT_TTY_MODE_CHANGED = "android.telecom.action.CURRENT_TTY_MODE_CHANGED";
+ field public static final String ACTION_TTY_PREFERRED_MODE_CHANGED = "android.telecom.action.TTY_PREFERRED_MODE_CHANGED";
+ field public static final int CALL_SOURCE_EMERGENCY_DIALPAD = 1; // 0x1
+ field public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2; // 0x2
+ field public static final int CALL_SOURCE_UNSPECIFIED = 0; // 0x0
field public static final String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT";
+ field public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE";
+ field public static final String EXTRA_CALL_TECHNOLOGY_TYPE = "android.telecom.extra.CALL_TECHNOLOGY_TYPE";
field public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT";
field public static final String EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE";
+ field public static final String EXTRA_CURRENT_TTY_MODE = "android.telecom.extra.CURRENT_TTY_MODE";
field public static final String EXTRA_IS_USER_INTENT_EMERGENCY_CALL = "android.telecom.extra.IS_USER_INTENT_EMERGENCY_CALL";
+ field public static final String EXTRA_TTY_PREFERRED_MODE = "android.telecom.extra.TTY_PREFERRED_MODE";
+ field public static final String EXTRA_UNKNOWN_CALL_HANDLE = "android.telecom.extra.UNKNOWN_CALL_HANDLE";
field public static final int TTY_MODE_FULL = 1; // 0x1
field public static final int TTY_MODE_HCO = 2; // 0x2
field public static final int TTY_MODE_OFF = 0; // 0x0
diff --git a/packages/InputDevices/res/raw/keyboard_layout_czech_qwerty.kcm b/packages/InputDevices/res/raw/keyboard_layout_czech_qwerty.kcm
new file mode 100644
index 0000000..dc614db
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_czech_qwerty.kcm
@@ -0,0 +1,365 @@
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Czech (EU - qwerty) keyboard layout.
+#
+
+type OVERLAY
+
+map key 86 PLUS
+
+### ROW 1
+
+key GRAVE {
+ label: ';'
+ base: ';'
+ shift: '\u00b0'
+ ralt: '\u0060'
+ shift+ralt: '\u007e'
+}
+
+key 1 {
+ label: '1'
+ base: '+'
+ shift: '1'
+ ralt: '!'
+}
+
+key 2 {
+ label: '2'
+ base: '\u011b'
+ capslock: '\u011a'
+ shift: '2'
+ ralt: '@'
+}
+
+key 3 {
+ label: '3'
+ base: '\u0161'
+ capslock: '\u0160'
+ shift: '3'
+ ralt: '#'
+}
+
+key 4 {
+ label: '4'
+ base: '\u010d'
+ capslock: '\u010c'
+ shift: '4'
+ ralt: '$'
+}
+
+key 5 {
+ label: '5'
+ base: '\u0159'
+ capslock: '\u0158'
+ shift: '5'
+ ralt: '%'
+}
+
+key 6 {
+ label: '6'
+ base: '\u017e'
+ capslock: '\u017d'
+ shift: '6'
+ ralt: '^'
+}
+
+key 7 {
+ label: '7'
+ base: '\u00fd'
+ capslock: '\u00dd'
+ shift: '7'
+ ralt: '&'
+}
+
+key 8 {
+ label: '8'
+ base: '\u00e1'
+ capslock: '\u00c1'
+ shift: '8'
+ ralt: '*'
+}
+
+key 9 {
+ label: '9'
+ base: '\u00ed'
+ capslock: '\u00cd'
+ shift: '9'
+ ralt: '('
+}
+
+key 0 {
+ label: '0'
+ base: '\u00e9'
+ capslock: '\u00c9'
+ shift: '0'
+ ralt: ')'
+}
+
+key MINUS {
+ label: '='
+ base: '='
+ shift: '%'
+ ralt: '-'
+ ralt+shift: '_'
+}
+
+key EQUALS {
+ label: '\u00b4'
+ base: '\u0301'
+ shift: '\u030c'
+ ralt: '='
+ ralt+shift: '+'
+}
+
+### ROW 2
+
+key Q {
+ label: 'Q'
+ base: 'q'
+ shift, capslock: 'Q'
+}
+
+key W {
+ label: 'W'
+ base: 'w'
+ shift, capslock: 'W'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+ ralt: '\u20ac'
+}
+
+key R {
+ label: 'R'
+ base: 'r'
+ shift, capslock: 'R'
+}
+
+key T {
+ label: 'T'
+ base: 't'
+ shift, capslock: 'T'
+}
+
+key Y {
+ label: 'Y'
+ base: 'y'
+ shift, capslock: 'Y'
+}
+
+key U {
+ label: 'U'
+ base: 'u'
+ shift, capslock: 'U'
+}
+
+key I {
+ label: 'I'
+ base: 'i'
+ shift, capslock: 'I'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '\u00fa'
+ base: '\u00fa'
+ capslock: '\u00da'
+ shift: '/'
+ ralt: '['
+ ralt+shift: '{'
+}
+
+key RIGHT_BRACKET {
+ label: ')'
+ base: ')'
+ shift: '('
+ ralt: ']'
+ ralt+shift: '}'
+}
+
+### ROW 3
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+}
+
+key D {
+ label: 'D'
+ base: 'd'
+ shift, capslock: 'D'
+}
+
+key F {
+ label: 'F'
+ base: 'f'
+ shift, capslock: 'F'
+}
+
+key G {
+ label: 'G'
+ base: 'g'
+ shift, capslock: 'G'
+}
+
+key H {
+ label: 'H'
+ base: 'h'
+ shift, capslock: 'H'
+}
+
+key J {
+ label: 'J'
+ base: 'j'
+ shift, capslock: 'J'
+}
+
+key K {
+ label: 'K'
+ base: 'k'
+ shift, capslock: 'K'
+}
+
+key L {
+ label: 'L'
+ base: 'l'
+ shift, capslock: 'L'
+}
+
+key SEMICOLON {
+ label: '\u016f'
+ base: '\u016f'
+ capslock: '\u016e'
+ shift: '"'
+ ralt: ';'
+ ralt+shift: ':'
+}
+
+key APOSTROPHE {
+ label: '\u00a7'
+ base: '\u00a7'
+ shift: '!'
+ ralt: '\u00a4'
+ ralt+shift: '\u005e'
+}
+
+key BACKSLASH {
+ label: '\u0308'
+ base: '\u0308'
+ shift: '\''
+ ralt: '\\'
+ ralt+shift: '|'
+}
+
+### ROW 4
+
+key PLUS {
+ label: '\\'
+ base: '\\'
+ shift: '|'
+ ralt: '\u00df'
+ shift+ralt: '\u02dd'
+}
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+}
+
+key V {
+ label: 'V'
+ base: 'v'
+ shift, capslock: 'V'
+ ralt: '@'
+}
+
+key B {
+ label: 'B'
+ base: 'b'
+ shift, capslock: 'B'
+}
+
+key N {
+ label: 'N'
+ base: 'n'
+ shift, capslock: 'N'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+ ralt: '\u00b5'
+}
+
+key COMMA {
+ label: ','
+ base: ','
+ shift: '?'
+ ralt: '<'
+ shift+ralt: '\u00d7'
+}
+
+key PERIOD {
+ label: '.'
+ base: '.'
+ shift: ':'
+ ralt: '>'
+ shift+ralt: '\u00f7'
+}
+
+key SLASH {
+ label: '-'
+ base: '-'
+ shift: '_'
+ ralt: '/'
+ ralt+shift: '?'
+}
diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml
index 9878146..e95a159 100644
--- a/packages/InputDevices/res/values/strings.xml
+++ b/packages/InputDevices/res/values/strings.xml
@@ -75,6 +75,9 @@
<!-- Czech keyboard layout label. [CHAR LIMIT=35] -->
<string name="keyboard_layout_czech">Czech</string>
+ <!-- Czech qwerty keyboard layout label. [CHAR LIMIT=35] -->
+ <string name="keyboard_layout_czech_qwerty">Czech QWERTY style</string>
+
<!-- Estonian keyboard layout label. [CHAR LIMIT=35] -->
<string name="keyboard_layout_estonian">Estonian</string>
diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml
index 0d7a13b..aa599ae 100644
--- a/packages/InputDevices/res/xml/keyboard_layouts.xml
+++ b/packages/InputDevices/res/xml/keyboard_layouts.xml
@@ -92,6 +92,10 @@
android:label="@string/keyboard_layout_czech"
android:keyboardLayout="@raw/keyboard_layout_czech" />
+ <keyboard-layout android:name="keyboard_layout_czech_qwerty"
+ android:label="@string/keyboard_layout_czech_qwerty"
+ android:keyboardLayout="@raw/keyboard_layout_czech_qwerty" />
+
<keyboard-layout android:name="keyboard_layout_estonian"
android:label="@string/keyboard_layout_estonian"
android:keyboardLayout="@raw/keyboard_layout_estonian" />
diff --git a/packages/PackageInstaller/res/values-es/strings.xml b/packages/PackageInstaller/res/values-es/strings.xml
index fa73873..1049c3c 100644
--- a/packages/PackageInstaller/res/values-es/strings.xml
+++ b/packages/PackageInstaller/res/values-es/strings.xml
@@ -56,8 +56,8 @@
<string name="uninstall_application_text" msgid="3816830743706143980">"¿Quieres desinstalar esta aplicación?"</string>
<string name="uninstall_application_text_all_users" msgid="575491774380227119">"¿Quieres desinstalar esta aplicación para "<b>"todos"</b>" los usuarios? La aplicación y sus datos se borrarán de "<b>"todos"</b>" los usuarios del dispositivo."</string>
<string name="uninstall_application_text_user" msgid="498072714173920526">"¿Quieres desinstalar esta aplicación para el usuario <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
- <string name="uninstall_update_text" msgid="863648314632448705">"¿Quieres reemplazar esta aplicación con la versión de fábrica? Ten en cuenta que se borrarán todos los datos."</string>
- <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"¿Quieres reemplazar esta aplicación con la versión de fábrica? Ten en cuenta que se borrarán todos los datos. Esto afecta a todos los usuarios del dispositivo, incluidos los que tienen perfiles de trabajo."</string>
+ <string name="uninstall_update_text" msgid="863648314632448705">"¿Quieres sustituir esta aplicación con la versión de fábrica? Ten en cuenta que se borrarán todos los datos."</string>
+ <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"¿Quieres sustituir esta aplicación con la versión de fábrica? Ten en cuenta que se borrarán todos los datos. Esto afecta a todos los usuarios del dispositivo, incluidos los que tienen perfiles de trabajo."</string>
<string name="uninstall_keep_data" msgid="7002379587465487550">"Mantener <xliff:g id="SIZE">%1$s</xliff:g> de datos de aplicaciones."</string>
<string name="uninstalling_notification_channel" msgid="840153394325714653">"Desinstalaciones en curso"</string>
<string name="uninstall_failure_notification_channel" msgid="1136405866767576588">"Desinstalaciones fallidas"</string>
diff --git a/packages/PackageInstaller/res/values-ne/strings.xml b/packages/PackageInstaller/res/values-ne/strings.xml
index 495a05b..60934b1 100644
--- a/packages/PackageInstaller/res/values-ne/strings.xml
+++ b/packages/PackageInstaller/res/values-ne/strings.xml
@@ -30,11 +30,11 @@
<string name="install_failed_blocked" msgid="8512284352994752094">"यो प्याकेज स्थापना गर्ने क्रममा अवरोध गरियो।"</string>
<string name="install_failed_conflict" msgid="3493184212162521426">"प्याकेजका रूपमा स्थापना नगरिएको एप विद्यमान प्याकेजसँग मेल खाँदैन।"</string>
<string name="install_failed_incompatible" product="tablet" msgid="6019021440094927928">"एपका रूपमा स्थापना नगरिएको एप तपाईंको ट्याब्लेटसँग मिल्दो छैन।"</string>
- <string name="install_failed_incompatible" product="tv" msgid="2890001324362291683">"यो एप तपाईंको टिभी सँग मिल्दो छैन।"</string>
+ <string name="install_failed_incompatible" product="tv" msgid="2890001324362291683">"यो एप तपाईंको TV सँग मिल्दो छैन।"</string>
<string name="install_failed_incompatible" product="default" msgid="7254630419511645826">"एपका रूपमा स्थापना नगरिएको एप तपाईंको फोनसँग मिल्दो छैन।"</string>
<string name="install_failed_invalid_apk" msgid="8581007676422623930">"प्याकेजका रूपमा स्थापना नगरिएको एप अमान्य जस्तो देखिन्छ।"</string>
<string name="install_failed_msg" product="tablet" msgid="6298387264270562442">"तपाईंको ट्याब्लेटमा <xliff:g id="APP_NAME">%1$s</xliff:g> स्थापना गर्न सकिएन।"</string>
- <string name="install_failed_msg" product="tv" msgid="1920009940048975221">"तपाईंको टिभी मा <xliff:g id="APP_NAME">%1$s</xliff:g> स्थापना गर्न सकिएन।"</string>
+ <string name="install_failed_msg" product="tv" msgid="1920009940048975221">"तपाईंको TV मा <xliff:g id="APP_NAME">%1$s</xliff:g> स्थापना गर्न सकिएन।"</string>
<string name="install_failed_msg" product="default" msgid="6484461562647915707">"तपाईंको फोनमा <xliff:g id="APP_NAME">%1$s</xliff:g> स्थापना गर्न सकिएन।"</string>
<string name="launch" msgid="3952550563999890101">"खोल्नुहोस्"</string>
<string name="unknown_apps_admin_dlg_text" msgid="4456572224020176095">"तपाईंका प्रशासकले अज्ञात स्रोतहरूबाट प्राप्त अनुप्रयोगहरूलाई स्थापना गर्ने अनुमति दिनुहुन्न"</string>
@@ -81,11 +81,11 @@
<string name="message_staging" msgid="8032722385658438567">"एप स्थापना गर्न तयारी गर्दै…"</string>
<string name="app_name_unknown" msgid="6881210203354323926">"अज्ञात"</string>
<string name="untrusted_external_source_warning" product="tablet" msgid="6539403649459942547">"तपाईंको सुरक्षाका लागि, तपाईंको ट्याब्लेटलाई यो स्रोतबाट प्राप्त हुने अज्ञात एपहरू स्थापना गर्ने अनुमति छैन।"</string>
- <string name="untrusted_external_source_warning" product="tv" msgid="1206648674551321364">"तपाईंको सुरक्षाका लागि, तपाईंको टिभी लाई यस स्रोतबाट प्राप्त हुने अज्ञात एपहरू स्थापना गर्ने अनुमति छैन।"</string>
+ <string name="untrusted_external_source_warning" product="tv" msgid="1206648674551321364">"तपाईंको सुरक्षाका लागि, तपाईंको TV लाई यस स्रोतबाट प्राप्त हुने अज्ञात एपहरू स्थापना गर्ने अनुमति छैन।"</string>
<string name="untrusted_external_source_warning" product="default" msgid="7279739265754475165">"तपाईंको सुरक्षाका लागि, तपाईंको फोनलाई यो स्रोतबाट प्राप्त हुने अज्ञात एपहरू स्थापना गर्ने अनुमति छैन।"</string>
<string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"तपाईंको फोन तथा व्यक्तिगत डेटा अज्ञात एपहरूबाट हुने आक्रमणको चपेटामा पर्ने बढी जोखिममा हुन्छन्। यो एप स्थापना गरेर तपाईं यसको प्रयोगबाट तपाईंको फोनमा हुन सक्ने क्षति वा डेटाको नोक्सानीका लागि स्वयं जिम्मेवार हुने कुरामा सहमत हुनुहुन्छ।"</string>
<string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"तपाईंको ट्याब्लेट तथा व्यक्तिगत डेटा अज्ञात एपहरूबाट हुने आक्रमणको चपेटामा पर्ने बढी जोखिममा हुन्छन्। यो एप स्थापना गरेर तपाईं यसको प्रयोगबाट तपाईंको ट्याब्लेटमा हुन सक्ने क्षति वा डेटाको नोक्सानीका लागि स्वयं जिम्मेवार हुने कुरामा सहमत हुनुहुन्छ।"</string>
- <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"तपाईंको टिभी तथा व्यक्तिगत डेटा अज्ञात एपहरूबाट हुने आक्रमणको चपेटामा पर्ने बढी जोखिममा हुन्छन्। यो एप स्थापना गरेर तपाईं यसको प्रयोगबाट तपाईंको टिभी मा हुन सक्ने क्षति वा डेटाको नोक्सानीका लागि स्वयं जिम्मेवार हुने कुरामा सहमत हुनुहुन्छ।"</string>
+ <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"तपाईंको TV तथा व्यक्तिगत डेटा अज्ञात एपहरूबाट हुने आक्रमणको चपेटामा पर्ने बढी जोखिममा हुन्छन्। यो एप स्थापना गरेर तपाईं यसको प्रयोगबाट तपाईंको TV मा हुन सक्ने क्षति वा डेटाको नोक्सानीका लागि स्वयं जिम्मेवार हुने कुरामा सहमत हुनुहुन्छ।"</string>
<string name="anonymous_source_continue" msgid="4375745439457209366">"जारी राख्नुहोस्"</string>
<string name="external_sources_settings" msgid="4046964413071713807">"सेटिङहरू"</string>
<string name="wear_app_channel" msgid="1960809674709107850">"वेयर एपहरूको स्थापना/स्थापना रद्द गर्दै"</string>
diff --git a/packages/PackageInstaller/res/values-or/strings.xml b/packages/PackageInstaller/res/values-or/strings.xml
index f3b97a9..b9908d2 100644
--- a/packages/PackageInstaller/res/values-or/strings.xml
+++ b/packages/PackageInstaller/res/values-or/strings.xml
@@ -19,7 +19,7 @@
<string name="app_name" msgid="7488448184431507488">"ପ୍ୟାକେଜ୍ ଇନଷ୍ଟଲର୍"</string>
<string name="install" msgid="711829760615509273">"ଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
<string name="done" msgid="6632441120016885253">"ହୋଇଗଲା"</string>
- <string name="cancel" msgid="1018267193425558088">"ବାତିଲ୍ କରନ୍ତୁ"</string>
+ <string name="cancel" msgid="1018267193425558088">"କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ"</string>
<string name="installing" msgid="4921993079741206516">"ଇନଷ୍ଟଲ୍ କରାଯାଉଛି…"</string>
<string name="installing_app" msgid="1165095864863849422">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> ଇନଷ୍ଟଲ୍ କରାଯାଉଛି…"</string>
<string name="install_done" msgid="5987363587661783896">"ଆପ୍ ଇନଷ୍ଟଲ୍ ହୋଇଗଲା।"</string>
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index a346cb2..98687b4 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4469836075319831821">"Gestor de cues d\'impressió"</string>
+ <string name="app_label" msgid="4469836075319831821">"Gest. cues impr."</string>
<string name="more_options_button" msgid="2243228396432556771">"Més opcions"</string>
<string name="label_destination" msgid="9132510997381599275">"Destinació"</string>
<string name="label_copies" msgid="3634531042822968308">"Còpies"</string>
diff --git a/packages/SettingsLib/HelpUtils/res/values-en-rAU/strings.xml b/packages/SettingsLib/HelpUtils/res/values-en-rAU/strings.xml
index 150020c..759da1d0 100644
--- a/packages/SettingsLib/HelpUtils/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/HelpUtils/res/values-en-rAU/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="help_feedback_label" msgid="7106780063063027882">"Help and feedback"</string>
+ <string name="help_feedback_label" msgid="7106780063063027882">"Help & feedback"</string>
</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-en-rCA/strings.xml b/packages/SettingsLib/HelpUtils/res/values-en-rCA/strings.xml
index 150020c..759da1d0 100644
--- a/packages/SettingsLib/HelpUtils/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/HelpUtils/res/values-en-rCA/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="help_feedback_label" msgid="7106780063063027882">"Help and feedback"</string>
+ <string name="help_feedback_label" msgid="7106780063063027882">"Help & feedback"</string>
</resources>
diff --git a/packages/SettingsLib/HelpUtils/res/values-en-rIN/strings.xml b/packages/SettingsLib/HelpUtils/res/values-en-rIN/strings.xml
index 150020c..759da1d0 100644
--- a/packages/SettingsLib/HelpUtils/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/HelpUtils/res/values-en-rIN/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="help_feedback_label" msgid="7106780063063027882">"Help and feedback"</string>
+ <string name="help_feedback_label" msgid="7106780063063027882">"Help & feedback"</string>
</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml
index 7f10edf..3a0bc2d 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-da/strings.xml
@@ -18,5 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="enabled_by_admin" msgid="6630472777476410137">"Aktiveret af administratoren"</string>
- <string name="disabled_by_admin" msgid="4023569940620832713">"Deaktiveret af administrator"</string>
+ <string name="disabled_by_admin" msgid="4023569940620832713">"Deaktiveret af administratoren"</string>
</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml
index 2a88124..aaf607f 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-eu/strings.xml
@@ -18,5 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="enabled_by_admin" msgid="6630472777476410137">"Administratzaileak gaitu egin du"</string>
- <string name="disabled_by_admin" msgid="4023569940620832713">"Administratzaileak desgaitu du"</string>
+ <string name="disabled_by_admin" msgid="4023569940620832713">"Administratzaileak desgaitu egin du"</string>
</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml
index 9c39f98..aaf9116 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-fa/strings.xml
@@ -17,6 +17,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="enabled_by_admin" msgid="6630472777476410137">"توسط سرپرست فعال شده"</string>
- <string name="disabled_by_admin" msgid="4023569940620832713">"توسط سرپرست غیرفعال شده"</string>
+ <string name="enabled_by_admin" msgid="6630472777476410137">"فعالشده توسط سرپرست"</string>
+ <string name="disabled_by_admin" msgid="4023569940620832713">"غیرفعالشده توسط سرپرست"</string>
</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml
index 4ce6460..1d23c31 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-or/strings.xml
@@ -18,5 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="enabled_by_admin" msgid="6630472777476410137">"ଆଡମିନଙ୍କ ଦ୍ୱାରା ସକ୍ଷମ କରାଯାଇଛି"</string>
- <string name="disabled_by_admin" msgid="4023569940620832713">"ଆଡମିନଙ୍କ ଦ୍ଵାରା ଅକ୍ଷମ କରାଯାଇଛି"</string>
+ <string name="disabled_by_admin" msgid="4023569940620832713">"ବ୍ୟବସ୍ଥାପକଙ୍କ ଦ୍ଵାରା ଅକ୍ଷମ କରାଯାଇଛି"</string>
</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml
index 908e2fb..e57d1cc 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-pt-rPT/strings.xml
@@ -18,5 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="enabled_by_admin" msgid="6630472777476410137">"Ativado pelo administrador"</string>
- <string name="disabled_by_admin" msgid="4023569940620832713">"Desativado pelo administrador"</string>
+ <string name="disabled_by_admin" msgid="4023569940620832713">"Desativada pelo administrador"</string>
</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml
index 8f17dc5..2da347c 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-te/strings.xml
@@ -17,6 +17,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="enabled_by_admin" msgid="6630472777476410137">"అడ్మిన్ ఎనేబుల్ చేశారు"</string>
- <string name="disabled_by_admin" msgid="4023569940620832713">"అడ్మిన్ డిజేబుల్ చేశారు"</string>
+ <string name="enabled_by_admin" msgid="6630472777476410137">"నిర్వాహకులు ప్రారంభించారు"</string>
+ <string name="disabled_by_admin" msgid="4023569940620832713">"నిర్వాహకులు నిలిపివేసారు"</string>
</resources>
diff --git a/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml b/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml
index 2c37652..f664bb4 100644
--- a/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/res/values-vi/strings.xml
@@ -18,5 +18,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="enabled_by_admin" msgid="6630472777476410137">"Do quản trị viên bật"</string>
- <string name="disabled_by_admin" msgid="4023569940620832713">"Đã bị quản trị viên vô hiệu hóa"</string>
+ <string name="disabled_by_admin" msgid="4023569940620832713">"Bị quản trị viên tắt"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-el/strings.xml b/packages/SettingsLib/SearchWidget/res/values-el/strings.xml
index d50436a..6f5ab78 100644
--- a/packages/SettingsLib/SearchWidget/res/values-el/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-el/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Αναζήτηση στις ρυθμίσεις"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Ρυθμίσεις αναζήτησης"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml b/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml
index 2c9aaa5..fa5f9bd 100644
--- a/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"تنظیمات جستجو"</string>
+ <string name="search_menu" msgid="1914043873178389845">"جستجوی تنظیمات"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-hr/strings.xml b/packages/SettingsLib/SearchWidget/res/values-hr/strings.xml
index 34cb8e0..9d83396 100644
--- a/packages/SettingsLib/SearchWidget/res/values-hr/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-hr/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Pretražite postavke"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Pretraži postavke"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-hy/strings.xml b/packages/SettingsLib/SearchWidget/res/values-hy/strings.xml
index b68b792..8fa5a84 100644
--- a/packages/SettingsLib/SearchWidget/res/values-hy/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-hy/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Որոնեք կարգավորումներ"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Որոնման կարգավորումներ"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-in/strings.xml b/packages/SettingsLib/SearchWidget/res/values-in/strings.xml
index ccf11d2..edf51cc 100644
--- a/packages/SettingsLib/SearchWidget/res/values-in/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-in/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Telusuri setelan"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Setelan penelusuran"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-is/strings.xml b/packages/SettingsLib/SearchWidget/res/values-is/strings.xml
index 3378c84..7ab103b 100644
--- a/packages/SettingsLib/SearchWidget/res/values-is/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-is/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Leita í stillingum"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Leitarstillingar"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-pt-rPT/strings.xml b/packages/SettingsLib/SearchWidget/res/values-pt-rPT/strings.xml
index 5fe116e..85a8d73 100644
--- a/packages/SettingsLib/SearchWidget/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-pt-rPT/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Pesquisar nas definições"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Pesquisa de definições"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-sq/strings.xml b/packages/SettingsLib/SearchWidget/res/values-sq/strings.xml
index 354941d..a531321 100644
--- a/packages/SettingsLib/SearchWidget/res/values-sq/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-sq/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Kërko te cilësimet"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Cilësimet e kërkimit"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-tl/strings.xml b/packages/SettingsLib/SearchWidget/res/values-tl/strings.xml
index 14b7b2f..111cf5a 100644
--- a/packages/SettingsLib/SearchWidget/res/values-tl/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-tl/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Maghanap sa mga setting"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Mga setting ng paghahanap"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-uk/strings.xml b/packages/SettingsLib/SearchWidget/res/values-uk/strings.xml
index 560ac13..dfd66b2 100644
--- a/packages/SettingsLib/SearchWidget/res/values-uk/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-uk/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Пошук налаштувань"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Налаштування пошуку"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml b/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml
index 90daf11..cb1a75a 100644
--- a/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Tìm trong thông tin cài đặt"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Tìm kiếm trong các mục cài đặt"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-bn/arrays.xml b/packages/SettingsLib/res/values-bn/arrays.xml
index b19cde4..a131a3b 100644
--- a/packages/SettingsLib/res/values-bn/arrays.xml
+++ b/packages/SettingsLib/res/values-bn/arrays.xml
@@ -40,7 +40,7 @@
<item msgid="8339720953594087771">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> এর সাথে কানেক্ট হচ্ছে…"</item>
<item msgid="3028983857109369308">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> দিয়ে যাচাইকরণ করা হচ্ছে..."</item>
<item msgid="4287401332778341890">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> থেকে আইপি অ্যাড্রেস জানা হচ্ছে…"</item>
- <item msgid="1043944043827424501">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>-এ কানেক্ট হয়েছে"</item>
+ <item msgid="1043944043827424501">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> তে কানেক্ট হয়েছে"</item>
<item msgid="7445993821842009653">"স্থগিত করা হয়েছে"</item>
<item msgid="1175040558087735707">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> থেকে ডিসকানেক্ট হচ্ছে…"</item>
<item msgid="699832486578171722">"ডিসকানেক্ট করা হয়েছে"</item>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 287a1ac..c27973f 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -22,7 +22,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="wifi_fail_to_scan" msgid="2333336097603822490">"No se pueden buscar las redes."</string>
<string name="wifi_security_none" msgid="7392696451280611452">"Ninguna"</string>
- <string name="wifi_remembered" msgid="3266709779723179188">"Guardado"</string>
+ <string name="wifi_remembered" msgid="3266709779723179188">"Guardada"</string>
<string name="wifi_disconnected" msgid="7054450256284661757">"Desconectado"</string>
<string name="wifi_disabled_generic" msgid="2651916945380294607">"Inhabilitada"</string>
<string name="wifi_disabled_network_failure" msgid="2660396183242399585">"Error de configuración IP"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index f9d57c4..3e8b1c1 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -37,7 +37,7 @@
<string name="wifi_no_internet" msgid="1774198889176926299">"Sen acceso a Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Gardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Conectouse automaticamente a través de %1$s"</string>
- <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Conectada automaticamente a través dun provedor de valoración de redes"</string>
+ <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Conectada automaticamente a través dun provedor de valoración de rede"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Conectado a través de %1$s"</string>
<string name="connected_via_app" msgid="3532267661404276584">"Wifi conectada a través de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Dispoñible a través de %1$s"</string>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index 5cdd954..c0af270 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -40,7 +40,7 @@
<item msgid="8339720953594087771">"Menyambung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="3028983857109369308">"Mengautentikasi dengan <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="4287401332778341890">"Mendapatkan alamat IP dari <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
- <item msgid="1043944043827424501">"Terhubung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+ <item msgid="1043944043827424501">"Tersambung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
<item msgid="7445993821842009653">"Ditangguhkan"</item>
<item msgid="1175040558087735707">"Diputus dari <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="699832486578171722">"Sambungan terputus"</item>
diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml
index 3018683..de38625 100644
--- a/packages/SettingsLib/res/values-it/arrays.xml
+++ b/packages/SettingsLib/res/values-it/arrays.xml
@@ -22,13 +22,13 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string-array name="wifi_status">
<item msgid="1596683495752107015"></item>
- <item msgid="3288373008277313483">"Scansione in corso…"</item>
- <item msgid="6050951078202663628">"Connessione…"</item>
- <item msgid="8356618438494652335">"Autenticazione…"</item>
- <item msgid="2837871868181677206">"Acquisizione indirizzo IP…"</item>
+ <item msgid="3288373008277313483">"Scansione in corso..."</item>
+ <item msgid="6050951078202663628">"Connessione..."</item>
+ <item msgid="8356618438494652335">"Autenticazione..."</item>
+ <item msgid="2837871868181677206">"Acquisizione indirizzo IP..."</item>
<item msgid="4613015005934755724">"Connessa"</item>
<item msgid="3763530049995655072">"Sospesa"</item>
- <item msgid="7852381437933824454">"Disconnessione…"</item>
+ <item msgid="7852381437933824454">"Disconnessione..."</item>
<item msgid="5046795712175415059">"Disconnessa"</item>
<item msgid="2473654476624070462">"Operazione non riuscita"</item>
<item msgid="9146847076036105115">"Bloccato"</item>
@@ -36,13 +36,13 @@
</string-array>
<string-array name="wifi_status_with_ssid">
<item msgid="5969842512724979061"></item>
- <item msgid="1818677602615822316">"Scansione in corso…"</item>
- <item msgid="8339720953594087771">"Connessione a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
- <item msgid="3028983857109369308">"Autenticazione con <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
- <item msgid="4287401332778341890">"Acquisizione indirizzo IP da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+ <item msgid="1818677602615822316">"Scansione in corso..."</item>
+ <item msgid="8339720953594087771">"Connessione a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+ <item msgid="3028983857109369308">"Autenticazione con <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+ <item msgid="4287401332778341890">"Acquisizione indirizzo IP da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
<item msgid="1043944043827424501">"Connessa a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
<item msgid="7445993821842009653">"Sospesa"</item>
- <item msgid="1175040558087735707">"Disconnessione da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+ <item msgid="1175040558087735707">"Disconnessione da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
<item msgid="699832486578171722">"Disconnessa"</item>
<item msgid="522383512264986901">"Operazione non riuscita"</item>
<item msgid="3602596701217484364">"Bloccato"</item>
diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml
index 91c2fa2..9f8a8e5 100644
--- a/packages/SettingsLib/res/values-ja/arrays.xml
+++ b/packages/SettingsLib/res/values-ja/arrays.xml
@@ -40,7 +40,7 @@
<item msgid="8339720953594087771">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>に接続中..."</item>
<item msgid="3028983857109369308">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>による認証中..."</item>
<item msgid="4287401332778341890">"IPアドレスを<xliff:g id="NETWORK_NAME">%1$s</xliff:g>から取得中..."</item>
- <item msgid="1043944043827424501">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> に接続済み"</item>
+ <item msgid="1043944043827424501">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>に接続しました"</item>
<item msgid="7445993821842009653">"保留中"</item>
<item msgid="1175040558087735707">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>から切断中..."</item>
<item msgid="699832486578171722">"切断されました"</item>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 8407db6..08cf5f9 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -211,8 +211,8 @@
<string name="adb_wireless_error" msgid="721958772149779856">"Алдаа"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"Wireless debugging"</string>
<string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Боломжтой төхөөрөмжүүдийг харах болох ашиглахын тулд wireless debugging-г асаана уу"</string>
- <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"QR кодоор төхөөрөмжийг хослуул"</string>
- <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR кодын сканнер ашиглан шинэ төхөөрөмжүүдийг хослуулна уу"</string>
+ <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Хурдан хариу үйлдлийн кодоор төхөөрөмжийг хослуул"</string>
+ <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Хурдан хариу үйлдлийн кодын сканнер ашиглан шинэ төхөөрөмжүүдийг хослуулна уу"</string>
<string name="adb_pair_method_code_title" msgid="1122590300445142904">"Хослуулах кодоор төхөөрөмжийг хослуулна уу"</string>
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Зургаан оронтой кодыг ашиглан шинэ төхөөрөмжүүдийг хослуулна уу"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"Хослуулсан төхөөрөмжүүд"</string>
@@ -226,12 +226,12 @@
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Wi‑Fi хослуулах код"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Хослуулалт амжилтгүй боллоо"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Төхөөрөмжийг ижил сүлжээнд холбосон эсэхийг шалгана уу."</string>
- <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"QR кодыг скан хийж Wi-Fi-р төхөөрөмжийг хослуулна уу"</string>
+ <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Хурдан хариу үйлдлийн кодыг скан хийж Wi-Fi-р төхөөрөмжийг хослуулна уу"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Төхөөрөмжийг хослуулж байна…"</string>
- <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Төхөөрөмжийг хослуулж чадсангүй. QR код буруу эсвэл төхөөрөмжийг ижил сүлжээнд холбоогүй байна."</string>
+ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Төхөөрөмжийг хослуулж чадсангүй. Хурдан хариу үйлдлийн код буруу эсвэл төхөөрөмжийг ижил сүлжээнд холбоогүй байна."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP хаяг ба порт"</string>
- <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR кодыг скан хийх"</string>
- <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR кодыг скан хийж Wi-Fi-р төхөөрөмжийг хослуулна уу"</string>
+ <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Хурдан хариу үйлдлийн кодыг скан хийх"</string>
+ <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Хурдан хариу үйлдлийн кодыг скан хийж Wi-Fi-р төхөөрөмжийг хослуулна уу"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Wi-Fi сүлжээнд холбогдоно уу"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, дебаг хийх, dev"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"Алдаа мэдээлэх товчлол"</string>
diff --git a/packages/SettingsLib/res/values-ne/arrays.xml b/packages/SettingsLib/res/values-ne/arrays.xml
index fb002c2..2895a02 100644
--- a/packages/SettingsLib/res/values-ne/arrays.xml
+++ b/packages/SettingsLib/res/values-ne/arrays.xml
@@ -238,7 +238,7 @@
</string-array>
<string-array name="show_non_rect_clip_entries">
<item msgid="2482978351289846212">"बन्द"</item>
- <item msgid="3405519300199774027">"गैर आयातकार क्षेत्र निलो रङमा कोर्नुहोस्"</item>
+ <item msgid="3405519300199774027">"गैर आयातकार क्षेत्र नीलो रङमा कोर्नुहोस्"</item>
<item msgid="1212561935004167943">"हाइलाइट परीक्षण चित्र कोर्ने आदेशहरू हरियोमा"</item>
</string-array>
<string-array name="track_frame_time_entries">
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 35bbbc0..34fdc1e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -543,12 +543,13 @@
mPbapProfile.setEnabled(device, true);
}
- if (mMapClientProfile != null) {
+ if ((mMapClientProfile != null)
+ && BluetoothUuid.containsAnyUuid(uuids, MapClientProfile.UUIDS)) {
profiles.add(mMapClientProfile);
removedProfiles.remove(mMapClientProfile);
}
- if ((mPbapClientProfile != null) && ArrayUtils.contains(localUuids, BluetoothUuid.PBAP_PCE)
+ if ((mPbapClientProfile != null)
&& BluetoothUuid.containsAnyUuid(uuids, PbapClientProfile.SRC_UUIDS)) {
profiles.add(mPbapClientProfile);
removedProfiles.remove(mPbapClientProfile);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index 19cb2f5..4881a86 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
@@ -47,8 +47,6 @@
private final LocalBluetoothProfileManager mProfileManager;
static final ParcelUuid[] UUIDS = {
- BluetoothUuid.MAP,
- BluetoothUuid.MNS,
BluetoothUuid.MAS,
};
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS b/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
index f506b7c..0bde5c0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
@@ -1,7 +1,9 @@
# Default reviewers for this and subdirectories.
-qal@google.com
+andychou@google.com
arcwang@google.com
-govenliu@google.com
asapperstein@google.com
+goldmanj@google.com
+qal@google.com
+wengsu@google.com
-# Emergency approvers in case the above are not available
\ No newline at end of file
+# Emergency approvers in case the above are not available
diff --git a/packages/SettingsProvider/res/values-fa/strings.xml b/packages/SettingsProvider/res/values-fa/strings.xml
index 946e2c0..cc0b557 100644
--- a/packages/SettingsProvider/res/values-fa/strings.xml
+++ b/packages/SettingsProvider/res/values-fa/strings.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_label" msgid="4567566098528588863">"تنظیم محل فضای ذخیرهسازی"</string>
+ <string name="app_label" msgid="4567566098528588863">"تنظیم محل ذخیره"</string>
<string name="wifi_softap_config_change" msgid="5688373762357941645">"تنظیمات نقطه اتصال تغییر کرده است"</string>
<string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"برای مشاهده جزئیات ضربه بزنید"</string>
</resources>
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 190015c..f5f58ef 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -323,6 +323,9 @@
<!-- Permissions required for CTS test - AdbManagerTest -->
<uses-permission android:name="android.permission.MANAGE_DEBUGGING" />
+ <!-- Permission needed for CTS test - DisplayTest -->
+ <uses-permission android:name="android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/Shell/res/values-it/strings.xml b/packages/Shell/res/values-it/strings.xml
index 02531f2..18ab908 100644
--- a/packages/Shell/res/values-it/strings.xml
+++ b/packages/Shell/res/values-it/strings.xml
@@ -21,7 +21,7 @@
<string name="bugreport_in_progress_title" msgid="4311705936714972757">"Generazione segnalazione di bug <xliff:g id="ID">#%d</xliff:g> in corso"</string>
<string name="bugreport_finished_title" msgid="4429132808670114081">"Segnalazione di bug <xliff:g id="ID">#%d</xliff:g> acquisita"</string>
<string name="bugreport_updating_title" msgid="4423539949559634214">"Aggiunta di dettagli alla segnalazione di bug"</string>
- <string name="bugreport_updating_wait" msgid="3322151947853929470">"Attendi…"</string>
+ <string name="bugreport_updating_wait" msgid="3322151947853929470">"Attendi..."</string>
<string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"La segnalazione di bug comparirà a breve sul telefono"</string>
<string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Seleziona per condividere la segnalazione di bug"</string>
<string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tocca per condividere la segnalazione di bug"</string>
diff --git a/packages/Shell/res/values-ky/strings.xml b/packages/Shell/res/values-ky/strings.xml
index 3567ac2..969e9ed 100644
--- a/packages/Shell/res/values-ky/strings.xml
+++ b/packages/Shell/res/values-ky/strings.xml
@@ -29,7 +29,7 @@
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Мүчүлүштүк тууралуу билдирүүңүздү скриншотсуз бөлүшүү үчүн таптап коюңуз же скриншот даяр болгуча күтө туруңуз"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Мүчүлүштүк тууралуу билдирүүңүздү скриншотсуз бөлүшүү үчүн таптап коюңуз же скриншот даяр болгуча күтө туруңуз"</string>
<string name="bugreport_confirm" msgid="5917407234515812495">"Мүчүлүштүктөр тууралуу билдирүүлөрдө тутумдун ар кандай таржымалдарынан алынган дайындар, ошондой эле купуя маалымат камтылышы мүмкүн (мисалы, жайгашкан жер сыяктуу). Мындай билдирүүлөрдү бир гана ишеничтүү адамдар жана колдонмолор менен бөлүшүңүз."</string>
- <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Экинчи көрүнбөсүн"</string>
+ <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Экинчи көрсөтүлбөсүн"</string>
<string name="bugreport_storage_title" msgid="5332488144740527109">"Мүчүлүштүктөрдү кабарлоо"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Мүчүлүштүк тууралуу кабарлаган файл окулбай койду"</string>
<string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Мүчүлүштүктөр жөнүндө кабардын чоо-жайы zip файлына кошулбай койду"</string>
diff --git a/packages/SimAppDialog/res/values-ky/strings.xml b/packages/SimAppDialog/res/values-ky/strings.xml
index 54cbb5b..32db421 100644
--- a/packages/SimAppDialog/res/values-ky/strings.xml
+++ b/packages/SimAppDialog/res/values-ky/strings.xml
@@ -19,7 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="8898068901680117589">"SIM-картанын колдонмосунун диалогу"</string>
<string name="install_carrier_app_title" msgid="334729104862562585">"Мобилдик кызматты жандыруу"</string>
- <string name="install_carrier_app_description" msgid="4014303558674923797">"Жаңы SIM картаңыз талаптагыдай иштеши үчүн, <xliff:g id="ID_1">%1$s</xliff:g> колдонмосун орнотуп алышыңыз керек"</string>
+ <string name="install_carrier_app_description" msgid="4014303558674923797">"Жаңы SIM-картаңыз талаптагыдай иштеши үчүн, <xliff:g id="ID_1">%1$s</xliff:g> колдонмосун орнотуп алышыңыз керек"</string>
<string name="install_carrier_app_description_default" msgid="7356830245205847840">"Жаңы SIM картаңыз талаптагыдай иштеши үчүн, байланыш операторунун колдонмосун орнотуп алышыңыз керек"</string>
<string name="install_carrier_app_defer_action" msgid="2558576736886876209">"Азыр эмес"</string>
<string name="install_carrier_app_download_action" msgid="7859229305958538064">"Колдонмону жүктөп алуу"</string>
diff --git a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
index d2f168e..2857308 100644
--- a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
+++ b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
@@ -584,15 +584,19 @@
}
private Uri getCurrentlySelectedRingtoneUri() {
- if (getCheckedItem() == mDefaultRingtonePos) {
- // Use the default Uri that they originally gave us.
- return mUriForDefaultItem;
- } else if (getCheckedItem() == mSilentPos) {
- // Use a null Uri for the 'Silent' item.
- return null;
- } else {
- return mRingtoneManager.getRingtoneUri(getRingtoneManagerPosition(getCheckedItem()));
- }
+ if (getCheckedItem() == POS_UNKNOWN) {
+ // When the getCheckItem is POS_UNKNOWN, it is not the case we expected.
+ // We return null for this case.
+ return null;
+ } else if (getCheckedItem() == mDefaultRingtonePos) {
+ // Use the default Uri that they originally gave us.
+ return mUriForDefaultItem;
+ } else if (getCheckedItem() == mSilentPos) {
+ // Use a null Uri for the 'Silent' item.
+ return null;
+ } else {
+ return mRingtoneManager.getRingtoneUri(getRingtoneManagerPosition(getCheckedItem()));
+ }
}
private void saveAnyPlayingRingtone() {
diff --git a/packages/SystemUI/res/values-fi/strings_tv.xml b/packages/SystemUI/res/values-fi/strings_tv.xml
index e22a166..3a80561 100644
--- a/packages/SystemUI/res/values-fi/strings_tv.xml
+++ b/packages/SystemUI/res/values-fi/strings_tv.xml
@@ -24,5 +24,5 @@
<string name="pip_close" msgid="5775212044472849930">"Sulje PIP"</string>
<string name="pip_fullscreen" msgid="3877997489869475181">"Koko näyttö"</string>
<string name="mic_active" msgid="5766614241012047024">"Mikrofoni aktiivinen"</string>
- <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s sai pääsyn mikrofoniisi"</string>
+ <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s käytti mikrofoniasi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings_tv.xml b/packages/SystemUI/res/values-nb/strings_tv.xml
index 9b46678..22580e6 100644
--- a/packages/SystemUI/res/values-nb/strings_tv.xml
+++ b/packages/SystemUI/res/values-nb/strings_tv.xml
@@ -24,5 +24,5 @@
<string name="pip_close" msgid="5775212044472849930">"Lukk PIP"</string>
<string name="pip_fullscreen" msgid="3877997489869475181">"Fullskjerm"</string>
<string name="mic_active" msgid="5766614241012047024">"Mikrofonen er aktiv"</string>
- <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s fikk tilgang til mikrofonen din"</string>
+ <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s brukte mikrofonen din"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings_tv.xml b/packages/SystemUI/res/values-pl/strings_tv.xml
index 852ea505..5921aa7 100644
--- a/packages/SystemUI/res/values-pl/strings_tv.xml
+++ b/packages/SystemUI/res/values-pl/strings_tv.xml
@@ -24,5 +24,5 @@
<string name="pip_close" msgid="5775212044472849930">"Zamknij PIP"</string>
<string name="pip_fullscreen" msgid="3877997489869475181">"Pełny ekran"</string>
<string name="mic_active" msgid="5766614241012047024">"Mikrofon aktywny"</string>
- <string name="app_accessed_mic" msgid="2754428675130470196">"Aplikacja %1$s uzyskała dostęp do mikrofonu"</string>
+ <string name="app_accessed_mic" msgid="2754428675130470196">"Aplikacja %1$s korzystała z mikrofonu"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings_tv.xml b/packages/SystemUI/res/values-sv/strings_tv.xml
index cf40057..64d6162 100644
--- a/packages/SystemUI/res/values-sv/strings_tv.xml
+++ b/packages/SystemUI/res/values-sv/strings_tv.xml
@@ -24,5 +24,5 @@
<string name="pip_close" msgid="5775212044472849930">"Stäng PIP"</string>
<string name="pip_fullscreen" msgid="3877997489869475181">"Helskärm"</string>
<string name="mic_active" msgid="5766614241012047024">"Mikrofonen är aktiv"</string>
- <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s har fått åtkomst till mikrofonen"</string>
+ <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s har använt mikrofonen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
index 1cd6314..3cf2b43 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings_tv.xml
@@ -24,5 +24,5 @@
<string name="pip_close" msgid="5775212044472849930">"關閉 PIP"</string>
<string name="pip_fullscreen" msgid="3877997489869475181">"全螢幕"</string>
<string name="mic_active" msgid="5766614241012047024">"麥克風已啟用"</string>
- <string name="app_accessed_mic" msgid="2754428675130470196">"「%1$s」已存取您的麥克風"</string>
+ <string name="app_accessed_mic" msgid="2754428675130470196">"%1$s 曾存取您的麥克風"</string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 02d2b8e..d1df276 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -126,6 +126,7 @@
import com.android.systemui.wm.DisplayImeController;
import com.android.systemui.wm.SystemWindows;
+import java.util.concurrent.Executor;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -167,6 +168,15 @@
* Generic handler on the main thread.
*/
private static final String MAIN_HANDLER_NAME = "main_handler";
+ /**
+ * Generic executor on the main thread.
+ */
+ private static final String MAIN_EXECUTOR_NAME = "main_executor";
+
+ /**
+ * Generic executor on a background thread.
+ */
+ private static final String BACKGROUND_EXECUTOR_NAME = "background_executor";
/**
* An email address to send memory leak reports to by default.
@@ -199,6 +209,17 @@
new DependencyKey<>(MAIN_HANDLER_NAME);
/**
+ * Generic executor on the main thread.
+ */
+ public static final DependencyKey<Executor> MAIN_EXECUTOR =
+ new DependencyKey<>(MAIN_EXECUTOR_NAME);
+ /**
+ * Generic executor on a background thread.
+ */
+ public static final DependencyKey<Executor> BACKGROUND_EXECUTOR =
+ new DependencyKey<>(BACKGROUND_EXECUTOR_NAME);
+
+ /**
* An email address to send memory leak reports to by default.
*/
public static final DependencyKey<String> LEAK_REPORT_EMAIL =
@@ -301,6 +322,8 @@
@Inject @Named(TIME_TICK_HANDLER_NAME) Lazy<Handler> mTimeTickHandler;
@Nullable
@Inject @Named(LEAK_REPORT_EMAIL_NAME) Lazy<String> mLeakReportEmail;
+ @Inject @Main Lazy<Executor> mMainExecutor;
+ @Inject @Background Lazy<Executor> mBackgroundExecutor;
@Inject Lazy<ClockManager> mClockManager;
@Inject Lazy<ActivityManagerWrapper> mActivityManagerWrapper;
@Inject Lazy<DevicePolicyManagerWrapper> mDevicePolicyManagerWrapper;
@@ -337,6 +360,8 @@
mProviders.put(BG_LOOPER, mBgLooper::get);
mProviders.put(MAIN_LOOPER, mMainLooper::get);
mProviders.put(MAIN_HANDLER, mMainHandler::get);
+ mProviders.put(MAIN_EXECUTOR, mMainExecutor::get);
+ mProviders.put(BACKGROUND_EXECUTOR, mBackgroundExecutor::get);
mProviders.put(ActivityStarter.class, mActivityStarter::get);
mProviders.put(BroadcastDispatcher.class, mBroadcastDispatcher::get);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index b47c59a..0a366c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -85,8 +85,6 @@
import com.android.systemui.tuner.LockscreenFragment.LockButtonFactory;
import com.android.systemui.tuner.TunerService;
-import java.util.concurrent.Executor;
-
/**
* Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
* text.
@@ -561,7 +559,7 @@
}
};
if (!mKeyguardStateController.canDismissLockScreen()) {
- Dependency.get(Executor.class).execute(runnable);
+ Dependency.get(Dependency.BACKGROUND_EXECUTOR).execute(runnable);
} else {
boolean dismissShade = !TextUtils.isEmpty(mRightButtonStr)
&& Dependency.get(TunerService.class).getValue(LOCKSCREEN_RIGHT_UNLOCK, 1) != 0;
diff --git a/packages/Tethering/apex/Android.bp b/packages/Tethering/apex/Android.bp
index 67097a7..0524374 100644
--- a/packages/Tethering/apex/Android.bp
+++ b/packages/Tethering/apex/Android.bp
@@ -19,6 +19,7 @@
updatable: true,
min_sdk_version: "current",
java_libs: ["framework-tethering"],
+ bpfs: ["offload.o"],
apps: ["Tethering"],
manifest: "manifest.json",
key: "com.android.tethering.key",
diff --git a/packages/Tethering/apex/manifest.json b/packages/Tethering/apex/manifest.json
index 538ffb3..8836c4e 100644
--- a/packages/Tethering/apex/manifest.json
+++ b/packages/Tethering/apex/manifest.json
@@ -1,4 +1,4 @@
{
"name": "com.android.tethering",
- "version": 300000000
+ "version": 300900700
}
diff --git a/packages/Tethering/bpf_progs/Android.bp b/packages/Tethering/bpf_progs/Android.bp
new file mode 100644
index 0000000..d54f861
--- /dev/null
+++ b/packages/Tethering/bpf_progs/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// bpf kernel programs
+//
+bpf {
+ name: "offload.o",
+ srcs: ["offload.c"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ include_dirs: [
+ // TODO: get rid of system/netd.
+ "system/netd/bpf_progs", // for bpf_net_helpers.h
+ "system/netd/libnetdbpf/include", // for bpf_shared.h
+ "system/netd/libnetdutils/include", // for UidConstants.h
+ ],
+}
diff --git a/packages/Tethering/bpf_progs/offload.c b/packages/Tethering/bpf_progs/offload.c
new file mode 100644
index 0000000..cc5af31
--- /dev/null
+++ b/packages/Tethering/bpf_progs/offload.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <linux/if.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/pkt_cls.h>
+#include <linux/tcp.h>
+
+#include "bpf_helpers.h"
+#include "bpf_net_helpers.h"
+#include "netdbpf/bpf_shared.h"
+
+DEFINE_BPF_MAP_GRW(tether_ingress_map, HASH, TetherIngressKey, TetherIngressValue, 64,
+ AID_NETWORK_STACK)
+
+// Tethering stats, indexed by upstream interface.
+DEFINE_BPF_MAP_GRW(tether_stats_map, HASH, uint32_t, TetherStatsValue, 16, AID_NETWORK_STACK)
+
+// Tethering data limit, indexed by upstream interface.
+// (tethering allowed when stats[iif].rxBytes + stats[iif].txBytes < limit[iif])
+DEFINE_BPF_MAP_GRW(tether_limit_map, HASH, uint32_t, uint64_t, 16, AID_NETWORK_STACK)
+
+static inline __always_inline int do_forward(struct __sk_buff* skb, bool is_ethernet) {
+ int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0;
+ void* data = (void*)(long)skb->data;
+ const void* data_end = (void*)(long)skb->data_end;
+ struct ethhdr* eth = is_ethernet ? data : NULL; // used iff is_ethernet
+ struct ipv6hdr* ip6 = is_ethernet ? (void*)(eth + 1) : data;
+
+ // Must be meta-ethernet IPv6 frame
+ if (skb->protocol != htons(ETH_P_IPV6)) return TC_ACT_OK;
+
+ // Must have (ethernet and) ipv6 header
+ if (data + l2_header_size + sizeof(*ip6) > data_end) return TC_ACT_OK;
+
+ // Ethertype - if present - must be IPv6
+ if (is_ethernet && (eth->h_proto != htons(ETH_P_IPV6))) return TC_ACT_OK;
+
+ // IP version must be 6
+ if (ip6->version != 6) return TC_ACT_OK;
+
+ // Cannot decrement during forward if already zero or would be zero,
+ // Let the kernel's stack handle these cases and generate appropriate ICMP errors.
+ if (ip6->hop_limit <= 1) return TC_ACT_OK;
+
+ // Protect against forwarding packets sourced from ::1 or fe80::/64 or other weirdness.
+ __be32 src32 = ip6->saddr.s6_addr32[0];
+ if (src32 != htonl(0x0064ff9b) && // 64:ff9b:/32 incl. XLAT464 WKP
+ (src32 & htonl(0xe0000000)) != htonl(0x20000000)) // 2000::/3 Global Unicast
+ return TC_ACT_OK;
+
+ TetherIngressKey k = {
+ .iif = skb->ifindex,
+ .neigh6 = ip6->daddr,
+ };
+
+ TetherIngressValue* v = bpf_tether_ingress_map_lookup_elem(&k);
+
+ // If we don't find any offload information then simply let the core stack handle it...
+ if (!v) return TC_ACT_OK;
+
+ uint32_t stat_and_limit_k = skb->ifindex;
+
+ TetherStatsValue* stat_v = bpf_tether_stats_map_lookup_elem(&stat_and_limit_k);
+
+ // If we don't have anywhere to put stats, then abort...
+ if (!stat_v) return TC_ACT_OK;
+
+ uint64_t* limit_v = bpf_tether_limit_map_lookup_elem(&stat_and_limit_k);
+
+ // If we don't have a limit, then abort...
+ if (!limit_v) return TC_ACT_OK;
+
+ // Required IPv6 minimum mtu is 1280, below that not clear what we should do, abort...
+ const int pmtu = v->pmtu;
+ if (pmtu < IPV6_MIN_MTU) return TC_ACT_OK;
+
+ // Approximate handling of TCP/IPv6 overhead for incoming LRO/GRO packets: default
+ // outbound path mtu of 1500 is not necessarily correct, but worst case we simply
+ // undercount, which is still better then not accounting for this overhead at all.
+ // Note: this really shouldn't be device/path mtu at all, but rather should be
+ // derived from this particular connection's mss (ie. from gro segment size).
+ // This would require a much newer kernel with newer ebpf accessors.
+ // (This is also blindly assuming 12 bytes of tcp timestamp option in tcp header)
+ uint64_t packets = 1;
+ uint64_t bytes = skb->len;
+ if (bytes > pmtu) {
+ const int tcp_overhead = sizeof(struct ipv6hdr) + sizeof(struct tcphdr) + 12;
+ const int mss = pmtu - tcp_overhead;
+ const uint64_t payload = bytes - tcp_overhead;
+ packets = (payload + mss - 1) / mss;
+ bytes = tcp_overhead * packets + payload;
+ }
+
+ // Are we past the limit? If so, then abort...
+ // Note: will not overflow since u64 is 936 years even at 5Gbps.
+ // Do not drop here. Offload is just that, whenever we fail to handle
+ // a packet we let the core stack deal with things.
+ // (The core stack needs to handle limits correctly anyway,
+ // since we don't offload all traffic in both directions)
+ if (stat_v->rxBytes + stat_v->txBytes + bytes > *limit_v) return TC_ACT_OK;
+
+ if (!is_ethernet) {
+ is_ethernet = true;
+ l2_header_size = sizeof(struct ethhdr);
+ // Try to inject an ethernet header, and simply return if we fail
+ if (bpf_skb_change_head(skb, l2_header_size, /*flags*/ 0)) {
+ __sync_fetch_and_add(&stat_v->rxErrors, 1);
+ return TC_ACT_OK;
+ }
+
+ // bpf_skb_change_head() invalidates all pointers - reload them
+ data = (void*)(long)skb->data;
+ data_end = (void*)(long)skb->data_end;
+ eth = data;
+ ip6 = (void*)(eth + 1);
+
+ // I do not believe this can ever happen, but keep the verifier happy...
+ if (data + l2_header_size + sizeof(*ip6) > data_end) {
+ __sync_fetch_and_add(&stat_v->rxErrors, 1);
+ return TC_ACT_SHOT;
+ }
+ };
+
+ // CHECKSUM_COMPLETE is a 16-bit one's complement sum,
+ // thus corrections for it need to be done in 16-byte chunks at even offsets.
+ // IPv6 nexthdr is at offset 6, while hop limit is at offset 7
+ uint8_t old_hl = ip6->hop_limit;
+ --ip6->hop_limit;
+ uint8_t new_hl = ip6->hop_limit;
+
+ // bpf_csum_update() always succeeds if the skb is CHECKSUM_COMPLETE and returns an error
+ // (-ENOTSUPP) if it isn't.
+ bpf_csum_update(skb, 0xFFFF - ntohs(old_hl) + ntohs(new_hl));
+
+ __sync_fetch_and_add(&stat_v->rxPackets, packets);
+ __sync_fetch_and_add(&stat_v->rxBytes, bytes);
+
+ // Overwrite any mac header with the new one
+ *eth = v->macHeader;
+
+ // Redirect to forwarded interface.
+ //
+ // Note that bpf_redirect() cannot fail unless you pass invalid flags.
+ // The redirect actually happens after the ebpf program has already terminated,
+ // and can fail for example for mtu reasons at that point in time, but there's nothing
+ // we can do about it here.
+ return bpf_redirect(v->oif, 0 /* this is effectively BPF_F_EGRESS */);
+}
+
+SEC("schedcls/ingress/tether_ether")
+int sched_cls_ingress_tether_ether(struct __sk_buff* skb) {
+ return do_forward(skb, true);
+}
+
+// Note: section names must be unique to prevent programs from appending to each other,
+// so instead the bpf loader will strip everything past the final $ symbol when actually
+// pinning the program into the filesystem.
+//
+// bpf_skb_change_head() is only present on 4.14+ and 2 trivial kernel patches are needed:
+// ANDROID: net: bpf: Allow TC programs to call BPF_FUNC_skb_change_head
+// ANDROID: net: bpf: permit redirect from ingress L3 to egress L2 devices at near max mtu
+// (the first of those has already been upstreamed)
+//
+// 5.4 kernel support was only added to Android Common Kernel in R,
+// and thus a 5.4 kernel always supports this.
+//
+// Hence, this mandatory (must load successfully) implementation for 5.4+ kernels:
+DEFINE_BPF_PROG_KVER("schedcls/ingress/tether_rawip$5_4", AID_ROOT, AID_ROOT,
+ sched_cls_ingress_tether_rawip_5_4, KVER(5, 4, 0))
+(struct __sk_buff* skb) {
+ return do_forward(skb, false);
+}
+
+// and this identical optional (may fail to load) implementation for [4.14..5.4) patched kernels:
+DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/ingress/tether_rawip$4_14", AID_ROOT, AID_ROOT,
+ sched_cls_ingress_tether_rawip_4_14, KVER(4, 14, 0),
+ KVER(5, 4, 0))
+(struct __sk_buff* skb) {
+ return do_forward(skb, false);
+}
+
+// and define a no-op stub for [4.9,4.14) and unpatched [4.14,5.4) kernels.
+// (if the above real 4.14+ program loaded successfully, then bpfloader will have already pinned
+// it at the same location this one would be pinned at and will thus skip loading this stub)
+DEFINE_BPF_PROG_KVER_RANGE("schedcls/ingress/tether_rawip$stub", AID_ROOT, AID_ROOT,
+ sched_cls_ingress_tether_rawip_stub, KVER_NONE, KVER(5, 4, 0))
+(struct __sk_buff* skb) {
+ return TC_ACT_OK;
+}
+
+LICENSE("Apache 2.0");
+CRITICAL("netd");
diff --git a/packages/Tethering/jni/android_net_util_TetheringUtils.cpp b/packages/Tethering/jni/android_net_util_TetheringUtils.cpp
index f6eb40a..94c871d 100644
--- a/packages/Tethering/jni/android_net_util_TetheringUtils.cpp
+++ b/packages/Tethering/jni/android_net_util_TetheringUtils.cpp
@@ -17,18 +17,63 @@
#include <errno.h>
#include <error.h>
#include <jni.h>
+#include <linux/filter.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/JNIHelpCompat.h>
#include <nativehelper/ScopedUtfChars.h>
#include <net/if.h>
+#include <netinet/ether.h>
+#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <sys/socket.h>
+#include <stdio.h>
#define LOG_TAG "TetheringUtils"
#include <android/log.h>
namespace android {
+static const uint32_t kIPv6NextHeaderOffset = offsetof(ip6_hdr, ip6_nxt);
+static const uint32_t kIPv6PayloadStart = sizeof(ip6_hdr);
+static const uint32_t kICMPv6TypeOffset = kIPv6PayloadStart + offsetof(icmp6_hdr, icmp6_type);
+
+static void android_net_util_setupIcmpFilter(JNIEnv *env, jobject javaFd, uint32_t type) {
+ sock_filter filter_code[] = {
+ // Check header is ICMPv6.
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeaderOffset),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3),
+
+ // Check ICMPv6 type.
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, type, 0, 1),
+
+ // Accept or reject.
+ BPF_STMT(BPF_RET | BPF_K, 0xffff),
+ BPF_STMT(BPF_RET | BPF_K, 0)
+ };
+
+ const sock_fprog filter = {
+ sizeof(filter_code) / sizeof(filter_code[0]),
+ filter_code,
+ };
+
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
+ }
+}
+
+static void android_net_util_setupNaSocket(JNIEnv *env, jobject clazz, jobject javaFd)
+{
+ android_net_util_setupIcmpFilter(env, javaFd, ND_NEIGHBOR_ADVERT);
+}
+
+static void android_net_util_setupNsSocket(JNIEnv *env, jobject clazz, jobject javaFd)
+{
+ android_net_util_setupIcmpFilter(env, javaFd, ND_NEIGHBOR_SOLICIT);
+}
+
static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd,
jint ifIndex)
{
@@ -125,7 +170,12 @@
*/
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_util_setupRaSocket },
+ { "setupNaSocket", "(Ljava/io/FileDescriptor;)V",
+ (void*) android_net_util_setupNaSocket },
+ { "setupNsSocket", "(Ljava/io/FileDescriptor;)V",
+ (void*) android_net_util_setupNsSocket },
+ { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V",
+ (void*) android_net_util_setupRaSocket },
};
int register_android_net_util_TetheringUtils(JNIEnv* env) {
diff --git a/packages/Tethering/src/android/net/ip/DadProxy.java b/packages/Tethering/src/android/net/ip/DadProxy.java
new file mode 100644
index 0000000..e2976b7
--- /dev/null
+++ b/packages/Tethering/src/android/net/ip/DadProxy.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import android.net.util.InterfaceParams;
+import android.os.Handler;
+
+import androidx.annotation.VisibleForTesting;
+
+/**
+ * Basic Duplicate address detection proxy.
+ *
+ * @hide
+ */
+public class DadProxy {
+ private static final String TAG = DadProxy.class.getSimpleName();
+
+ @VisibleForTesting
+ public static NeighborPacketForwarder naForwarder;
+ public static NeighborPacketForwarder nsForwarder;
+
+ public DadProxy(Handler h, InterfaceParams tetheredIface) {
+ naForwarder = new NeighborPacketForwarder(h, tetheredIface,
+ NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT);
+ nsForwarder = new NeighborPacketForwarder(h, tetheredIface,
+ NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION);
+ }
+
+ /** Stop NS/NA Forwarders. */
+ public void stop() {
+ naForwarder.stop();
+ nsForwarder.stop();
+ }
+
+ /** Set upstream iface on both forwarders. */
+ public void setUpstreamIface(InterfaceParams upstreamIface) {
+ naForwarder.setUpstreamIface(upstreamIface);
+ nsForwarder.setUpstreamIface(upstreamIface);
+ }
+}
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 673cbf0..336124d 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -51,6 +51,7 @@
import android.net.util.InterfaceSet;
import android.net.util.PrefixUtils;
import android.net.util.SharedLog;
+import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -160,6 +161,15 @@
/** Capture IpServer dependencies, for injection. */
public abstract static class Dependencies {
+ /**
+ * Create a DadProxy instance to be used by IpServer.
+ * To support multiple tethered interfaces concurrently DAD Proxy
+ * needs to be supported per IpServer instead of per upstream.
+ */
+ public DadProxy getDadProxy(Handler handler, InterfaceParams ifParams) {
+ return new DadProxy(handler, ifParams);
+ }
+
/** Create an IpNeighborMonitor to be used by this IpServer */
public IpNeighborMonitor getIpNeighborMonitor(Handler handler, SharedLog log,
IpNeighborMonitor.NeighborEventConsumer consumer) {
@@ -256,6 +266,7 @@
// Advertisements (otherwise, we do not add them to mLinkProperties at all).
private LinkProperties mLastIPv6LinkProperties;
private RouterAdvertisementDaemon mRaDaemon;
+ private DadProxy mDadProxy;
// To be accessed only on the handler thread
private int mDhcpServerStartIndex = 0;
@@ -674,6 +685,13 @@
return false;
}
+ // TODO: use ShimUtils instead of explicitly checking the version here.
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R || "S".equals(Build.VERSION.CODENAME)
+ || "T".equals(Build.VERSION.CODENAME)) {
+ // DAD Proxy starts forwarding packets after IPv6 upstream is present.
+ mDadProxy = mDeps.getDadProxy(getHandler(), mInterfaceParams);
+ }
+
return true;
}
@@ -685,6 +703,11 @@
mRaDaemon.stop();
mRaDaemon = null;
}
+
+ if (mDadProxy != null) {
+ mDadProxy.stop();
+ mDadProxy = null;
+ }
}
// IPv6TetheringCoordinator sends updates with carefully curated IPv6-only
@@ -702,11 +725,16 @@
}
RaParams params = null;
- int upstreamIfindex = 0;
+ String upstreamIface = null;
+ InterfaceParams upstreamIfaceParams = null;
+ int upstreamIfIndex = 0;
if (v6only != null) {
- final String upstreamIface = v6only.getInterfaceName();
-
+ upstreamIface = v6only.getInterfaceName();
+ upstreamIfaceParams = mDeps.getInterfaceParams(upstreamIface);
+ if (upstreamIfaceParams != null) {
+ upstreamIfIndex = upstreamIfaceParams.index;
+ }
params = new RaParams();
params.mtu = v6only.getMtu();
params.hasDefaultRoute = v6only.hasIpv6DefaultRoute();
@@ -726,15 +754,13 @@
}
}
- upstreamIfindex = mDeps.getIfindex(upstreamIface);
-
// Add upstream index to name mapping for the tether stats usage in the coordinator.
// Although this mapping could be added by both class Tethering and IpServer, adding
// mapping from IpServer guarantees that the mapping is added before the adding
// forwarding rules. That is because there are different state machines in both
// classes. It is hard to guarantee the link property update order between multiple
// state machines.
- mBpfCoordinator.addUpstreamNameToLookupTable(upstreamIfindex, upstreamIface);
+ mBpfCoordinator.addUpstreamNameToLookupTable(upstreamIfIndex, upstreamIface);
}
// If v6only is null, we pass in null to setRaParams(), which handles
@@ -743,8 +769,11 @@
setRaParams(params);
mLastIPv6LinkProperties = v6only;
- updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfindex, null);
- mLastIPv6UpstreamIfindex = upstreamIfindex;
+ updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfIndex, null);
+ mLastIPv6UpstreamIfindex = upstreamIfIndex;
+ if (mDadProxy != null) {
+ mDadProxy.setUpstreamIface(upstreamIfaceParams);
+ }
}
private void removeRoutesFromLocalNetwork(@NonNull final List<RouteInfo> toBeRemoved) {
diff --git a/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java b/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
new file mode 100644
index 0000000..73fc833
--- /dev/null
+++ b/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.AF_PACKET;
+import static android.system.OsConstants.ETH_P_IPV6;
+import static android.system.OsConstants.IPPROTO_RAW;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_NONBLOCK;
+import static android.system.OsConstants.SOCK_RAW;
+
+import android.net.util.InterfaceParams;
+import android.net.util.PacketReader;
+import android.net.util.SocketUtils;
+import android.net.util.TetheringUtils;
+import android.os.Handler;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.Inet6Address;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+
+/**
+ * Basic IPv6 Neighbor Advertisement Forwarder.
+ *
+ * Forward NA packets from upstream iface to tethered iface
+ * and NS packets from tethered iface to upstream iface.
+ *
+ * @hide
+ */
+public class NeighborPacketForwarder extends PacketReader {
+ private final String mTag;
+
+ private FileDescriptor mFd;
+
+ // TODO: get these from NetworkStackConstants.
+ private static final int IPV6_ADDR_LEN = 16;
+ private static final int IPV6_DST_ADDR_OFFSET = 24;
+ private static final int IPV6_HEADER_LEN = 40;
+ private static final int ETH_HEADER_LEN = 14;
+
+ private InterfaceParams mListenIfaceParams, mSendIfaceParams;
+
+ private final int mType;
+ public static final int ICMPV6_NEIGHBOR_ADVERTISEMENT = 136;
+ public static final int ICMPV6_NEIGHBOR_SOLICITATION = 135;
+
+ public NeighborPacketForwarder(Handler h, InterfaceParams tetheredInterface, int type) {
+ super(h);
+ mTag = NeighborPacketForwarder.class.getSimpleName() + "-"
+ + tetheredInterface.name + "-" + type;
+ mType = type;
+
+ if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) {
+ mSendIfaceParams = tetheredInterface;
+ } else {
+ mListenIfaceParams = tetheredInterface;
+ }
+ }
+
+ /** Set new upstream iface and start/stop based on new params. */
+ public void setUpstreamIface(InterfaceParams upstreamParams) {
+ final InterfaceParams oldUpstreamParams;
+
+ if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) {
+ oldUpstreamParams = mListenIfaceParams;
+ mListenIfaceParams = upstreamParams;
+ } else {
+ oldUpstreamParams = mSendIfaceParams;
+ mSendIfaceParams = upstreamParams;
+ }
+
+ if (oldUpstreamParams == null && upstreamParams != null) {
+ start();
+ } else if (oldUpstreamParams != null && upstreamParams == null) {
+ stop();
+ } else if (oldUpstreamParams != null && upstreamParams != null
+ && oldUpstreamParams.index != upstreamParams.index) {
+ stop();
+ start();
+ }
+ }
+
+ // TODO: move NetworkStackUtils.closeSocketQuietly to
+ // frameworks/libs/net/common/device/com/android/net/module/util/[someclass].
+ private void closeSocketQuietly(FileDescriptor fd) {
+ try {
+ SocketUtils.closeSocket(fd);
+ } catch (IOException ignored) {
+ }
+ }
+
+ @Override
+ protected FileDescriptor createFd() {
+ try {
+ // ICMPv6 packets from modem do not have eth header, so RAW socket cannot be used.
+ // To keep uniformity in both directions PACKET socket can be used.
+ mFd = Os.socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
+
+ // TODO: convert setup*Socket to setupICMPv6BpfFilter with filter type?
+ if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) {
+ TetheringUtils.setupNaSocket(mFd);
+ } else if (mType == ICMPV6_NEIGHBOR_SOLICITATION) {
+ TetheringUtils.setupNsSocket(mFd);
+ }
+
+ SocketAddress bindAddress = SocketUtils.makePacketSocketAddress(
+ ETH_P_IPV6, mListenIfaceParams.index);
+ Os.bind(mFd, bindAddress);
+ } catch (ErrnoException | SocketException e) {
+ Log.wtf(mTag, "Failed to create socket", e);
+ closeSocketQuietly(mFd);
+ return null;
+ }
+
+ return mFd;
+ }
+
+ private Inet6Address getIpv6DestinationAddress(byte[] recvbuf) {
+ Inet6Address dstAddr;
+ try {
+ dstAddr = (Inet6Address) Inet6Address.getByAddress(Arrays.copyOfRange(recvbuf,
+ IPV6_DST_ADDR_OFFSET, IPV6_DST_ADDR_OFFSET + IPV6_ADDR_LEN));
+ } catch (UnknownHostException | ClassCastException impossible) {
+ throw new AssertionError("16-byte array not valid IPv6 address?");
+ }
+ return dstAddr;
+ }
+
+ @Override
+ protected void handlePacket(byte[] recvbuf, int length) {
+ if (mSendIfaceParams == null) {
+ return;
+ }
+
+ // The BPF filter should already have checked the length of the packet, but...
+ if (length < IPV6_HEADER_LEN) {
+ return;
+ }
+ Inet6Address destv6 = getIpv6DestinationAddress(recvbuf);
+ if (!destv6.isMulticastAddress()) {
+ return;
+ }
+ InetSocketAddress dest = new InetSocketAddress(destv6, 0);
+
+ FileDescriptor fd = null;
+ try {
+ fd = Os.socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW);
+ SocketUtils.bindSocketToInterface(fd, mSendIfaceParams.name);
+
+ int ret = Os.sendto(fd, recvbuf, 0, length, 0, dest);
+ } catch (ErrnoException | SocketException e) {
+ Log.e(mTag, "handlePacket error: " + e);
+ } finally {
+ closeSocketQuietly(fd);
+ }
+ }
+}
diff --git a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
index 6f017dc..7c0b7cc7 100644
--- a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
+++ b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
@@ -18,6 +18,7 @@
import static android.net.util.NetworkConstants.IPV6_MIN_MTU;
import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
+import static android.net.util.TetheringUtils.getAllNodesForScopeId;
import static android.system.OsConstants.AF_INET6;
import static android.system.OsConstants.IPPROTO_ICMPV6;
import static android.system.OsConstants.SOCK_RAW;
@@ -44,7 +45,6 @@
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
-import java.net.UnknownHostException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -92,10 +92,6 @@
private static final int DAY_IN_SECONDS = 86_400;
- private static final byte[] ALL_NODES = new byte[] {
- (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
- };
-
private final InterfaceParams mInterface;
private final InetSocketAddress mAllNodes;
@@ -240,7 +236,6 @@
}
}
-
public RouterAdvertisementDaemon(InterfaceParams ifParams) {
mInterface = ifParams;
mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mInterface.index), 0);
@@ -363,15 +358,6 @@
}
}
- private static Inet6Address getAllNodesForScopeId(int scopeId) {
- try {
- return Inet6Address.getByAddress("ff02::1", ALL_NODES, scopeId);
- } catch (UnknownHostException uhe) {
- Log.wtf(TAG, "Failed to construct ff02::1 InetAddress: " + uhe);
- return null;
- }
- }
-
private static byte asByte(int value) {
return (byte) value;
}
diff --git a/packages/Tethering/src/android/net/util/TetheringUtils.java b/packages/Tethering/src/android/net/util/TetheringUtils.java
index b17b4ba..53b54f7 100644
--- a/packages/Tethering/src/android/net/util/TetheringUtils.java
+++ b/packages/Tethering/src/android/net/util/TetheringUtils.java
@@ -17,11 +17,15 @@
import android.net.TetherStatsParcel;
import android.net.TetheringRequestParcel;
+import android.util.Log;
import androidx.annotation.NonNull;
import java.io.FileDescriptor;
+import java.net.Inet6Address;
import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Arrays;
import java.util.Objects;
/**
@@ -30,6 +34,24 @@
* {@hide}
*/
public class TetheringUtils {
+ public static final byte[] ALL_NODES = new byte[] {
+ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+ };
+
+ /**
+ * Configures a socket for receiving and sending ICMPv6 neighbor advertisments.
+ * @param fd the socket's {@link FileDescriptor}.
+ */
+ public static native void setupNaSocket(FileDescriptor fd)
+ throws SocketException;
+
+ /**
+ * Configures a socket for receiving and sending ICMPv6 neighbor solicitations.
+ * @param fd the socket's {@link FileDescriptor}.
+ */
+ public static native void setupNsSocket(FileDescriptor fd)
+ throws SocketException;
+
/**
* The object which records offload Tx/Rx forwarded bytes/packets.
* TODO: Replace the inner class ForwardedStats of class OffloadHardwareInterface with
@@ -129,4 +151,15 @@
&& request.exemptFromEntitlementCheck == otherRequest.exemptFromEntitlementCheck
&& request.showProvisioningUi == otherRequest.showProvisioningUi;
}
+
+ /** Get inet6 address for all nodes given scope ID. */
+ public static Inet6Address getAllNodesForScopeId(int scopeId) {
+ try {
+ return Inet6Address.getByAddress("ff02::1", ALL_NODES, scopeId);
+ } catch (UnknownHostException uhe) {
+ Log.wtf("TetheringUtils", "Failed to construct Inet6Address from "
+ + Arrays.toString(ALL_NODES) + " and scopedId " + scopeId);
+ return null;
+ }
+ }
}
diff --git a/packages/Tethering/tests/integration/Android.bp b/packages/Tethering/tests/integration/Android.bp
index ed69b7d..02bab9b 100644
--- a/packages/Tethering/tests/integration/Android.bp
+++ b/packages/Tethering/tests/integration/Android.bp
@@ -22,7 +22,6 @@
static_libs: [
"NetworkStackApiStableLib",
"androidx.test.rules",
- "frameworks-base-testutils",
"mockito-target-extended-minus-junit4",
"net-tests-utils",
"testables",
diff --git a/packages/Tethering/tests/privileged/Android.bp b/packages/Tethering/tests/privileged/Android.bp
index a0fb246..9217345 100644
--- a/packages/Tethering/tests/privileged/Android.bp
+++ b/packages/Tethering/tests/privileged/Android.bp
@@ -14,8 +14,22 @@
// limitations under the License.
//
+java_defaults {
+ name: "TetheringPrivilegedTestsJniDefaults",
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ "libtetherutilsjni",
+ ],
+ jni_uses_sdk_apis: true,
+ visibility: ["//visibility:private"],
+}
+
android_test {
name: "TetheringPrivilegedTests",
+ defaults: [
+ "TetheringPrivilegedTestsJniDefaults",
+ ],
srcs: [
"src/**/*.java",
"src/**/*.kt",
@@ -23,8 +37,13 @@
certificate: "networkstack",
platform_apis: true,
test_suites: [
- "general-tests",
+ "device-tests",
"mts",
],
+ static_libs: [
+ "androidx.test.rules",
+ "net-tests-utils",
+ "TetheringApiCurrentLib",
+ ],
compile_multilib: "both",
}
diff --git a/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java b/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
new file mode 100644
index 0000000..747d3e8
--- /dev/null
+++ b/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.IPPROTO_TCP;
+
+import static com.android.internal.util.BitUtils.uint16;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.net.INetd;
+import android.net.InetAddresses;
+import android.net.MacAddress;
+import android.net.TestNetworkInterface;
+import android.net.TestNetworkManager;
+import android.net.util.InterfaceParams;
+import android.net.util.IpUtils;
+import android.net.util.TetheringUtils;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.system.ErrnoException;
+import android.system.Os;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.TapPacketReader;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+import java.io.FileDescriptor;
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicReference;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DadProxyTest {
+ private static final int DATA_BUFFER_LEN = 4096;
+ private static final int PACKET_TIMEOUT_MS = 5_000;
+
+ // TODO: make NetworkStackConstants accessible to this test and use the constant from there.
+ private static final int ETHER_SRC_ADDR_OFFSET = 6;
+
+ private DadProxy mProxy;
+ TestNetworkInterface mUpstreamTestIface, mTetheredTestIface;
+ private InterfaceParams mUpstreamParams, mTetheredParams;
+ private HandlerThread mHandlerThread;
+ private Handler mHandler;
+ private TapPacketReader mUpstreamPacketReader, mTetheredPacketReader;
+ private FileDescriptor mUpstreamTapFd, mTetheredTapFd;
+
+ private static INetd sNetd;
+
+ @BeforeClass
+ public static void setupOnce() {
+ System.loadLibrary("tetherutilsjni");
+
+ final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+ final IBinder netdIBinder =
+ (IBinder) inst.getContext().getSystemService(Context.NETD_SERVICE);
+ sNetd = INetd.Stub.asInterface(netdIBinder);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mHandlerThread = new HandlerThread(getClass().getSimpleName());
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+
+ setupTapInterfaces();
+
+ // Looper must be prepared here since AndroidJUnitRunner runs tests on separate threads.
+ if (Looper.myLooper() == null) Looper.prepare();
+
+ DadProxy mProxy = setupProxy();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mHandlerThread != null) {
+ mHandler.post(mUpstreamPacketReader::stop); // Also closes the socket
+ mHandler.post(mTetheredPacketReader::stop); // Also closes the socket
+ mUpstreamTapFd = null;
+ mTetheredTapFd = null;
+ mHandlerThread.quitSafely();
+ }
+
+ if (mTetheredParams != null) {
+ sNetd.networkRemoveInterface(INetd.LOCAL_NET_ID, mTetheredParams.name);
+ }
+ if (mUpstreamParams != null) {
+ sNetd.networkRemoveInterface(INetd.LOCAL_NET_ID, mUpstreamParams.name);
+ }
+
+ if (mUpstreamTestIface != null) {
+ try {
+ Os.close(mUpstreamTestIface.getFileDescriptor().getFileDescriptor());
+ } catch (ErrnoException e) { }
+ }
+
+ if (mTetheredTestIface != null) {
+ try {
+ Os.close(mTetheredTestIface.getFileDescriptor().getFileDescriptor());
+ } catch (ErrnoException e) { }
+ }
+ }
+
+ private TestNetworkInterface setupTapInterface() {
+ final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+ AtomicReference<TestNetworkInterface> iface = new AtomicReference<>();
+
+ inst.getUiAutomation().adoptShellPermissionIdentity();
+ try {
+ final TestNetworkManager tnm = (TestNetworkManager) inst.getContext().getSystemService(
+ Context.TEST_NETWORK_SERVICE);
+ iface.set(tnm.createTapInterface());
+ } finally {
+ inst.getUiAutomation().dropShellPermissionIdentity();
+ }
+
+ return iface.get();
+ }
+
+ private void setupTapInterfaces() {
+ // Create upstream test iface.
+ mUpstreamTestIface = setupTapInterface();
+ mUpstreamParams = InterfaceParams.getByName(mUpstreamTestIface.getInterfaceName());
+ assertNotNull(mUpstreamParams);
+ mUpstreamTapFd = mUpstreamTestIface.getFileDescriptor().getFileDescriptor();
+ mUpstreamPacketReader = new TapPacketReader(mHandler, mUpstreamTapFd,
+ DATA_BUFFER_LEN);
+ mHandler.post(mUpstreamPacketReader::start);
+
+ // Create tethered test iface.
+ mTetheredTestIface = setupTapInterface();
+ mTetheredParams = InterfaceParams.getByName(mTetheredTestIface.getInterfaceName());
+ assertNotNull(mTetheredParams);
+ mTetheredTapFd = mTetheredTestIface.getFileDescriptor().getFileDescriptor();
+ mTetheredPacketReader = new TapPacketReader(mHandler, mTetheredTapFd,
+ DATA_BUFFER_LEN);
+ mHandler.post(mTetheredPacketReader::start);
+ }
+
+ private static final int IPV6_HEADER_LEN = 40;
+ private static final int ETH_HEADER_LEN = 14;
+ private static final int ICMPV6_NA_NS_LEN = 24;
+ private static final int LL_TARGET_OPTION_LEN = 8;
+ private static final int ICMPV6_CHECKSUM_OFFSET = 2;
+ private static final int ETHER_TYPE_IPV6 = 0x86dd;
+
+ // TODO: move the IpUtils code to frameworks/lib/net and link it statically.
+ private static int checksumFold(int sum) {
+ while (sum > 0xffff) {
+ sum = (sum >> 16) + (sum & 0xffff);
+ }
+ return sum;
+ }
+
+ // TODO: move the IpUtils code to frameworks/lib/net and link it statically.
+ private static short checksumAdjust(short checksum, short oldWord, short newWord) {
+ checksum = (short) ~checksum;
+ int tempSum = checksumFold(uint16(checksum) + uint16(newWord) + 0xffff - uint16(oldWord));
+ return (short) ~tempSum;
+ }
+
+ // TODO: move the IpUtils code to frameworks/lib/net and link it statically.
+ private static short icmpv6Checksum(ByteBuffer buf, int ipOffset, int transportOffset,
+ int transportLen) {
+ // The ICMPv6 checksum is the same as the TCP checksum, except the pseudo-header uses
+ // 58 (ICMPv6) instead of 6 (TCP). Calculate the TCP checksum, and then do an incremental
+ // checksum adjustment for the change in the next header byte.
+ short checksum = IpUtils.tcpChecksum(buf, ipOffset, transportOffset, transportLen);
+ return checksumAdjust(checksum, (short) IPPROTO_TCP, (short) IPPROTO_ICMPV6);
+ }
+
+ private static ByteBuffer createDadPacket(int type) {
+ // Refer to buildArpPacket()
+ int icmpLen = ICMPV6_NA_NS_LEN
+ + (type == NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT
+ ? LL_TARGET_OPTION_LEN : 0);
+ final ByteBuffer buf = ByteBuffer.allocate(icmpLen + IPV6_HEADER_LEN + ETH_HEADER_LEN);
+
+ // Ethernet header.
+ final MacAddress srcMac = MacAddress.fromString("33:33:ff:66:77:88");
+ buf.put(srcMac.toByteArray());
+ final MacAddress dstMac = MacAddress.fromString("01:02:03:04:05:06");
+ buf.put(dstMac.toByteArray());
+ buf.putShort((short) ETHER_TYPE_IPV6);
+
+ // IPv6 header
+ byte[] version = {(byte) 0x60, 0x00, 0x00, 0x00};
+ buf.put(version); // Version
+ buf.putShort((byte) icmpLen); // Length
+ buf.put((byte) IPPROTO_ICMPV6); // Next header
+ buf.put((byte) 0xff); // Hop limit
+
+ final byte[] target =
+ InetAddresses.parseNumericAddress("fe80::1122:3344:5566:7788").getAddress();
+ final byte[] src;
+ final byte[] dst;
+ if (type == NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION) {
+ src = InetAddresses.parseNumericAddress("::").getAddress();
+ dst = InetAddresses.parseNumericAddress("ff02::1:ff66:7788").getAddress();
+ } else {
+ src = target;
+ dst = TetheringUtils.ALL_NODES;
+ }
+ buf.put(src);
+ buf.put(dst);
+
+ // ICMPv6 Header
+ buf.put((byte) type); // Type
+ buf.put((byte) 0x00); // Code
+ buf.putShort((short) 0); // Checksum
+ buf.putInt(0); // Reserved
+ buf.put(target);
+
+ if (type == NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT) {
+ //NA packet has LL target address
+ //ICMPv6 Option
+ buf.put((byte) 0x02); // Type
+ buf.put((byte) 0x01); // Length
+ byte[] ll_target = MacAddress.fromString("01:02:03:04:05:06").toByteArray();
+ buf.put(ll_target);
+ }
+
+ // Populate checksum field
+ final int transportOffset = ETH_HEADER_LEN + IPV6_HEADER_LEN;
+ final short checksum = icmpv6Checksum(buf, ETH_HEADER_LEN, transportOffset, icmpLen);
+ buf.putShort(transportOffset + ICMPV6_CHECKSUM_OFFSET, checksum);
+
+ buf.flip();
+ return buf;
+ }
+
+ private DadProxy setupProxy() throws Exception {
+ DadProxy proxy = new DadProxy(mHandler, mTetheredParams);
+ mHandler.post(() -> proxy.setUpstreamIface(mUpstreamParams));
+
+ // Upstream iface is added to local network to simplify test case.
+ // Otherwise the test needs to create and destroy a network for the upstream iface.
+ sNetd.networkAddInterface(INetd.LOCAL_NET_ID, mUpstreamParams.name);
+ sNetd.networkAddInterface(INetd.LOCAL_NET_ID, mTetheredParams.name);
+
+ return proxy;
+ }
+
+ // TODO: change to assert.
+ private boolean waitForPacket(ByteBuffer packet, TapPacketReader reader) {
+ byte[] p;
+
+ while ((p = reader.popPacket(PACKET_TIMEOUT_MS)) != null) {
+ final ByteBuffer buffer = ByteBuffer.wrap(p);
+
+ if (buffer.compareTo(packet) == 0) return true;
+ }
+ return false;
+ }
+
+ private void updateDstMac(ByteBuffer buf, MacAddress mac) {
+ buf.put(mac.toByteArray());
+ buf.rewind();
+ }
+ private void updateSrcMac(ByteBuffer buf, InterfaceParams ifaceParams) {
+ buf.position(ETHER_SRC_ADDR_OFFSET);
+ buf.put(ifaceParams.macAddr.toByteArray());
+ buf.rewind();
+ }
+
+ @Test
+ public void testNaForwardingFromUpstreamToTether() throws Exception {
+ ByteBuffer na = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT);
+
+ mUpstreamPacketReader.sendResponse(na);
+ updateDstMac(na, MacAddress.fromString("33:33:00:00:00:01"));
+ updateSrcMac(na, mTetheredParams);
+ assertTrue(waitForPacket(na, mTetheredPacketReader));
+ }
+
+ @Test
+ // TODO: remove test once DAD works in both directions.
+ public void testNaForwardingFromTetherToUpstream() throws Exception {
+ ByteBuffer na = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT);
+
+ mTetheredPacketReader.sendResponse(na);
+ updateDstMac(na, MacAddress.fromString("33:33:00:00:00:01"));
+ updateSrcMac(na, mTetheredParams);
+ assertFalse(waitForPacket(na, mUpstreamPacketReader));
+ }
+
+ @Test
+ public void testNsForwardingFromTetherToUpstream() throws Exception {
+ ByteBuffer ns = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION);
+
+ mTetheredPacketReader.sendResponse(ns);
+ updateSrcMac(ns, mUpstreamParams);
+ assertTrue(waitForPacket(ns, mUpstreamPacketReader));
+ }
+
+ @Test
+ // TODO: remove test once DAD works in both directions.
+ public void testNsForwardingFromUpstreamToTether() throws Exception {
+ ByteBuffer ns = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION);
+
+ mUpstreamPacketReader.sendResponse(ns);
+ updateSrcMac(ns, mUpstreamParams);
+ assertFalse(waitForPacket(ns, mTetheredPacketReader));
+ }
+}
diff --git a/packages/Tethering/tests/unit/jarjar-rules.txt b/packages/Tethering/tests/unit/jarjar-rules.txt
index ec2d2b0..7ed8963 100644
--- a/packages/Tethering/tests/unit/jarjar-rules.txt
+++ b/packages/Tethering/tests/unit/jarjar-rules.txt
@@ -9,3 +9,8 @@
rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1
rule android.util.LocalLog* com.android.networkstack.tethering.util.LocalLog@1
+
+# TODO: either stop using frameworks-base-testutils or remove the unit test classes it contains.
+# TestableLooper from "testables" can be used instead of TestLooper from frameworks-base-testutils.
+zap android.os.test.TestLooperTest*
+zap com.android.test.filters.SelectTestTests*
\ No newline at end of file
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 3b72b5b..1a976ad 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -86,6 +86,7 @@
import android.net.util.InterfaceSet;
import android.net.util.PrefixUtils;
import android.net.util.SharedLog;
+import android.os.Build;
import android.os.Handler;
import android.os.RemoteException;
import android.os.test.TestLooper;
@@ -100,8 +101,12 @@
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
import com.android.networkstack.tethering.PrivateAddressCoordinator;
import com.android.networkstack.tethering.TetheringConfiguration;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -120,6 +125,9 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public class IpServerTest {
+ @Rule
+ public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
+
private static final String IFACE_NAME = "testnet1";
private static final String UPSTREAM_IFACE = "upstream0";
private static final String UPSTREAM_IFACE2 = "upstream1";
@@ -132,6 +140,11 @@
private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams(
IFACE_NAME, 42 /* index */, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */);
+ private static final InterfaceParams UPSTREAM_IFACE_PARAMS = new InterfaceParams(
+ UPSTREAM_IFACE, UPSTREAM_IFINDEX, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */);
+ private static final InterfaceParams UPSTREAM_IFACE_PARAMS2 = new InterfaceParams(
+ UPSTREAM_IFACE2, UPSTREAM_IFINDEX2, MacAddress.ALL_ZEROS_ADDRESS,
+ 1500 /* defaultMtu */);
private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000;
@@ -142,6 +155,7 @@
@Mock private IpServer.Callback mCallback;
@Mock private SharedLog mSharedLog;
@Mock private IDhcpServer mDhcpServer;
+ @Mock private DadProxy mDadProxy;
@Mock private RouterAdvertisementDaemon mRaDaemon;
@Mock private IpNeighborMonitor mIpNeighborMonitor;
@Mock private IpServer.Dependencies mDependencies;
@@ -165,8 +179,11 @@
private void initStateMachine(int interfaceType, boolean usingLegacyDhcp,
boolean usingBpfOffload) throws Exception {
+ when(mDependencies.getDadProxy(any(), any())).thenReturn(mDadProxy);
when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
+ when(mDependencies.getInterfaceParams(UPSTREAM_IFACE)).thenReturn(UPSTREAM_IFACE_PARAMS);
+ when(mDependencies.getInterfaceParams(UPSTREAM_IFACE2)).thenReturn(UPSTREAM_IFACE_PARAMS2);
when(mDependencies.getIfindex(eq(UPSTREAM_IFACE))).thenReturn(UPSTREAM_IFINDEX);
when(mDependencies.getIfindex(eq(UPSTREAM_IFACE2))).thenReturn(UPSTREAM_IFINDEX2);
@@ -1103,4 +1120,78 @@
}
return true;
}
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void dadProxyUpdates() throws Exception {
+ InOrder inOrder = inOrder(mDadProxy);
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
+ inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
+
+ // Add an upstream without IPv6.
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE, null, 0);
+ inOrder.verify(mDadProxy).setUpstreamIface(null);
+
+ // Add IPv6 to the upstream.
+ LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(UPSTREAM_IFACE);
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, 0);
+ inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
+
+ // Change upstream.
+ // New linkproperties is needed, otherwise changing the iface has no impact.
+ LinkProperties lp2 = new LinkProperties();
+ lp2.setInterfaceName(UPSTREAM_IFACE2);
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp2, 0);
+ inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS2);
+
+ // Lose IPv6 on the upstream...
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE2, null, 0);
+ inOrder.verify(mDadProxy).setUpstreamIface(null);
+
+ // ... and regain it on a different upstream.
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, 0);
+ inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
+
+ // Lose upstream.
+ dispatchTetherConnectionChanged(null, null, 0);
+ inOrder.verify(mDadProxy).setUpstreamIface(null);
+
+ // Regain upstream.
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, 0);
+ inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
+
+ // Stop tethering.
+ mIpServer.stop();
+ mLooper.dispatchAll();
+ }
+
+ private void checkDadProxyEnabled(boolean expectEnabled) throws Exception {
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
+ InOrder inOrder = inOrder(mDadProxy);
+ // Add IPv6 to the upstream.
+ LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(UPSTREAM_IFACE);
+ if (expectEnabled) {
+ inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
+ } else {
+ inOrder.verifyNoMoreInteractions();
+ }
+ // Stop tethering.
+ mIpServer.stop();
+ mLooper.dispatchAll();
+ if (expectEnabled) {
+ inOrder.verify(mDadProxy).stop();
+ }
+ else {
+ verify(mDependencies, never()).getDadProxy(any(), any());
+ }
+ }
+ @Test @IgnoreAfter(Build.VERSION_CODES.R)
+ public void testDadProxyUpdates_DisabledUpToR() throws Exception {
+ checkDadProxyEnabled(false);
+ }
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testDadProxyUpdates_EnabledAfterR() throws Exception {
+ checkDadProxyEnabled(true);
+ }
}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 1fe3840..df57020 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -110,6 +110,7 @@
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpServer;
+import android.net.ip.DadProxy;
import android.net.ip.IpNeighborMonitor;
import android.net.ip.IpServer;
import android.net.ip.RouterAdvertisementDaemon;
@@ -196,6 +197,7 @@
@Mock private CarrierConfigManager mCarrierConfigManager;
@Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
@Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator;
+ @Mock private DadProxy mDadProxy;
@Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon;
@Mock private IpNeighborMonitor mIpNeighborMonitor;
@Mock private IDhcpServer mDhcpServer;
@@ -280,6 +282,12 @@
public class MockIpServerDependencies extends IpServer.Dependencies {
@Override
+ public DadProxy getDadProxy(
+ Handler handler, InterfaceParams ifParams) {
+ return mDadProxy;
+ }
+
+ @Override
public RouterAdvertisementDaemon getRouterAdvertisementDaemon(
InterfaceParams ifParams) {
return mRouterAdvertisementDaemon;
@@ -832,6 +840,7 @@
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
sendIPv6TetherUpdates(upstreamState);
+ verify(mDadProxy, never()).setUpstreamIface(notNull());
verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull());
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks(
any(), any());
@@ -858,6 +867,8 @@
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
sendIPv6TetherUpdates(upstreamState);
+ // TODO: add interfaceParams to compare in verify.
+ verify(mDadProxy, times(1)).setUpstreamIface(notNull());
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
verify(mNetd, times(1)).tetherApplyDnsInterfaces();
}
@@ -874,6 +885,7 @@
any(), any());
sendIPv6TetherUpdates(upstreamState);
+ verify(mDadProxy, times(1)).setUpstreamIface(notNull());
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
verify(mNetd, times(1)).tetherApplyDnsInterfaces();
}
@@ -891,6 +903,7 @@
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
sendIPv6TetherUpdates(upstreamState);
+ verify(mDadProxy, times(1)).setUpstreamIface(notNull());
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
verify(mNetd, times(1)).tetherApplyDnsInterfaces();
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 2e4d44c..bb567b4 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -412,7 +412,8 @@
if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
if (DBG) {
- Slog.d(TAG, "Bluetooth Adapter name changed to " + newName);
+ Slog.d(TAG, "Bluetooth Adapter name changed to " + newName + " by "
+ + mContext.getPackageName());
}
if (newName != null) {
storeNameAndAddress(newName, null);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index aeb8fbb..8a1baf2 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -5875,10 +5875,6 @@
return nai == getDefaultNetwork();
}
- private boolean isDefaultRequest(NetworkRequestInfo nri) {
- return nri.request.requestId == mDefaultRequest.requestId;
- }
-
// TODO : remove this method. It's a stopgap measure to help sheperding a number of dependent
// changes that would conflict throughout the automerger graph. Having this method temporarily
// helps with the process of going through with all these dependent changes across the entire
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 208c943..fd5a621 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -89,6 +89,7 @@
import com.android.internal.telephony.IPhoneStateListener;
import com.android.internal.telephony.ITelephonyRegistry;
import com.android.internal.telephony.TelephonyPermissions;
+import com.android.internal.telephony.util.TelephonyUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
@@ -1723,7 +1724,7 @@
&& (mDataConnectionState[phoneId] != state
|| mDataConnectionNetworkType[phoneId] != networkType)) {
String str = "onDataConnectionStateChanged("
- + dataStateToString(state)
+ + TelephonyUtils.dataStateToString(state)
+ ", " + getNetworkTypeName(networkType)
+ ") subId=" + subId + ", phoneId=" + phoneId;
log(str);
@@ -2580,7 +2581,7 @@
// status bar takes care of that after taking into account all of the
// required info.
Intent intent = new Intent(ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
- intent.putExtra(PHONE_CONSTANTS_STATE_KEY, dataStateToString(state));
+ intent.putExtra(PHONE_CONSTANTS_STATE_KEY, TelephonyUtils.dataStateToString(state));
intent.putExtra(PHONE_CONSTANTS_DATA_APN_KEY, apn);
intent.putExtra(PHONE_CONSTANTS_DATA_APN_TYPE_KEY,
ApnSetting.getApnTypesStringFromBitmask(apnType));
@@ -2938,21 +2939,6 @@
}
/**
- * Convert TelephonyManager.DATA_* to string.
- *
- * @return The data state in string format.
- */
- private static String dataStateToString(int state) {
- switch (state) {
- case TelephonyManager.DATA_DISCONNECTED: return "DISCONNECTED";
- case TelephonyManager.DATA_CONNECTING: return "CONNECTING";
- case TelephonyManager.DATA_CONNECTED: return "CONNECTED";
- case TelephonyManager.DATA_SUSPENDED: return "SUSPENDED";
- }
- return "UNKNOWN(" + state + ")";
- }
-
- /**
* Returns a string representation of the radio technology (network type)
* currently in use on the device.
* @param subId for which network type is returned
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a3fbd2c..09c0ba37 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13738,10 +13738,10 @@
}
long kernelUsed = memInfo.getKernelUsedSizeKb();
final long ionHeap = Debug.getIonHeapsSizeKb();
- if (ionHeap > 0) {
+ final long ionPool = Debug.getIonPoolsSizeKb();
+ if (ionHeap >= 0 && ionPool >= 0) {
final long ionMapped = Debug.getIonMappedSizeKb();
final long ionUnmapped = ionHeap - ionMapped;
- final long ionPool = Debug.getIonPoolsSizeKb();
pw.print(" ION: ");
pw.print(stringifyKBSize(ionHeap + ionPool));
pw.print(" (");
@@ -14552,10 +14552,10 @@
memInfoBuilder.append("\n");
long kernelUsed = memInfo.getKernelUsedSizeKb();
final long ionHeap = Debug.getIonHeapsSizeKb();
- if (ionHeap > 0) {
+ final long ionPool = Debug.getIonPoolsSizeKb();
+ if (ionHeap >= 0 && ionPool >= 0) {
final long ionMapped = Debug.getIonMappedSizeKb();
final long ionUnmapped = ionHeap - ionMapped;
- final long ionPool = Debug.getIonPoolsSizeKb();
memInfoBuilder.append(" ION: ");
memInfoBuilder.append(stringifyKBSize(ionHeap + ionPool));
memInfoBuilder.append("\n");
diff --git a/services/core/java/com/android/server/am/PendingTempWhitelists.java b/services/core/java/com/android/server/am/PendingTempWhitelists.java
index b36e3c7..50d58f0 100644
--- a/services/core/java/com/android/server/am/PendingTempWhitelists.java
+++ b/services/core/java/com/android/server/am/PendingTempWhitelists.java
@@ -32,13 +32,13 @@
void put(int uid, ActivityManagerService.PendingTempWhitelist value) {
mPendingTempWhitelist.put(uid, value);
- mService.mAtmInternal.onUidAddedToPendingTempWhitelist(uid, value.tag);
+ mService.mAtmInternal.onUidAddedToPendingTempAllowlist(uid, value.tag);
}
void removeAt(int index) {
final int uid = mPendingTempWhitelist.keyAt(index);
mPendingTempWhitelist.removeAt(index);
- mService.mAtmInternal.onUidRemovedFromPendingTempWhitelist(uid);
+ mService.mAtmInternal.onUidRemovedFromPendingTempAllowlist(uid);
}
ActivityManagerService.PendingTempWhitelist get(int uid) {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 6eab022..42af4da 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1786,9 +1786,9 @@
}
}
}
-
- mHistoricalRegistry.clearHistory(uid, packageName);
}
+
+ mHistoricalRegistry.clearHistory(uid, packageName);
}
public void uidRemoved(int uid) {
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 1f0066a..01fa9e7 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -367,6 +367,13 @@
Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network);
}
}
+ // Ignore the case when the network disconnects immediately after stop() has been
+ // called and the keepalive code is waiting for the response from the modem. This
+ // might happen when the caller listens for a lower-layer network disconnect
+ // callback and stop the keepalive at that time. But the stop() races with the
+ // stop() generated in ConnectivityService network disconnection code path.
+ if (mStartedState == STOPPING && reason == ERROR_INVALID_NETWORK) return;
+
// Store the reason of stopping, and report it after the keepalive is fully stopped.
if (mStopReason != ERROR_STOP_REASON_UNINITIALIZED) {
throw new IllegalStateException("Unexpected stop reason: " + mStopReason);
@@ -380,9 +387,6 @@
// e.g. invalid parameter.
cleanupStoppedKeepalive(mNai, mSlot);
break;
- case STOPPING:
- // Keepalive is already in stopping state, ignore.
- return;
default:
mStartedState = STOPPING;
switch (mType) {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 5484bfc..9817abf 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -256,8 +256,8 @@
@GuardedBy("this")
private final Set<UidRange> mBlockedUidsAsToldToNetd = new ArraySet<>();
- // Handle of the user initiating VPN.
- private final int mUserHandle;
+ // The user id of initiating VPN.
+ private final int mUserId;
interface RetryScheduler {
void checkInterruptAndDelay(boolean sleepLonger) throws InterruptedException;
@@ -384,26 +384,26 @@
}
public Vpn(Looper looper, Context context, INetworkManagementService netService,
- @UserIdInt int userHandle, @NonNull KeyStore keyStore) {
- this(looper, context, new Dependencies(), netService, userHandle, keyStore,
+ @UserIdInt int userId, @NonNull KeyStore keyStore) {
+ this(looper, context, new Dependencies(), netService, userId, keyStore,
new SystemServices(context), new Ikev2SessionCreator());
}
@VisibleForTesting
protected Vpn(Looper looper, Context context, Dependencies deps,
INetworkManagementService netService,
- int userHandle, @NonNull KeyStore keyStore, SystemServices systemServices,
+ int userId, @NonNull KeyStore keyStore, SystemServices systemServices,
Ikev2SessionCreator ikev2SessionCreator) {
mContext = context;
mDeps = deps;
mNetd = netService;
- mUserHandle = userHandle;
+ mUserId = userId;
mLooper = looper;
mSystemServices = systemServices;
mIkev2SessionCreator = ikev2SessionCreator;
mPackage = VpnConfig.LEGACY_VPN;
- mOwnerUID = getAppUid(mPackage, mUserHandle);
+ mOwnerUID = getAppUid(mPackage, mUserId);
mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(mPackage);
try {
@@ -613,7 +613,7 @@
PackageManager pm = mContext.getPackageManager();
ApplicationInfo appInfo = null;
try {
- appInfo = pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserHandle);
+ appInfo = pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserId);
} catch (NameNotFoundException unused) {
Log.w(TAG, "Can't find \"" + packageName + "\" when checking always-on support");
}
@@ -624,7 +624,7 @@
final Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE);
intent.setPackage(packageName);
List<ResolveInfo> services =
- pm.queryIntentServicesAsUser(intent, PackageManager.GET_META_DATA, mUserHandle);
+ pm.queryIntentServicesAsUser(intent, PackageManager.GET_META_DATA, mUserId);
if (services == null || services.size() == 0) {
return false;
}
@@ -769,12 +769,12 @@
final long token = Binder.clearCallingIdentity();
try {
mSystemServices.settingsSecurePutStringForUser(Settings.Secure.ALWAYS_ON_VPN_APP,
- getAlwaysOnPackage(), mUserHandle);
+ getAlwaysOnPackage(), mUserId);
mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
- (mAlwaysOn && mLockdown ? 1 : 0), mUserHandle);
+ (mAlwaysOn && mLockdown ? 1 : 0), mUserId);
mSystemServices.settingsSecurePutStringForUser(
LOCKDOWN_ALLOWLIST_SETTING_NAME,
- String.join(",", mLockdownAllowlist), mUserHandle);
+ String.join(",", mLockdownAllowlist), mUserId);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -786,11 +786,11 @@
final long token = Binder.clearCallingIdentity();
try {
final String alwaysOnPackage = mSystemServices.settingsSecureGetStringForUser(
- Settings.Secure.ALWAYS_ON_VPN_APP, mUserHandle);
+ Settings.Secure.ALWAYS_ON_VPN_APP, mUserId);
final boolean alwaysOnLockdown = mSystemServices.settingsSecureGetIntForUser(
- Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserHandle) != 0;
+ Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserId) != 0;
final String allowlistString = mSystemServices.settingsSecureGetStringForUser(
- LOCKDOWN_ALLOWLIST_SETTING_NAME, mUserHandle);
+ LOCKDOWN_ALLOWLIST_SETTING_NAME, mUserId);
final List<String> allowedPackages = TextUtils.isEmpty(allowlistString)
? Collections.emptyList() : Arrays.asList(allowlistString.split(","));
setAlwaysOnPackageInternal(
@@ -850,13 +850,13 @@
DeviceIdleInternal idleController =
LocalServices.getService(DeviceIdleInternal.class);
idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage,
- VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS, mUserHandle, false, "vpn");
+ VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS, mUserId, false, "vpn");
// Start the VPN service declared in the app's manifest.
Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE);
serviceIntent.setPackage(alwaysOnPackage);
try {
- return mContext.startServiceAsUser(serviceIntent, UserHandle.of(mUserHandle)) != null;
+ return mContext.startServiceAsUser(serviceIntent, UserHandle.of(mUserId)) != null;
} catch (RuntimeException e) {
Log.e(TAG, "VpnService " + serviceIntent + " failed to start", e);
return false;
@@ -958,7 +958,7 @@
// We can't just check that packageName matches mPackage, because if the app was uninstalled
// and reinstalled it will no longer be prepared. Similarly if there is a shared UID, the
// calling package may not be the same as the prepared package. Check both UID and package.
- return getAppUid(packageName, mUserHandle) == mOwnerUID && mPackage.equals(packageName);
+ return getAppUid(packageName, mUserId) == mOwnerUID && mPackage.equals(packageName);
}
/** Prepare the VPN for the given package. Does not perform permission checks. */
@@ -998,7 +998,7 @@
Log.i(TAG, "Switched from " + mPackage + " to " + newPackage);
mPackage = newPackage;
- mOwnerUID = getAppUid(newPackage, mUserHandle);
+ mOwnerUID = getAppUid(newPackage, mUserId);
mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(newPackage);
try {
mNetd.allowProtect(mOwnerUID);
@@ -1019,7 +1019,7 @@
// Check if the caller is authorized.
enforceControlPermissionOrInternalCaller();
- final int uid = getAppUid(packageName, mUserHandle);
+ final int uid = getAppUid(packageName, mUserId);
if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) {
// Authorization for nonexistent packages (or fake ones) can't be updated.
return false;
@@ -1095,14 +1095,14 @@
|| isVpnServicePreConsented(context, packageName);
}
- private int getAppUid(final String app, final int userHandle) {
+ private int getAppUid(final String app, final int userId) {
if (VpnConfig.LEGACY_VPN.equals(app)) {
return Process.myUid();
}
PackageManager pm = mContext.getPackageManager();
return Binder.withCleanCallingIdentity(() -> {
try {
- return pm.getPackageUidAsUser(app, userHandle);
+ return pm.getPackageUidAsUser(app, userId);
} catch (NameNotFoundException e) {
return -1;
}
@@ -1116,7 +1116,7 @@
PackageManager pm = mContext.getPackageManager();
try {
ApplicationInfo appInfo =
- pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserHandle);
+ pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserId);
return appInfo.targetSdkVersion >= VERSION_CODES.Q;
} catch (NameNotFoundException unused) {
Log.w(TAG, "Can't find \"" + packageName + "\"");
@@ -1241,7 +1241,7 @@
mNetworkCapabilities.setOwnerUid(mOwnerUID);
mNetworkCapabilities.setAdministratorUids(new int[] {mOwnerUID});
- mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserHandle,
+ mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserId,
mConfig.allowedApplications, mConfig.disallowedApplications));
long token = Binder.clearCallingIdentity();
try {
@@ -1315,7 +1315,7 @@
enforceNotRestrictedUser();
ResolveInfo info = AppGlobals.getPackageManager().resolveService(intent,
- null, 0, mUserHandle);
+ null, 0, mUserId);
if (info == null) {
throw new SecurityException("Cannot find " + config.user);
}
@@ -1352,7 +1352,7 @@
Connection connection = new Connection();
if (!mContext.bindServiceAsUser(intent, connection,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
- new UserHandle(mUserHandle))) {
+ new UserHandle(mUserId))) {
throw new IllegalStateException("Cannot bind " + config.user);
}
@@ -1427,10 +1427,10 @@
}
// Note: Return type guarantees results are deduped and sorted, which callers require.
- private SortedSet<Integer> getAppsUids(List<String> packageNames, int userHandle) {
+ private SortedSet<Integer> getAppsUids(List<String> packageNames, int userId) {
SortedSet<Integer> uids = new TreeSet<>();
for (String app : packageNames) {
- int uid = getAppUid(app, userHandle);
+ int uid = getAppUid(app, userId);
if (uid != -1) uids.add(uid);
}
return uids;
@@ -1444,22 +1444,22 @@
* the UID ranges will match the app list specified there. Otherwise, all UIDs
* in each user and profile will be included.
*
- * @param userHandle The userId to create UID ranges for along with any of its restricted
+ * @param userId The userId to create UID ranges for along with any of its restricted
* profiles.
* @param allowedApplications (optional) List of applications to allow.
* @param disallowedApplications (optional) List of applications to deny.
*/
@VisibleForTesting
- Set<UidRange> createUserAndRestrictedProfilesRanges(@UserIdInt int userHandle,
+ Set<UidRange> createUserAndRestrictedProfilesRanges(@UserIdInt int userId,
@Nullable List<String> allowedApplications,
@Nullable List<String> disallowedApplications) {
final Set<UidRange> ranges = new ArraySet<>();
// Assign the top-level user to the set of ranges
- addUserToRanges(ranges, userHandle, allowedApplications, disallowedApplications);
+ addUserToRanges(ranges, userId, allowedApplications, disallowedApplications);
// If the user can have restricted profiles, assign all its restricted profiles too
- if (canHaveRestrictedProfile(userHandle)) {
+ if (canHaveRestrictedProfile(userId)) {
final long token = Binder.clearCallingIdentity();
List<UserInfo> users;
try {
@@ -1468,7 +1468,7 @@
Binder.restoreCallingIdentity(token);
}
for (UserInfo user : users) {
- if (user.isRestricted() && (user.restrictedProfileParentId == userHandle)) {
+ if (user.isRestricted() && (user.restrictedProfileParentId == userId)) {
addUserToRanges(ranges, user.id, allowedApplications, disallowedApplications);
}
}
@@ -1485,18 +1485,18 @@
* in the user will be included.
*
* @param ranges {@link Set} of {@link UidRange}s to which to add.
- * @param userHandle The userId to add to {@param ranges}.
+ * @param userId The userId to add to {@param ranges}.
* @param allowedApplications (optional) allowlist of applications to include.
* @param disallowedApplications (optional) denylist of applications to exclude.
*/
@VisibleForTesting
- void addUserToRanges(@NonNull Set<UidRange> ranges, @UserIdInt int userHandle,
+ void addUserToRanges(@NonNull Set<UidRange> ranges, @UserIdInt int userId,
@Nullable List<String> allowedApplications,
@Nullable List<String> disallowedApplications) {
if (allowedApplications != null) {
// Add ranges covering all UIDs for allowedApplications.
int start = -1, stop = -1;
- for (int uid : getAppsUids(allowedApplications, userHandle)) {
+ for (int uid : getAppsUids(allowedApplications, userId)) {
if (start == -1) {
start = uid;
} else if (uid != stop + 1) {
@@ -1508,9 +1508,9 @@
if (start != -1) ranges.add(new UidRange(start, stop));
} else if (disallowedApplications != null) {
// Add all ranges for user skipping UIDs for disallowedApplications.
- final UidRange userRange = UidRange.createForUser(userHandle);
+ final UidRange userRange = UidRange.createForUser(userId);
int start = userRange.start;
- for (int uid : getAppsUids(disallowedApplications, userHandle)) {
+ for (int uid : getAppsUids(disallowedApplications, userId)) {
if (uid == start) {
start++;
} else {
@@ -1521,16 +1521,16 @@
if (start <= userRange.stop) ranges.add(new UidRange(start, userRange.stop));
} else {
// Add all UIDs for the user.
- ranges.add(UidRange.createForUser(userHandle));
+ ranges.add(UidRange.createForUser(userId));
}
}
// Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that
- // apply to userHandle.
- static private List<UidRange> uidRangesForUser(int userHandle, Set<UidRange> existingRanges) {
+ // apply to userId.
+ private static List<UidRange> uidRangesForUser(int userId, Set<UidRange> existingRanges) {
// UidRange#createForUser returns the entire range of UIDs available to a macro-user.
// This is something like 0-99999 ; {@see UserHandle#PER_USER_RANGE}
- final UidRange userRange = UidRange.createForUser(userHandle);
+ final UidRange userRange = UidRange.createForUser(userId);
final List<UidRange> ranges = new ArrayList<>();
for (UidRange range : existingRanges) {
if (userRange.containsRange(range)) {
@@ -1545,15 +1545,15 @@
*
* <p>Should be called on primary ConnectivityService thread.
*/
- public void onUserAdded(int userHandle) {
+ public void onUserAdded(int userId) {
// If the user is restricted tie them to the parent user's VPN
- UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
- if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
+ UserInfo user = UserManager.get(mContext).getUserInfo(userId);
+ if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
synchronized(Vpn.this) {
final Set<UidRange> existingRanges = mNetworkCapabilities.getUids();
if (existingRanges != null) {
try {
- addUserToRanges(existingRanges, userHandle, mConfig.allowedApplications,
+ addUserToRanges(existingRanges, userId, mConfig.allowedApplications,
mConfig.disallowedApplications);
// ConnectivityService will call {@link #updateCapabilities} and apply
// those for VPN network.
@@ -1572,16 +1572,16 @@
*
* <p>Should be called on primary ConnectivityService thread.
*/
- public void onUserRemoved(int userHandle) {
+ public void onUserRemoved(int userId) {
// clean up if restricted
- UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
- if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
+ UserInfo user = UserManager.get(mContext).getUserInfo(userId);
+ if (user.isRestricted() && user.restrictedProfileParentId == mUserId) {
synchronized(Vpn.this) {
final Set<UidRange> existingRanges = mNetworkCapabilities.getUids();
if (existingRanges != null) {
try {
final List<UidRange> removedRanges =
- uidRangesForUser(userHandle, existingRanges);
+ uidRangesForUser(userId, existingRanges);
existingRanges.removeAll(removedRanges);
// ConnectivityService will call {@link #updateCapabilities} and
// apply those for VPN network.
@@ -1639,7 +1639,7 @@
final Set<UidRange> rangesToTellNetdToAdd;
if (enforce) {
final Set<UidRange> rangesThatShouldBeBlocked =
- createUserAndRestrictedProfilesRanges(mUserHandle,
+ createUserAndRestrictedProfilesRanges(mUserId,
/* allowedApplications */ null,
/* disallowedApplications */ exemptedPackages);
@@ -1909,7 +1909,7 @@
private void updateAlwaysOnNotification(DetailedState networkState) {
final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED);
- final UserHandle user = UserHandle.of(mUserHandle);
+ final UserHandle user = UserHandle.of(mUserId);
final long token = Binder.clearCallingIdentity();
try {
final NotificationManager notificationManager = NotificationManager.from(mContext);
@@ -2019,7 +2019,7 @@
private void enforceNotRestrictedUser() {
Binder.withCleanCallingIdentity(() -> {
final UserManager mgr = UserManager.get(mContext);
- final UserInfo user = mgr.getUserInfo(mUserHandle);
+ final UserInfo user = mgr.getUserInfo(mUserId);
if (user.isRestricted()) {
throw new SecurityException("Restricted users cannot configure VPNs");
@@ -2054,9 +2054,9 @@
public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore,
LinkProperties egress) {
UserManager mgr = UserManager.get(mContext);
- UserInfo user = mgr.getUserInfo(mUserHandle);
+ UserInfo user = mgr.getUserInfo(mUserId);
if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN,
- new UserHandle(mUserHandle))) {
+ new UserHandle(mUserId))) {
throw new SecurityException("Restricted users cannot establish VPNs");
}
@@ -2984,14 +2984,14 @@
}
private void verifyCallingUidAndPackage(String packageName) {
- if (getAppUid(packageName, mUserHandle) != Binder.getCallingUid()) {
+ if (getAppUid(packageName, mUserId) != Binder.getCallingUid()) {
throw new SecurityException("Mismatched package and UID");
}
}
@VisibleForTesting
String getProfileNameForPackage(String packageName) {
- return Credentials.PLATFORM_VPN + mUserHandle + "_" + packageName;
+ return Credentials.PLATFORM_VPN + mUserId + "_" + packageName;
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index 0b4f31d..28bd97e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -117,14 +117,15 @@
// TODO: Validate more than length for the following messages.
// Messages for the One Touch Record.
- FixedLengthValidator oneByteValidator = new FixedLengthValidator(1);
addValidationInfo(Constants.MESSAGE_RECORD_ON,
new VariableLengthValidator(1, 8), DEST_DIRECT);
- addValidationInfo(Constants.MESSAGE_RECORD_STATUS, oneByteValidator, DEST_DIRECT);
+ addValidationInfo(Constants.MESSAGE_RECORD_STATUS,
+ new RecordStatusInfoValidator(), DEST_DIRECT);
// TODO: Handle messages for the Timer Programming.
// Messages for the System Information.
+ FixedLengthValidator oneByteValidator = new FixedLengthValidator(1);
addValidationInfo(Constants.MESSAGE_CEC_VERSION, oneByteValidator, DEST_DIRECT);
addValidationInfo(Constants.MESSAGE_SET_MENU_LANGUAGE,
new FixedLengthValidator(3), DEST_BROADCAST);
@@ -339,4 +340,23 @@
isValidPhysicalAddress(params, 0) && isValidPhysicalAddress(params, 2));
}
}
+
+ /**
+ * Check if the given record status message parameter is valid.
+ * A valid parameter should lie within the range description of Record Status Info defined in
+ * CEC 1.4 Specification : Operand Descriptions (Section 17)
+ */
+ private class RecordStatusInfoValidator implements ParameterValidator {
+ @Override
+ public int isValid(byte[] params) {
+ if (params.length < 1) {
+ return ERROR_PARAMETER_SHORT;
+ }
+ return toErrorCode(isWithinRange(params[0], 0x01, 0x07)
+ || isWithinRange(params[0], 0x09, 0x0E)
+ || isWithinRange(params[0], 0x10, 0x17)
+ || isWithinRange(params[0], 0x1A, 0x1B)
+ || params[0] == 0x1F);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 3e9377e..b79953e 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -70,7 +70,7 @@
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.content.pm.ActivityInfo.PERSIST_ACROSS_REBOOTS;
import static android.content.pm.ActivityInfo.PERSIST_ROOT_ONLY;
@@ -1679,7 +1679,7 @@
if (options != null) {
final boolean useLockTask = options.getLockTaskMode();
if (useLockTask && lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_DEFAULT) {
- lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+ lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
}
}
return lockTaskLaunchMode;
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 6bfcf0c..3dd82a6 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -75,9 +75,9 @@
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_ALLOWLISTED;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_WHITELISTED;
import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -788,7 +788,7 @@
final LockTaskController lockTaskController = mService.getLockTaskController();
if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
|| task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV
- || (task.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED
+ || (task.mLockTaskAuth == LOCK_TASK_AUTH_ALLOWLISTED
&& lockTaskController.getLockTaskModeState()
== LOCK_TASK_MODE_LOCKED)) {
lockTaskController.startLockTaskMode(task, false, 0 /* blank UID */);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index d5df906..9125d90 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -510,8 +510,8 @@
public abstract void onActiveUidsCleared();
public abstract void onUidProcStateChanged(int uid, int procState);
- public abstract void onUidAddedToPendingTempWhitelist(int uid, String tag);
- public abstract void onUidRemovedFromPendingTempWhitelist(int uid);
+ public abstract void onUidAddedToPendingTempAllowlist(int uid, String tag);
+ public abstract void onUidRemovedFromPendingTempAllowlist(int uid);
/** Handle app crash event in {@link android.app.IActivityController} if there is one. */
public abstract boolean handleAppCrashInActivityController(String processName, int pid,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 205523b..ffbf6dd 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -386,7 +386,7 @@
private AppOpsManager mAppOpsManager;
/** All active uids in the system. */
private final MirrorActiveUids mActiveUids = new MirrorActiveUids();
- private final SparseArray<String> mPendingTempWhitelist = new SparseArray<>();
+ private final SparseArray<String> mPendingTempAllowlist = new SparseArray<>();
/** All processes currently running that might have a window organized by name. */
final ProcessMap<WindowProcessController> mProcessNames = new ProcessMap<>();
/** All processes we currently have running mapped by pid and uid */
@@ -1103,7 +1103,7 @@
@Override
public int startActivityIntentSender(IApplicationThread caller, IIntentSender target,
- IBinder whitelistToken, Intent fillInIntent, String resolvedType, IBinder resultTo,
+ IBinder allowlistToken, Intent fillInIntent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle bOptions) {
enforceNotIsolatedCaller("startActivityIntentSender");
// Refuse possible leaked file descriptors
@@ -1126,7 +1126,7 @@
mAppSwitchesAllowedTime = 0;
}
}
- return pir.sendInner(0, fillInIntent, resolvedType, whitelistToken, null, null,
+ return pir.sendInner(0, fillInIntent, resolvedType, allowlistToken, null, null,
resultTo, resultWho, requestCode, flagsMask, flagsValues, bOptions);
}
@@ -3035,7 +3035,7 @@
// system or a specific app.
// * System-initiated requests will only start the pinned mode (screen pinning)
// * App-initiated requests
- // - will put the device in fully locked mode (LockTask), if the app is whitelisted
+ // - will put the device in fully locked mode (LockTask), if the app is allowlisted
// - will start the pinned mode, otherwise
final int callingUid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
@@ -3075,7 +3075,7 @@
"updateLockTaskPackages()");
}
synchronized (mGlobalLock) {
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":"
+ if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Allowlisting " + userId + ":"
+ Arrays.toString(packages));
getLockTaskController().updateLockTaskPackages(userId, packages);
}
@@ -5964,11 +5964,11 @@
}
/**
- * @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on
- * the whitelist
+ * @return allowlist tag for a uid from mPendingTempAllowlist, null if not currently on
+ * the allowlist
*/
- String getPendingTempWhitelistTagForUidLocked(int uid) {
- return mPendingTempWhitelist.get(uid);
+ String getPendingTempAllowlistTagForUidLocked(int uid) {
+ return mPendingTempAllowlist.get(uid);
}
void logAppTooSlow(WindowProcessController app, long startTime, String msg) {
@@ -7297,16 +7297,16 @@
}
@Override
- public void onUidAddedToPendingTempWhitelist(int uid, String tag) {
+ public void onUidAddedToPendingTempAllowlist(int uid, String tag) {
synchronized (mGlobalLockWithoutBoost) {
- mPendingTempWhitelist.put(uid, tag);
+ mPendingTempAllowlist.put(uid, tag);
}
}
@Override
- public void onUidRemovedFromPendingTempWhitelist(int uid) {
+ public void onUidRemovedFromPendingTempAllowlist(int uid) {
synchronized (mGlobalLockWithoutBoost) {
- mPendingTempWhitelist.remove(uid);
+ mPendingTempAllowlist.remove(uid);
}
}
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index 892ee71..c36dede 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -33,11 +33,11 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_ALLOWLISTED;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_PINNABLE;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_WHITELISTED;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -264,12 +264,12 @@
}
/**
- * @return whether the requested task is allowed to be locked (either whitelisted, or declares
+ * @return whether the requested task is allowed to be locked (either allowlisted, or declares
* lockTaskMode="always" in the manifest).
*/
- boolean isTaskWhitelisted(Task task) {
+ boolean isTaskAllowlisted(Task task) {
switch(task.mLockTaskAuth) {
- case LOCK_TASK_AUTH_WHITELISTED:
+ case LOCK_TASK_AUTH_ALLOWLISTED:
case LOCK_TASK_AUTH_LAUNCHABLE:
case LOCK_TASK_AUTH_LAUNCHABLE_PRIV:
return true;
@@ -311,7 +311,7 @@
private boolean isLockTaskModeViolationInternal(Task task, boolean isNewClearTask) {
// TODO: Double check what's going on here. If the task is already in lock task mode, it's
- // likely whitelisted, so will return false below.
+ // likely allowlisted, so will return false below.
if (isTaskLocked(task) && !isNewClearTask) {
// If the task is already at the top and won't be cleared, then allow the operation
return false;
@@ -327,7 +327,7 @@
return false;
}
- return !(isTaskWhitelisted(task) || mLockTaskModeTasks.isEmpty());
+ return !(isTaskAllowlisted(task) || mLockTaskModeTasks.isEmpty());
}
private boolean isRecentsAllowed(int userId) {
@@ -356,7 +356,7 @@
return false;
default:
}
- return isPackageWhitelisted(userId, packageName);
+ return isPackageAllowlisted(userId, packageName);
}
private boolean isEmergencyCallTask(Task task) {
@@ -556,7 +556,7 @@
if (!isSystemCaller) {
task.mLockTaskUid = callingUid;
if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
- // startLockTask() called by app, but app is not part of lock task whitelist. Show
+ // startLockTask() called by app, but app is not part of lock task allowlist. Show
// app pinning request. We will come back here with isSystemCaller true.
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Mode default, asking user");
StatusBarManagerInternal statusBarManager = LocalServices.getService(
@@ -649,8 +649,8 @@
/**
* Update packages that are allowed to be launched in lock task mode.
- * @param userId Which user this whitelist is associated with
- * @param packages The whitelist of packages allowed in lock task mode
+ * @param userId Which user this allowlist is associated with
+ * @param packages The allowlist of packages allowed in lock task mode
* @see #mLockTaskPackages
*/
void updateLockTaskPackages(int userId, String[] packages) {
@@ -659,19 +659,19 @@
boolean taskChanged = false;
for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx >= 0; --taskNdx) {
final Task lockedTask = mLockTaskModeTasks.get(taskNdx);
- final boolean wasWhitelisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
- || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
+ final boolean wasAllowlisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
+ || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_ALLOWLISTED;
lockedTask.setLockTaskAuth();
- final boolean isWhitelisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
- || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
+ final boolean isAllowlisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
+ || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_ALLOWLISTED;
if (mLockTaskModeState != LOCK_TASK_MODE_LOCKED
|| lockedTask.mUserId != userId
- || !wasWhitelisted || isWhitelisted) {
+ || !wasAllowlisted || isAllowlisted) {
continue;
}
- // Terminate locked tasks that have recently lost whitelist authorization.
+ // Terminate locked tasks that have recently lost allowlist authorization.
if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " +
lockedTask + " mLockTaskAuth()=" + lockedTask.lockTaskAuthToString());
removeLockedTask(lockedTask);
@@ -697,17 +697,17 @@
}
}
- boolean isPackageWhitelisted(int userId, String pkg) {
+ boolean isPackageAllowlisted(int userId, String pkg) {
if (pkg == null) {
return false;
}
- String[] whitelist;
- whitelist = mLockTaskPackages.get(userId);
- if (whitelist == null) {
+ String[] allowlist;
+ allowlist = mLockTaskPackages.get(userId);
+ if (allowlist == null) {
return false;
}
- for (String whitelistedPkg : whitelist) {
- if (pkg.equals(whitelistedPkg)) {
+ for (String allowlistedPkg : allowlist) {
+ if (pkg.equals(allowlistedPkg)) {
return true;
}
}
diff --git a/services/core/java/com/android/server/wm/PolicyControl.java b/services/core/java/com/android/server/wm/PolicyControl.java
index 0f92bc8..61b6e0b 100644
--- a/services/core/java/com/android/server/wm/PolicyControl.java
+++ b/services/core/java/com/android/server/wm/PolicyControl.java
@@ -196,40 +196,40 @@
private static final String ALL = "*";
private static final String APPS = "apps";
- private final ArraySet<String> mWhitelist;
- private final ArraySet<String> mBlacklist;
+ private final ArraySet<String> mAllowlist;
+ private final ArraySet<String> mDenylist;
- private Filter(ArraySet<String> whitelist, ArraySet<String> blacklist) {
- mWhitelist = whitelist;
- mBlacklist = blacklist;
+ private Filter(ArraySet<String> allowlist, ArraySet<String> denylist) {
+ mAllowlist = allowlist;
+ mDenylist = denylist;
}
boolean matches(LayoutParams attrs) {
if (attrs == null) return false;
boolean isApp = attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
&& attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
- if (isApp && mBlacklist.contains(APPS)) return false;
- if (onBlacklist(attrs.packageName)) return false;
- if (isApp && mWhitelist.contains(APPS)) return true;
- return onWhitelist(attrs.packageName);
+ if (isApp && mDenylist.contains(APPS)) return false;
+ if (onDenylist(attrs.packageName)) return false;
+ if (isApp && mAllowlist.contains(APPS)) return true;
+ return onAllowlist(attrs.packageName);
}
boolean matches(String packageName) {
- return !onBlacklist(packageName) && onWhitelist(packageName);
+ return !onDenylist(packageName) && onAllowlist(packageName);
}
- private boolean onBlacklist(String packageName) {
- return mBlacklist.contains(packageName) || mBlacklist.contains(ALL);
+ private boolean onDenylist(String packageName) {
+ return mDenylist.contains(packageName) || mDenylist.contains(ALL);
}
- private boolean onWhitelist(String packageName) {
- return mWhitelist.contains(ALL) || mWhitelist.contains(packageName);
+ private boolean onAllowlist(String packageName) {
+ return mAllowlist.contains(ALL) || mAllowlist.contains(packageName);
}
void dump(PrintWriter pw) {
pw.print("Filter[");
- dump("whitelist", mWhitelist, pw); pw.print(',');
- dump("blacklist", mBlacklist, pw); pw.print(']');
+ dump("allowlist", mAllowlist, pw); pw.print(',');
+ dump("denylist", mDenylist, pw); pw.print(']');
}
private void dump(String name, ArraySet<String> set, PrintWriter pw) {
@@ -253,18 +253,18 @@
// e.g. "com.package1", or "apps, com.android.keyguard" or "*"
static Filter parse(String value) {
if (value == null) return null;
- ArraySet<String> whitelist = new ArraySet<String>();
- ArraySet<String> blacklist = new ArraySet<String>();
+ ArraySet<String> allowlist = new ArraySet<String>();
+ ArraySet<String> denylist = new ArraySet<String>();
for (String token : value.split(",")) {
token = token.trim();
if (token.startsWith("-") && token.length() > 1) {
token = token.substring(1);
- blacklist.add(token);
+ denylist.add(token);
} else {
- whitelist.add(token);
+ allowlist.add(token);
}
}
- return new Filter(whitelist, blacklist);
+ return new Filter(allowlist, denylist);
}
}
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 851b533..3fe75a4 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -655,7 +655,8 @@
}
for (int i = mTasks.size() - 1; i >= 0; --i) {
final Task task = mTasks.get(i);
- if (task.mUserId == userId && !mService.getLockTaskController().isTaskWhitelisted(task)) {
+ if (task.mUserId == userId
+ && !mService.getLockTaskController().isTaskAllowlisted(task)) {
remove(task);
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 4700864..39aa60b 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2582,7 +2582,7 @@
mDisplayAccessUIDs.clear();
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent displayContent = getChildAt(displayNdx);
- // Only bother calculating the whitelist for private displays
+ // Only bother calculating the allowlist for private displays
if (displayContent.isPrivate()) {
mDisplayAccessUIDs.append(
displayContent.mDisplayId, displayContent.getPresentUIDs());
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index b71ecbb..ede6708 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -233,10 +233,10 @@
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
- // Check if someone tries to launch an unwhitelisted activity into LockTask mode.
+ // Check if someone tries to launch an unallowlisted activity into LockTask mode.
final boolean lockTaskMode = options.getLockTaskMode();
if (aInfo != null && lockTaskMode
- && !supervisor.mService.getLockTaskController().isPackageWhitelisted(
+ && !supervisor.mService.getLockTaskController().isPackageAllowlisted(
UserHandle.getUserId(callingUid), aInfo.packageName)) {
final String msg = "Permission Denial: starting " + getIntentString(intent)
+ " from " + callerApp + " (pid=" + callingPid
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 6785127..3f197f7 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -40,7 +40,7 @@
import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
@@ -264,7 +264,7 @@
/** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
/** Can enter lockTask without user approval. Can start over existing lockTask task. */
- final static int LOCK_TASK_AUTH_WHITELISTED = 3;
+ final static int LOCK_TASK_AUTH_ALLOWLISTED = 3;
/** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
* lockTask task. */
final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
@@ -1377,7 +1377,7 @@
getDisplayArea().addStackReferenceIfNeeded((ActivityStack) child);
}
- // Make sure the list of display UID whitelists is updated
+ // Make sure the list of display UID allowlists is updated
// now that this record is in a new task.
mRootWindowContainer.updateUIDsPresentOnDisplay();
@@ -1594,7 +1594,7 @@
case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
- case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
+ case LOCK_TASK_AUTH_ALLOWLISTED: return "LOCK_TASK_AUTH_ALLOWLISTED";
case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
default: return "unknown=" + mLockTaskAuth;
}
@@ -1614,8 +1614,8 @@
final LockTaskController lockTaskController = mAtmService.getLockTaskController();
switch (r.lockTaskLaunchMode) {
case LOCK_TASK_LAUNCH_MODE_DEFAULT:
- mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
- ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
+ mLockTaskAuth = lockTaskController.isPackageAllowlisted(mUserId, pkg)
+ ? LOCK_TASK_AUTH_ALLOWLISTED : LOCK_TASK_AUTH_PINNABLE;
break;
case LOCK_TASK_LAUNCH_MODE_NEVER:
@@ -1626,8 +1626,8 @@
mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
break;
- case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
- mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
+ case LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED:
+ mLockTaskAuth = lockTaskController.isPackageAllowlisted(mUserId, pkg)
? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
break;
}
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index f7082a9..f3940e6 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -305,6 +305,7 @@
}
mJobCondition.notify_all();
mJobProcessor.join();
+ mLooper->wake();
mCmdLooperThread.join();
mTimedQueue->stop();
// Ensure that mounts are destroyed while the service is still valid.
@@ -1377,7 +1378,7 @@
}
void IncrementalService::runCmdLooper() {
- constexpr auto kTimeoutMsecs = 1000;
+ constexpr auto kTimeoutMsecs = -1;
while (mRunning.load(std::memory_order_relaxed)) {
mLooper->pollAll(kTimeoutMsecs);
}
diff --git a/services/tests/servicestests/src/com/android/server/display/color/GlobalSaturationTintControllerTest.java b/services/tests/servicestests/src/com/android/server/display/color/GlobalSaturationTintControllerTest.java
index 7b88a0e..4f0cb32 100644
--- a/services/tests/servicestests/src/com/android/server/display/color/GlobalSaturationTintControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/color/GlobalSaturationTintControllerTest.java
@@ -32,9 +32,11 @@
public void setAndGetMatrix() {
final GlobalSaturationTintController tintController = new GlobalSaturationTintController();
tintController.setMatrix(50);
- assertThat(tintController.getMatrix()).hasValuesWithin(0.00001f)
- .of(new float[]{0.6155f, 0.1155f, 0.1155f, 0.0f, 0.3575f, 0.85749996f, 0.3575f,
- 0.0f, 0.036f, 0.036f, 0.536f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f});
+ assertThat(tintController.getMatrix()).usingTolerance(0.00001f)
+ .containsExactly(
+ 0.6155f, 0.1155f, 0.1155f, 0.0f, 0.3575f, 0.85749996f, 0.3575f,
+ 0.0f, 0.036f, 0.036f, 0.536f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)
+ .inOrder();
}
@Test
@@ -43,6 +45,7 @@
tintController.setMatrix(100);
final float[] matrix = new float[16];
Matrix.setIdentityM(matrix, 0);
- assertThat(tintController.getMatrix()).hasValuesWithin(0.00001f).of(matrix);
+ assertThat(tintController.getMatrix()).usingTolerance(0.00001f)
+ .containsExactly(matrix).inOrder();
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index a137cde..e345bec 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -168,8 +168,8 @@
@Test
public void testStartLockTaskMode_once() throws Exception {
- // GIVEN a task record with whitelisted auth
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN a task record with allowlisted auth
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
// WHEN calling setLockTaskMode for LOCKED mode without resuming
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
@@ -185,9 +185,9 @@
@Test
public void testStartLockTaskMode_twice() throws Exception {
- // GIVEN two task records with whitelisted auth
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN two task records with allowlisted auth
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
// WHEN calling setLockTaskMode for LOCKED mode on both tasks
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
@@ -205,7 +205,7 @@
@Test
public void testStartLockTaskMode_pinningRequest() {
- // GIVEN a task record that is not whitelisted, i.e. with pinned auth
+ // GIVEN a task record that is not allowlisted, i.e. with pinned auth
Task tr = getTask(Task.LOCK_TASK_AUTH_PINNABLE);
// WHEN calling startLockTaskMode
@@ -236,23 +236,23 @@
@Test
public void testLockTaskViolation() {
- // GIVEN one task record with whitelisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN one task record with allowlisted auth that is in lock task mode
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN it's not a lock task violation to try and launch this task without clearing
assertFalse(mLockTaskController.isLockTaskModeViolation(tr, false));
- // THEN it's a lock task violation to launch another task that is not whitelisted
+ // THEN it's a lock task violation to launch another task that is not allowlisted
assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(
Task.LOCK_TASK_AUTH_PINNABLE)));
// THEN it's a lock task violation to launch another task that is disallowed from lock task
assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(
Task.LOCK_TASK_AUTH_DONT_LOCK)));
- // THEN it's no a lock task violation to launch another task that is whitelisted
+ // THEN it's no a lock task violation to launch another task that is allowlisted
assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
- Task.LOCK_TASK_AUTH_WHITELISTED)));
+ Task.LOCK_TASK_AUTH_ALLOWLISTED)));
assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
Task.LOCK_TASK_AUTH_LAUNCHABLE)));
// THEN it's not a lock task violation to launch another task that is priv launchable
@@ -262,8 +262,8 @@
@Test
public void testLockTaskViolation_emergencyCall() {
- // GIVEN one task record with whitelisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN one task record with allowlisted auth that is in lock task mode
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// GIVEN tasks necessary for emergency calling
@@ -294,8 +294,8 @@
@Test
public void testStopLockTaskMode() throws Exception {
- // GIVEN one task record with whitelisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN one task record with allowlisted auth that is in lock task mode
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN the same caller calls stopLockTaskMode
@@ -311,8 +311,8 @@
@Test(expected = SecurityException.class)
public void testStopLockTaskMode_differentCaller() {
- // GIVEN one task record with whitelisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN one task record with allowlisted auth that is in lock task mode
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN a different caller calls stopLockTaskMode
@@ -323,8 +323,8 @@
@Test
public void testStopLockTaskMode_systemCaller() {
- // GIVEN one task record with whitelisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN one task record with allowlisted auth that is in lock task mode
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN system calls stopLockTaskMode
@@ -336,9 +336,9 @@
@Test
public void testStopLockTaskMode_twoTasks() throws Exception {
- // GIVEN two task records with whitelisted auth that is in lock task mode
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN two task records with allowlisted auth that is in lock task mode
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -357,9 +357,9 @@
@Test
public void testStopLockTaskMode_rootTask() throws Exception {
- // GIVEN two task records with whitelisted auth that is in lock task mode
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN two task records with allowlisted auth that is in lock task mode
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -405,9 +405,9 @@
@Test
public void testClearLockedTasks() throws Exception {
- // GIVEN two task records with whitelisted auth that is in lock task mode
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN two task records with allowlisted auth that is in lock task mode
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -434,7 +434,7 @@
.thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -454,7 +454,7 @@
.thenReturn(true);
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -471,7 +471,7 @@
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 1, mContext.getUserId());
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -488,7 +488,7 @@
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 0, mContext.getUserId());
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -500,45 +500,45 @@
@Test
public void testUpdateLockTaskPackages() {
- String[] whitelist1 = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
- String[] whitelist2 = {TEST_PACKAGE_NAME};
+ String[] allowlist1 = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
+ String[] allowlist2 = {TEST_PACKAGE_NAME};
- // No package is whitelisted initially
- for (String pkg : whitelist1) {
- assertFalse("Package shouldn't be whitelisted: " + pkg,
- mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg));
- assertFalse("Package shouldn't be whitelisted for user 0: " + pkg,
- mLockTaskController.isPackageWhitelisted(0, pkg));
+ // No package is allowlisted initially
+ for (String pkg : allowlist1) {
+ assertFalse("Package shouldn't be allowlisted: " + pkg,
+ mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg));
+ assertFalse("Package shouldn't be allowlisted for user 0: " + pkg,
+ mLockTaskController.isPackageAllowlisted(0, pkg));
}
- // Apply whitelist
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist1);
+ // Apply allowlist
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist1);
- // Assert the whitelist is applied to the correct user
- for (String pkg : whitelist1) {
- assertTrue("Package should be whitelisted: " + pkg,
- mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg));
- assertFalse("Package shouldn't be whitelisted for user 0: " + pkg,
- mLockTaskController.isPackageWhitelisted(0, pkg));
+ // Assert the allowlist is applied to the correct user
+ for (String pkg : allowlist1) {
+ assertTrue("Package should be allowlisted: " + pkg,
+ mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg));
+ assertFalse("Package shouldn't be allowlisted for user 0: " + pkg,
+ mLockTaskController.isPackageAllowlisted(0, pkg));
}
- // Update whitelist
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist2);
+ // Update allowlist
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist2);
- // Assert the new whitelist is applied
- assertTrue("Package should remain whitelisted: " + TEST_PACKAGE_NAME,
- mLockTaskController.isPackageWhitelisted(TEST_USER_ID, TEST_PACKAGE_NAME));
- assertFalse("Package should no longer be whitelisted: " + TEST_PACKAGE_NAME_2,
- mLockTaskController.isPackageWhitelisted(TEST_USER_ID, TEST_PACKAGE_NAME_2));
+ // Assert the new allowlist is applied
+ assertTrue("Package should remain allowlisted: " + TEST_PACKAGE_NAME,
+ mLockTaskController.isPackageAllowlisted(TEST_USER_ID, TEST_PACKAGE_NAME));
+ assertFalse("Package should no longer be allowlisted: " + TEST_PACKAGE_NAME_2,
+ mLockTaskController.isPackageAllowlisted(TEST_USER_ID, TEST_PACKAGE_NAME_2));
}
@Test
public void testUpdateLockTaskPackages_taskRemoved() throws Exception {
- // GIVEN two tasks which are whitelisted initially
+ // GIVEN two tasks which are allowlisted initially
Task tr1 = getTaskForUpdate(TEST_PACKAGE_NAME, true);
Task tr2 = getTaskForUpdate(TEST_PACKAGE_NAME_2, false);
- String[] whitelist = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+ String[] allowlist = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
// GIVEN the tasks are launched into LockTask mode
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
@@ -548,9 +548,9 @@
assertTrue(mLockTaskController.isTaskLocked(tr2));
verifyLockTaskStarted(STATUS_BAR_MASK_LOCKED, DISABLE2_MASK);
- // WHEN removing one package from whitelist
- whitelist = new String[] {TEST_PACKAGE_NAME};
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+ // WHEN removing one package from allowlist
+ allowlist = new String[] {TEST_PACKAGE_NAME};
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
// THEN the task running that package should be stopped
verify(tr2).performClearTaskLocked();
@@ -560,9 +560,9 @@
assertTrue(mLockTaskController.isTaskLocked(tr1));
verifyLockTaskStarted(STATUS_BAR_MASK_LOCKED, DISABLE2_MASK);
- // WHEN removing the last package from whitelist
- whitelist = new String[] {};
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+ // WHEN removing the last package from allowlist
+ allowlist = new String[] {};
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
// THEN the last task should be cleared, and the system should quit LockTask mode
verify(tr1).performClearTaskLocked();
@@ -574,7 +574,7 @@
@Test
public void testUpdateLockTaskFeatures() throws Exception {
// GIVEN a locked task
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN lock task mode should be started with default status bar masks
@@ -616,7 +616,7 @@
@Test
public void testUpdateLockTaskFeatures_differentUser() throws Exception {
// GIVEN a locked task
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN lock task mode should be started with default status bar masks
@@ -638,7 +638,7 @@
@Test
public void testUpdateLockTaskFeatures_keyguard() {
// GIVEN a locked task
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN keyguard should be disabled
@@ -704,7 +704,7 @@
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
// Start lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK is not enabled
@@ -719,15 +719,15 @@
assertTrue(mLockTaskController.isActivityAllowed(
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_ALWAYS));
- // unwhitelisted package should not be allowed
+ // unallowlisted package should not be allowed
assertFalse(mLockTaskController.isActivityAllowed(
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
- // update the whitelist
- String[] whitelist = new String[] { TEST_PACKAGE_NAME };
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+ // update the allowlist
+ String[] allowlist = new String[] { TEST_PACKAGE_NAME };
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
- // whitelisted package should be allowed
+ // allowlisted package should be allowed
assertTrue(mLockTaskController.isActivityAllowed(
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
@@ -755,17 +755,17 @@
}
/**
- * @param isAppAware {@code true} if the app has marked if_whitelisted in its manifest
+ * @param isAppAware {@code true} if the app has marked if_allowlisted in its manifest
*/
private Task getTaskForUpdate(String pkg, boolean isAppAware) {
- final int authIfWhitelisted = isAppAware
+ final int authIfAllowlisted = isAppAware
? Task.LOCK_TASK_AUTH_LAUNCHABLE
- : Task.LOCK_TASK_AUTH_WHITELISTED;
- Task tr = getTask(pkg, authIfWhitelisted);
+ : Task.LOCK_TASK_AUTH_ALLOWLISTED;
+ Task tr = getTask(pkg, authIfAllowlisted);
doAnswer((invocation) -> {
- boolean isWhitelisted =
- mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg);
- tr.mLockTaskAuth = isWhitelisted ? authIfWhitelisted : Task.LOCK_TASK_AUTH_PINNABLE;
+ boolean isAllowlisted =
+ mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg);
+ tr.mLockTaskAuth = isAllowlisted ? authIfAllowlisted : Task.LOCK_TASK_AUTH_PINNABLE;
return null;
}).when(tr).setLockTaskAuth();
return tr;
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index bebbbd0..f7fe1ba 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -16,6 +16,7 @@
package android.telecom;
+import android.annotation.SystemApi;
import android.media.ToneGenerator;
import android.os.Parcel;
import android.os.Parcelable;
@@ -80,21 +81,26 @@
* Reason code (returned via {@link #getReason()}) which indicates that a call could not be
* completed because the cellular radio is off or out of service, the device is connected to
* a wifi network, but the user has not enabled wifi calling.
- * @hide
*/
public static final String REASON_WIFI_ON_BUT_WFC_OFF = "REASON_WIFI_ON_BUT_WFC_OFF";
/**
* Reason code (returned via {@link #getReason()}), which indicates that the video telephony
* call was disconnected because IMS access is blocked.
- * @hide
*/
public static final String REASON_IMS_ACCESS_BLOCKED = "REASON_IMS_ACCESS_BLOCKED";
/**
- * Reason code, which indicates that the conference call is simulating single party conference.
+ * Reason code (returned via {@link #getReason()}), which indicates that the connection service
+ * is setting the call's state to {@link Call#STATE_DISCONNECTED} because it is internally
+ * changing the representation of an IMS conference call to simulate a single-party call.
+ *
+ * This reason code is only used for communication between a {@link ConnectionService} and
+ * Telecom and should not be surfaced to the user.
+ *
* @hide
*/
+ @SystemApi
public static final String REASON_EMULATING_SINGLE_CALL = "EMULATING_SINGLE_CALL";
/**
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 768c8ee..c20e5ad 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -48,11 +48,15 @@
public final class PhoneAccount implements Parcelable {
/**
- * {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which determines the
- * sort order for {@link PhoneAccount}s from the same
- * {@link android.telecom.ConnectionService}.
+ * String extra which determines the order in which {@link PhoneAccount}s are sorted
+ *
+ * This is an extras key set via {@link Builder#setExtras} which determines the order in which
+ * {@link PhoneAccount}s from the same {@link ConnectionService} are sorted. The accounts
+ * are sorted by this key via standard lexicographical order, and this ordering is used to
+ * determine priority when a call can be placed via multiple accounts.
* @hide
*/
+ @SystemApi
public static final String EXTRA_SORT_ORDER =
"android.telecom.extra.SORT_ORDER";
@@ -85,8 +89,7 @@
/**
* Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which
* indicates that all calls from this {@link PhoneAccount} should be treated as VoIP calls
- * rather than cellular calls.
- * @hide
+ * rather than cellular calls by the Telecom audio handling logic.
*/
public static final String EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE =
"android.telecom.extra.ALWAYS_USE_VOIP_AUDIO_MODE";
@@ -160,6 +163,7 @@
* in progress.
* @hide
*/
+ @SystemApi
public static final String EXTRA_PLAY_CALL_RECORDING_TONE =
"android.telecom.extra.PLAY_CALL_RECORDING_TONE";
@@ -254,6 +258,7 @@
* See {@link #getCapabilities}
* @hide
*/
+ @SystemApi
public static final int CAPABILITY_EMERGENCY_CALLS_ONLY = 0x80;
/**
@@ -277,6 +282,7 @@
* convert all outgoing video calls to emergency numbers to audio-only.
* @hide
*/
+ @SystemApi
public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 0x200;
/**
@@ -323,9 +329,9 @@
/**
* Flag indicating that this {@link PhoneAccount} is the preferred SIM subscription for
- * emergency calls. A {@link PhoneAccount} that sets this capabilitiy must also
+ * emergency calls. A {@link PhoneAccount} that sets this capability must also
* set the {@link #CAPABILITY_SIM_SUBSCRIPTION} and {@link #CAPABILITY_PLACE_EMERGENCY_CALLS}
- * capabilities. There should only be one emergency preferred {@link PhoneAccount}.
+ * capabilities. There must only be one emergency preferred {@link PhoneAccount} on the device.
* <p>
* When set, Telecom will prefer this {@link PhoneAccount} over others for emergency calling,
* even if the emergency call was placed with a specific {@link PhoneAccount} set using the
@@ -334,6 +340,7 @@
*
* @hide
*/
+ @SystemApi
public static final int CAPABILITY_EMERGENCY_PREFERRED = 0x2000;
/**
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index bcb1736..1f3740b 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -322,6 +322,7 @@
* the remote handle of the new call.
* @hide
*/
+ @SystemApi
public static final String EXTRA_UNKNOWN_CALL_HANDLE =
"android.telecom.extra.UNKNOWN_CALL_HANDLE";
@@ -392,6 +393,7 @@
* </ul>
* @hide
*/
+ @SystemApi
public static final String EXTRA_CALL_TECHNOLOGY_TYPE =
"android.telecom.extra.CALL_TECHNOLOGY_TYPE";
@@ -728,17 +730,57 @@
public static final int TTY_MODE_VCO = 3;
/**
- * Broadcast intent action indicating that the current TTY mode has changed. An intent extra
- * provides this state as an int.
+ * Broadcast intent action indicating that the current TTY mode has changed.
*
- * @see #EXTRA_CURRENT_TTY_MODE
+ * This intent will contain {@link #EXTRA_CURRENT_TTY_MODE} as an intent extra, giving the new
+ * TTY mode.
* @hide
*/
+ @TestApi
+ @SystemApi
public static final String ACTION_CURRENT_TTY_MODE_CHANGED =
"android.telecom.action.CURRENT_TTY_MODE_CHANGED";
/**
- * The lookup key for an int that indicates the current TTY mode.
+ * Integer extra key that indicates the current TTY mode.
+ *
+ * Used with {@link #ACTION_CURRENT_TTY_MODE_CHANGED}.
+ *
+ * Valid modes are:
+ * <ul>
+ * <li>{@link #TTY_MODE_OFF}</li>
+ * <li>{@link #TTY_MODE_FULL}</li>
+ * <li>{@link #TTY_MODE_HCO}</li>
+ * <li>{@link #TTY_MODE_VCO}</li>
+ * </ul>
+ *
+ * This TTY mode is distinct from the one sent via {@link #ACTION_TTY_PREFERRED_MODE_CHANGED},
+ * since the current TTY mode will always be {@link #TTY_MODE_OFF}unless a TTY terminal is
+ * plugged into the device.
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public static final String EXTRA_CURRENT_TTY_MODE =
+ "android.telecom.extra.CURRENT_TTY_MODE";
+
+ /**
+ * Broadcast intent action indicating that the TTY preferred operating mode has changed.
+ *
+ * This intent will contain {@link #EXTRA_TTY_PREFERRED_MODE} as an intent extra, giving the new
+ * preferred TTY mode.
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public static final String ACTION_TTY_PREFERRED_MODE_CHANGED =
+ "android.telecom.action.TTY_PREFERRED_MODE_CHANGED";
+
+ /**
+ * Integer extra key that indicates the preferred TTY mode.
+ *
+ * Used with {@link #ACTION_TTY_PREFERRED_MODE_CHANGED}.
+ *
* Valid modes are:
* <ul>
* <li>{@link #TTY_MODE_OFF}</li>
@@ -748,26 +790,8 @@
* </ul>
* @hide
*/
- public static final String EXTRA_CURRENT_TTY_MODE =
- "android.telecom.extra.CURRENT_TTY_MODE";
-
- /**
- * Broadcast intent action indicating that the TTY preferred operating mode has changed. An
- * intent extra provides the new mode as an int.
- *
- * @see #EXTRA_TTY_PREFERRED_MODE
- * @hide
- */
- public static final String ACTION_TTY_PREFERRED_MODE_CHANGED =
- "android.telecom.action.TTY_PREFERRED_MODE_CHANGED";
-
- /**
- * The lookup key for an int that indicates preferred TTY mode. Valid modes are: -
- * {@link #TTY_MODE_OFF} - {@link #TTY_MODE_FULL} - {@link #TTY_MODE_HCO} -
- * {@link #TTY_MODE_VCO}
- *
- * @hide
- */
+ @TestApi
+ @SystemApi
public static final String EXTRA_TTY_PREFERRED_MODE =
"android.telecom.extra.TTY_PREFERRED_MODE";
@@ -843,8 +867,10 @@
* {@link TelecomManager#CALL_SOURCE_EMERGENCY_DIALPAD},
* {@link TelecomManager#CALL_SOURCE_EMERGENCY_SHORTCUT}.
*
+ * Intended for use with the platform emergency dialer only.
* @hide
*/
+ @SystemApi
public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE";
/**
@@ -852,6 +878,7 @@
*
* @hide
*/
+ @SystemApi
public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2;
/**
@@ -859,6 +886,7 @@
*
* @hide
*/
+ @SystemApi
public static final int CALL_SOURCE_EMERGENCY_DIALPAD = 1;
/**
@@ -866,6 +894,7 @@
*
* @hide
*/
+ @SystemApi
public static final int CALL_SOURCE_UNSPECIFIED = 0;
/**
diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index 6826974..7736473 100644
--- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
@@ -15,6 +15,8 @@
*/
package com.android.internal.telephony.util;
+import static android.telephony.Annotation.DataState;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -26,6 +28,7 @@
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.SystemProperties;
+import android.telephony.TelephonyManager;
import java.io.PrintWriter;
import java.util.Collections;
@@ -154,4 +157,22 @@
} catch (InterruptedException ignored) {
}
}
+
+ /**
+ * Convert data state to string
+ *
+ * @return The data state in string format.
+ */
+ public static String dataStateToString(@DataState int state) {
+ switch (state) {
+ case TelephonyManager.DATA_DISCONNECTED: return "DISCONNECTED";
+ case TelephonyManager.DATA_CONNECTING: return "CONNECTING";
+ case TelephonyManager.DATA_CONNECTED: return "CONNECTED";
+ case TelephonyManager.DATA_SUSPENDED: return "SUSPENDED";
+ case TelephonyManager.DATA_DISCONNECTING: return "DISCONNECTING";
+ case TelephonyManager.DATA_UNKNOWN: return "UNKNOWN";
+ }
+ // This is the error case. The well-defined value for UNKNOWN is -1.
+ return "UNKNOWN(" + state + ")";
+ }
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c978154..f2dae23 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -32,6 +32,7 @@
import android.service.carrier.CarrierService;
import android.telecom.TelecomManager;
import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsSsData;
import com.android.internal.telephony.ICarrierConfigLoader;
import com.android.telephony.Rlog;
@@ -66,6 +67,18 @@
public static final String EXTRA_SUBSCRIPTION_INDEX =
SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX;
+ /**
+ * Service class flag if no specific service class is specified.
+ * Reference: 3GPP TS 27.007 Section 7.4 Facility lock +CLCK
+ */
+ public static final int SERVICE_CLASS_NONE = ImsSsData.SERVICE_CLASS_NONE;
+
+ /**
+ * Service class flag for voice telephony.
+ * Reference: 3GPP TS 27.007 Section 7.4 Facility lock +CLCK
+ */
+ public static final int SERVICE_CLASS_VOICE = ImsSsData.SERVICE_CLASS_VOICE;
+
private final Context mContext;
/**
@@ -212,6 +225,18 @@
"call_barring_supports_deactivate_all_bool";
/**
+ * Specifies the service class for call barring service. Default value is
+ * {@link #SERVICE_CLASS_VOICE}.
+ * The value set as below:
+ * <ul>
+ * <li>0: {@link #SERVICE_CLASS_NONE}</li>
+ * <li>1: {@link #SERVICE_CLASS_VOICE}</li>
+ * </ul>
+ */
+ public static final String KEY_CALL_BARRING_DEFAULT_SERVICE_CLASS_INT =
+ "call_barring_default_service_class_int";
+
+ /**
* Flag indicating whether the Phone app should ignore EVENT_SIM_NETWORK_LOCKED
* events from the Sim.
* If true, this will prevent the IccNetworkDepersonalizationPanel from being shown, and
@@ -3880,10 +3905,23 @@
* Indicating whether DUN APN should be disabled when the device is roaming. In that case,
* the default APN (i.e. internet) will be used for tethering.
*
+ * This config is only available when using Preset APN(not user edited) as Preferred APN.
+ *
* @hide
*/
- public static final String KEY_DISABLE_DUN_APN_WHILE_ROAMING =
- "disable_dun_apn_while_roaming";
+ public static final String KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL =
+ "disable_dun_apn_while_roaming_with_preset_apn_bool";
+
+ /**
+ * Where there is no preferred APN, specifies the carrier's default preferred APN.
+ * Specifies the {@link android.provider.Telephony.Carriers.APN} of the default preferred apn.
+ *
+ * This config is only available with Preset APN(not user edited).
+ *
+ * @hide
+ */
+ public static final String KEY_DEFAULT_PREFERRED_APN_NAME_STRING =
+ "default_preferred_apn_name_string";
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -3959,6 +3997,7 @@
sDefaults.putBoolean(KEY_CALL_BARRING_VISIBILITY_BOOL, false);
sDefaults.putBoolean(KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL, true);
sDefaults.putBoolean(KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL, true);
+ sDefaults.putInt(KEY_CALL_BARRING_DEFAULT_SERVICE_CLASS_INT, SERVICE_CLASS_VOICE);
sDefaults.putBoolean(KEY_CALL_FORWARDING_VISIBILITY_BOOL, true);
sDefaults.putBoolean(KEY_CALL_FORWARDING_WHEN_UNREACHABLE_SUPPORTED_BOOL, true);
sDefaults.putBoolean(KEY_CALL_FORWARDING_WHEN_UNANSWERED_SUPPORTED_BOOL, true);
@@ -4422,7 +4461,8 @@
"ims:2", "cbs:2", "ia:2", "emergency:2", "mcx:3", "xcap:3"
});
sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]);
- sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING, false);
+ sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false);
+ sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, "");
}
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 4b5399e..c7aaee1 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5499,23 +5499,6 @@
}
}
- /**
- * Convert data state to string
- *
- * @return The data state in string format.
- * @hide
- */
- public static String dataStateToString(@DataState int state) {
- switch (state) {
- case DATA_DISCONNECTED: return "DISCONNECTED";
- case DATA_CONNECTING: return "CONNECTING";
- case DATA_CONNECTED: return "CONNECTED";
- case DATA_SUSPENDED: return "SUSPENDED";
- case DATA_DISCONNECTING: return "DISCONNECTING";
- }
- return "UNKNOWN(" + state + ")";
- }
-
/**
* @hide
*/
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index 2b3072e..da7311c 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -137,18 +137,30 @@
}
@Override
- public IImsMmTelFeature createMmTelFeature(int slotId, IImsFeatureStatusCallback c) {
- return createMmTelFeatureInternal(slotId, c);
+ public IImsMmTelFeature createMmTelFeature(int slotId) {
+ return createMmTelFeatureInternal(slotId);
}
@Override
- public IImsRcsFeature createRcsFeature(int slotId, IImsFeatureStatusCallback c) {
- return createRcsFeatureInternal(slotId, c);
+ public IImsRcsFeature createRcsFeature(int slotId) {
+ return createRcsFeatureInternal(slotId);
}
@Override
- public void removeImsFeature(int slotId, int featureType, IImsFeatureStatusCallback c) {
- ImsService.this.removeImsFeature(slotId, featureType, c);
+ public void addFeatureStatusCallback(int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ ImsService.this.addImsFeatureStatusCallback(slotId, featureType, c);
+ }
+
+ @Override
+ public void removeFeatureStatusCallback(int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ ImsService.this.removeImsFeatureStatusCallback(slotId, featureType, c);
+ }
+
+ @Override
+ public void removeImsFeature(int slotId, int featureType) {
+ ImsService.this.removeImsFeature(slotId, featureType);
}
@Override
@@ -204,11 +216,10 @@
return mFeaturesBySlot.get(slotId);
}
- private IImsMmTelFeature createMmTelFeatureInternal(int slotId,
- IImsFeatureStatusCallback c) {
+ private IImsMmTelFeature createMmTelFeatureInternal(int slotId) {
MmTelFeature f = createMmTelFeature(slotId);
if (f != null) {
- setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL, c);
+ setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL);
return f.getBinder();
} else {
Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned.");
@@ -216,11 +227,10 @@
}
}
- private IImsRcsFeature createRcsFeatureInternal(int slotId,
- IImsFeatureStatusCallback c) {
+ private IImsRcsFeature createRcsFeatureInternal(int slotId) {
RcsFeature f = createRcsFeature(slotId);
if (f != null) {
- setupFeature(f, slotId, ImsFeature.FEATURE_RCS, c);
+ setupFeature(f, slotId, ImsFeature.FEATURE_RCS);
return f.getBinder();
} else {
Log.e(LOG_TAG, "createRcsFeatureInternal: null feature returned.");
@@ -228,13 +238,45 @@
}
}
- private void setupFeature(ImsFeature f, int slotId, int featureType,
- IImsFeatureStatusCallback c) {
+ private void setupFeature(ImsFeature f, int slotId, int featureType) {
f.initialize(this, slotId);
- f.addImsFeatureStatusCallback(c);
addImsFeature(slotId, featureType, f);
}
+ private void addImsFeatureStatusCallback(int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ synchronized (mFeaturesBySlot) {
+ // get ImsFeature associated with the slot/feature
+ SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
+ if (features == null) {
+ Log.w(LOG_TAG, "Can not add ImsFeatureStatusCallback - no features on slot "
+ + slotId);
+ return;
+ }
+ ImsFeature f = features.get(featureType);
+ if (f != null) {
+ f.addImsFeatureStatusCallback(c);
+ }
+ }
+ }
+
+ private void removeImsFeatureStatusCallback(int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ synchronized (mFeaturesBySlot) {
+ // get ImsFeature associated with the slot/feature
+ SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
+ if (features == null) {
+ Log.w(LOG_TAG, "Can not remove ImsFeatureStatusCallback - no features on slot "
+ + slotId);
+ return;
+ }
+ ImsFeature f = features.get(featureType);
+ if (f != null) {
+ f.removeImsFeatureStatusCallback(c);
+ }
+ }
+ }
+
private void addImsFeature(int slotId, int featureType, ImsFeature f) {
synchronized (mFeaturesBySlot) {
// Get SparseArray for Features, by querying slot Id
@@ -248,8 +290,7 @@
}
}
- private void removeImsFeature(int slotId, int featureType,
- IImsFeatureStatusCallback c) {
+ private void removeImsFeature(int slotId, int featureType) {
synchronized (mFeaturesBySlot) {
// get ImsFeature associated with the slot/feature
SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
@@ -264,7 +305,6 @@
+ featureType + " exists on slot " + slotId);
return;
}
- f.removeImsFeatureStatusCallback(c);
f.onFeatureRemoved();
features.remove(featureType);
}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl b/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl
index c7da681..c956cbc 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl
@@ -31,12 +31,14 @@
*/
interface IImsServiceController {
void setListener(IImsServiceControllerListener l);
- IImsMmTelFeature createMmTelFeature(int slotId, in IImsFeatureStatusCallback c);
- IImsRcsFeature createRcsFeature(int slotId, in IImsFeatureStatusCallback c);
+ IImsMmTelFeature createMmTelFeature(int slotId);
+ IImsRcsFeature createRcsFeature(int slotId);
ImsFeatureConfiguration querySupportedImsFeatures();
+ void addFeatureStatusCallback(int slotId, int featureType, in IImsFeatureStatusCallback c);
+ void removeFeatureStatusCallback(int slotId, int featureType, in IImsFeatureStatusCallback c);
// Synchronous call to ensure the ImsService is ready before continuing with feature creation.
void notifyImsServiceReadyForFeatureCreation();
- void removeImsFeature(int slotId, int featureType, in IImsFeatureStatusCallback c);
+ void removeImsFeature(int slotId, int featureType);
IImsConfig getConfig(int slotId);
IImsRegistration getRegistration(int slotId);
oneway void enableIms(int slotId);
diff --git a/telephony/java/android/telephony/ims/compat/ImsService.java b/telephony/java/android/telephony/ims/compat/ImsService.java
index eafbb14..41d1d72 100644
--- a/telephony/java/android/telephony/ims/compat/ImsService.java
+++ b/telephony/java/android/telephony/ims/compat/ImsService.java
@@ -21,7 +21,6 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent;
import android.os.IBinder;
-import android.os.RemoteException;
import android.telephony.CarrierConfigManager;
import android.telephony.ims.compat.feature.ImsFeature;
import android.telephony.ims.compat.feature.MMTelFeature;
@@ -91,25 +90,35 @@
protected final IBinder mImsServiceController = new IImsServiceController.Stub() {
@Override
- public IImsMMTelFeature createEmergencyMMTelFeature(int slotId,
+ public IImsMMTelFeature createEmergencyMMTelFeature(int slotId) {
+ return createEmergencyMMTelFeatureInternal(slotId);
+ }
+
+ @Override
+ public IImsMMTelFeature createMMTelFeature(int slotId) {
+ return createMMTelFeatureInternal(slotId);
+ }
+
+ @Override
+ public IImsRcsFeature createRcsFeature(int slotId) {
+ return createRcsFeatureInternal(slotId);
+ }
+
+ @Override
+ public void removeImsFeature(int slotId, int featureType) {
+ ImsService.this.removeImsFeature(slotId, featureType);
+ }
+
+ @Override
+ public void addFeatureStatusCallback(int slotId, int featureType,
IImsFeatureStatusCallback c) {
- return createEmergencyMMTelFeatureInternal(slotId, c);
+ addImsFeatureStatusCallback(slotId, featureType, c);
}
@Override
- public IImsMMTelFeature createMMTelFeature(int slotId, IImsFeatureStatusCallback c) {
- return createMMTelFeatureInternal(slotId, c);
- }
-
- @Override
- public IImsRcsFeature createRcsFeature(int slotId, IImsFeatureStatusCallback c) {
- return createRcsFeatureInternal(slotId, c);
- }
-
- @Override
- public void removeImsFeature(int slotId, int featureType, IImsFeatureStatusCallback c)
- throws RemoteException {
- ImsService.this.removeImsFeature(slotId, featureType, c);
+ public void removeFeatureStatusCallback(int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ removeImsFeatureStatusCallback(slotId, featureType, c);
}
};
@@ -137,46 +146,40 @@
return mFeaturesBySlot.get(slotId);
}
- private IImsMMTelFeature createEmergencyMMTelFeatureInternal(int slotId,
- IImsFeatureStatusCallback c) {
+ private IImsMMTelFeature createEmergencyMMTelFeatureInternal(int slotId) {
MMTelFeature f = onCreateEmergencyMMTelImsFeature(slotId);
if (f != null) {
- setupFeature(f, slotId, ImsFeature.EMERGENCY_MMTEL, c);
+ setupFeature(f, slotId, ImsFeature.EMERGENCY_MMTEL);
return f.getBinder();
} else {
return null;
}
}
- private IImsMMTelFeature createMMTelFeatureInternal(int slotId,
- IImsFeatureStatusCallback c) {
+ private IImsMMTelFeature createMMTelFeatureInternal(int slotId) {
MMTelFeature f = onCreateMMTelImsFeature(slotId);
if (f != null) {
- setupFeature(f, slotId, ImsFeature.MMTEL, c);
+ setupFeature(f, slotId, ImsFeature.MMTEL);
return f.getBinder();
} else {
return null;
}
}
- private IImsRcsFeature createRcsFeatureInternal(int slotId,
- IImsFeatureStatusCallback c) {
+ private IImsRcsFeature createRcsFeatureInternal(int slotId) {
RcsFeature f = onCreateRcsFeature(slotId);
if (f != null) {
- setupFeature(f, slotId, ImsFeature.RCS, c);
+ setupFeature(f, slotId, ImsFeature.RCS);
return f.getBinder();
} else {
return null;
}
}
- private void setupFeature(ImsFeature f, int slotId, int featureType,
- IImsFeatureStatusCallback c) {
+ private void setupFeature(ImsFeature f, int slotId, int featureType) {
f.setContext(this);
f.setSlotId(slotId);
- f.addImsFeatureStatusCallback(c);
addImsFeature(slotId, featureType, f);
- // TODO: Remove once new onFeatureReady AIDL is merged in.
f.onFeatureReady();
}
@@ -193,12 +196,45 @@
}
}
- private void removeImsFeature(int slotId, int featureType,
+ private void addImsFeatureStatusCallback(int slotId, int featureType,
IImsFeatureStatusCallback c) {
synchronized (mFeaturesBySlot) {
// get ImsFeature associated with the slot/feature
SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
if (features == null) {
+ Log.w(LOG_TAG, "Can not add ImsFeatureStatusCallback. No ImsFeatures exist on"
+ + " slot " + slotId);
+ return;
+ }
+ ImsFeature f = features.get(featureType);
+ if (f != null) {
+ f.addImsFeatureStatusCallback(c);
+ }
+ }
+ }
+
+ private void removeImsFeatureStatusCallback(int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ synchronized (mFeaturesBySlot) {
+ // get ImsFeature associated with the slot/feature
+ SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
+ if (features == null) {
+ Log.w(LOG_TAG, "Can not remove ImsFeatureStatusCallback. No ImsFeatures exist on"
+ + " slot " + slotId);
+ return;
+ }
+ ImsFeature f = features.get(featureType);
+ if (f != null) {
+ f.removeImsFeatureStatusCallback(c);
+ }
+ }
+ }
+
+ private void removeImsFeature(int slotId, int featureType) {
+ synchronized (mFeaturesBySlot) {
+ // get ImsFeature associated with the slot/feature
+ SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
+ if (features == null) {
Log.w(LOG_TAG, "Can not remove ImsFeature. No ImsFeatures exist on slot "
+ slotId);
return;
@@ -209,7 +245,6 @@
+ featureType + " exists on slot " + slotId);
return;
}
- f.removeImsFeatureStatusCallback(c);
f.onFeatureRemoved();
features.remove(featureType);
}
diff --git a/telephony/java/com/android/ims/internal/IImsServiceController.aidl b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
index 857089f..e9528f4 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceController.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
@@ -25,8 +25,10 @@
* {@hide}
*/
interface IImsServiceController {
- IImsMMTelFeature createEmergencyMMTelFeature(int slotId, in IImsFeatureStatusCallback c);
- IImsMMTelFeature createMMTelFeature(int slotId, in IImsFeatureStatusCallback c);
- IImsRcsFeature createRcsFeature(int slotId, in IImsFeatureStatusCallback c);
- void removeImsFeature(int slotId, int featureType, in IImsFeatureStatusCallback c);
+ IImsMMTelFeature createEmergencyMMTelFeature(int slotId);
+ IImsMMTelFeature createMMTelFeature(int slotId);
+ IImsRcsFeature createRcsFeature(int slotId);
+ void removeImsFeature(int slotId, int featureType);
+ void addFeatureStatusCallback(int slotId, int featureType, in IImsFeatureStatusCallback c);
+ void removeFeatureStatusCallback(int slotId, int featureType, in IImsFeatureStatusCallback c);
}
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index 9f0b41f..c895420 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -67,6 +67,9 @@
private NetworkAgent mNetworkAgent;
private int mStartKeepaliveError = SocketKeepalive.ERROR_UNSUPPORTED;
private int mStopKeepaliveError = SocketKeepalive.NO_KEEPALIVE;
+ // Controls how test network agent is going to wait before responding to keepalive
+ // start/stop. Useful when simulate KeepaliveTracker is waiting for response from modem.
+ private long mKeepaliveResponseDelay = 0L;
private Integer mExpectedKeepaliveSlot = null;
public NetworkAgentWrapper(int transport, LinkProperties linkProperties, Context context)
@@ -134,12 +137,17 @@
if (mWrapper.mExpectedKeepaliveSlot != null) {
assertEquals((int) mWrapper.mExpectedKeepaliveSlot, slot);
}
- onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError);
+ mWrapper.mHandlerThread.getThreadHandler().postDelayed(
+ () -> onSocketKeepaliveEvent(slot, mWrapper.mStartKeepaliveError),
+ mWrapper.mKeepaliveResponseDelay);
}
@Override
public void stopSocketKeepalive(Message msg) {
- onSocketKeepaliveEvent(msg.arg1, mWrapper.mStopKeepaliveError);
+ final int slot = msg.arg1;
+ mWrapper.mHandlerThread.getThreadHandler().postDelayed(
+ () -> onSocketKeepaliveEvent(slot, mWrapper.mStopKeepaliveError),
+ mWrapper.mKeepaliveResponseDelay);
}
@Override
@@ -248,6 +256,10 @@
mStopKeepaliveError = reason;
}
+ public void setKeepaliveResponseDelay(long delay) {
+ mKeepaliveResponseDelay = delay;
+ }
+
public void setExpectedKeepaliveSlot(Integer slot) {
mExpectedKeepaliveSlot = slot;
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 57c356d..862e552 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -4292,6 +4292,32 @@
myNet = connectKeepaliveNetwork(lp);
mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
+ // Check that a stop followed by network disconnects does not result in crash.
+ try (SocketKeepalive ka = mCm.createSocketKeepalive(
+ myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
+ ka.start(validKaInterval);
+ callback.expectStarted();
+ // Delay the response of keepalive events in networkAgent long enough to make sure
+ // the follow-up network disconnection will be processed first.
+ mWiFiNetworkAgent.setKeepaliveResponseDelay(3 * TIMEOUT_MS);
+ ka.stop();
+
+ // Make sure the stop has been processed. Wait for executor idle is needed to prevent
+ // flaky since the actual stop call to the service is delegated to executor thread.
+ waitForIdleSerialExecutor(executor, TIMEOUT_MS);
+ waitForIdle();
+
+ mWiFiNetworkAgent.disconnect();
+ mWiFiNetworkAgent.expectDisconnected();
+ callback.expectStopped();
+ callback.assertNoCallback();
+ }
+
+ // Reconnect.
+ waitForIdle();
+ myNet = connectKeepaliveNetwork(lp);
+ mWiFiNetworkAgent.setStartKeepaliveEvent(SocketKeepalive.SUCCESS);
+
// Check that keepalive slots start from 1 and increment. The first one gets slot 1.
mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
int srcPort2 = 0;
diff --git a/tools/aapt2/DominatorTree_test.cpp b/tools/aapt2/DominatorTree_test.cpp
index fe4f951..3e49034 100644
--- a/tools/aapt2/DominatorTree_test.cpp
+++ b/tools/aapt2/DominatorTree_test.cpp
@@ -173,4 +173,30 @@
EXPECT_EQ(expected, printer.ToString(&tree));
}
+TEST(DominatorTreeTest, NonZeroDensitiesMatch) {
+ const ConfigDescription sw600_config = test::ParseConfigOrDie("sw600dp");
+ const ConfigDescription sw600_hdpi_config = test::ParseConfigOrDie("sw600dp-hdpi");
+ const ConfigDescription sw800_hdpi_config = test::ParseConfigOrDie("sw800dp-hdpi");
+ const ConfigDescription sw800_xxhdpi_config = test::ParseConfigOrDie("sw800dp-xxhdpi");
+
+ std::vector<std::unique_ptr<ResourceConfigValue>> configs;
+ configs.push_back(util::make_unique<ResourceConfigValue>(ConfigDescription::DefaultConfig(), ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(sw600_config, ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(sw600_hdpi_config, ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(sw800_hdpi_config, ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(sw800_xxhdpi_config, ""));
+
+ DominatorTree tree(configs);
+ PrettyPrinter printer;
+
+ std::string expected =
+ "<default>\n"
+ " sw600dp-v13\n"
+ " sw600dp-hdpi-v13\n"
+ " sw800dp-hdpi-v13\n"
+ " sw800dp-xxhdpi-v13\n";
+ EXPECT_EQ(expected, printer.ToString(&tree));
+}
+
+
} // namespace aapt
diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp
index ae01170..b78f48c 100644
--- a/tools/aapt2/Resource.cpp
+++ b/tools/aapt2/Resource.cpp
@@ -96,8 +96,6 @@
return "styleable";
case ResourceType::kTransition:
return "transition";
- case ResourceType::kUnknown:
- return "unknown";
case ResourceType::kXml:
return "xml";
}
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index c49c370..4e051a3 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -66,11 +66,6 @@
kStyle,
kStyleable,
kTransition,
-
- // Not a parsed type. It is only used when loading resource tables that may have modified type
- // names
- kUnknown,
-
kXml,
};
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 72cb41a..fd12d02 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -2335,11 +2335,15 @@
}
// Populate some default no-compress extensions that are already compressed.
- options_.extensions_to_not_compress.insert(
- {".jpg", ".jpeg", ".png", ".gif", ".wav", ".mp2", ".mp3", ".ogg",
- ".aac", ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet", ".rtttl",
- ".imy", ".xmf", ".mp4", ".m4a", ".m4v", ".3gp", ".3gpp", ".3g2",
- ".3gpp2", ".amr", ".awb", ".wma", ".wmv", ".webm", ".mkv"});
+ options_.extensions_to_not_compress.insert({
+ // Image extensions
+ ".jpg", ".jpeg", ".png", ".gif", ".webp",
+ // Audio extensions
+ ".wav", ".mp2", ".mp3", ".ogg", ".aac", ".mid", ".midi", ".smf", ".jet", ".rtttl", ".imy",
+ ".xmf", ".amr", ".awb",
+ // Audio/video extensions
+ ".mpg", ".mpeg", ".mp4", ".m4a", ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2", ".wma", ".wmv",
+ ".webm", ".mkv"});
// Turn off auto versioning for static-libs.
if (context.GetPackageType() == PackageType::kStaticLib) {
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index f362744..cccd9fa 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -352,15 +352,15 @@
config.copyFromDtoH(type->config);
const std::string type_str = util::GetString(type_pool_, type->id - 1);
-
- // Be lenient on the name of the type if the table is lenient on resource validation.
- auto parsed_type = ResourceType::kUnknown;
- if (const ResourceType* parsed = ParseResourceType(type_str)) {
- parsed_type = *parsed;
- } else if (table_->GetValidateResources()) {
- diag_->Error(DiagMessage(source_) << "invalid type name '" << type_str << "' for type with ID "
- << (int) type->id);
- return false;
+ const ResourceType* parsed_type = ParseResourceType(type_str);
+ if (!parsed_type) {
+ // Be lenient on the name of the type if the table is lenient on resource validation.
+ bool log_error = table_->GetValidateResources();
+ if (log_error) {
+ diag_->Error(DiagMessage(source_) << "invalid type name '" << type_str
+ << "' for type with ID " << type->id);
+ }
+ return !log_error;
}
TypeVariant tv(type);
@@ -370,9 +370,8 @@
continue;
}
- const ResourceName name(package->name, parsed_type,
+ const ResourceName name(package->name, *parsed_type,
util::GetString(key_pool_, util::DeviceToHost32(entry->key.index)));
-
const ResourceId res_id(package->id.value(), type->id, static_cast<uint16_t>(it.index()));
std::unique_ptr<Value> resource_value;
diff --git a/wifi/OWNERS b/wifi/OWNERS
index 0601047..c1c70e2 100644
--- a/wifi/OWNERS
+++ b/wifi/OWNERS
@@ -1,6 +1,6 @@
set noparent
+dysu@google.com
etancohen@google.com
-mplass@google.com
rpius@google.com
satk@google.com